1# -*- coding: utf-8 -*-2# Copyright 2011 Takeshi KOMIYA3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.1516from __future__ import division1718from blockdiag.imagedraw.simplesvg import pathdata19from blockdiag.noderenderer import install_renderer20from blockdiag.noderenderer.base import NodeShape21from blockdiag.utils import Box222324class Cloud(NodeShape):25 def __init__(self, node, metrics=None):26 super(Cloud, self).__init__(node, metrics)2728 pt = metrics.cell(node).topleft29 rx = (self.node.width or self.metrics.node_width) // 1230 ry = (self.node.height or self.metrics.node_height) // 531 self.textbox = Box(pt.x + rx * 2, pt.y + ry,32 pt.x + rx * 11, pt.y + ry * 4)3334 def render_shape(self, drawer, _, **kwargs):35 # draw background36 self.render_shape_background(drawer, **kwargs)3738 if not kwargs.get('shadow') and self.node.background:39 drawer.image(self.textbox, self.node.background)4041 def render_shape_background(self, drawer, **kwargs):42 fill = kwargs.get('fill')4344 m = self.metrics.cell(self.node)45 pt = m.topleft46 rx = (self.node.width or self.metrics.node_width) // 1247 ry = (self.node.height or self.metrics.node_height) // 54849 ellipses = [Box(pt.x + rx * 2, pt.y + ry,50 pt.x + rx * 5, pt.y + ry * 3),51 Box(pt.x + rx * 4, pt.y,52 pt.x + rx * 9, pt.y + ry * 2),53 Box(pt.x + rx * 8, pt.y + ry,54 pt.x + rx * 11, pt.y + ry * 3),55 Box(pt.x + rx * 9, pt.y + ry * 2,56 pt.x + rx * 13, pt.y + ry * 4),57 Box(pt.x + rx * 8, pt.y + ry * 2,58 pt.x + rx * 11, pt.y + ry * 5),59 Box(pt.x + rx * 5, pt.y + ry * 2,60 pt.x + rx * 8, pt.y + ry * 5),61 Box(pt.x + rx * 2, pt.y + ry * 2,62 pt.x + rx * 5, pt.y + ry * 5),63 Box(pt.x + rx * 0, pt.y + ry * 2,64 pt.x + rx * 4, pt.y + ry * 4)]6566 for e in ellipses:67 if kwargs.get('shadow'):68 e = self.shift_shadow(e)69 if kwargs.get('style') == 'blur':70 drawer.ellipse(e, fill=fill, outline=fill,71 filter='transp-blur')72 else:73 drawer.ellipse(e, fill=fill, outline=fill)74 else:75 drawer.ellipse(e, fill=self.node.color,76 outline=self.node.linecolor,77 style=self.node.style)7879 rects = [Box(pt.x + rx * 2, pt.y + ry * 2,80 pt.x + rx * 11, pt.y + ry * 4),81 Box(pt.x + rx * 4, pt.y + ry,82 pt.x + rx * 9, pt.y + ry * 2)]83 for rect in rects:84 if kwargs.get('shadow'):85 rect = self.shift_shadow(rect)86 if kwargs.get('style') == 'blur':87 drawer.rectangle(rect, fill=fill, outline=fill,88 filter='transp-blur')89 else:90 drawer.rectangle(rect, fill=fill, outline=fill)91 else:92 drawer.rectangle(rect, fill=self.node.color,93 outline=self.node.color)9495 def render_vector_shape(self, drawer, _, **kwargs):96 fill = kwargs.get('fill')9798 # create pathdata99 m = self.metrics.cell(self.node)100 rx = (self.node.width or self.metrics.node_width) // 12101 ry = (self.node.height or self.metrics.node_height) // 5102103 pt = m.topleft104 if kwargs.get('shadow'):105 pt = self.shift_shadow(pt)106107 path = pathdata(pt.x + rx * 2, pt.y + ry * 2)108 path.ellarc(rx * 2, ry, 0, 0, 1, pt.x + rx * 4, pt.y + ry)109 path.ellarc(rx * 2, ry * 3 // 4, 0, 0, 1, pt.x + rx * 9, pt.y + ry)110 path.ellarc(rx * 2, ry, 0, 0, 1, pt.x + rx * 11, pt.y + ry * 2)111 path.ellarc(rx * 2, ry, 0, 0, 1, pt.x + rx * 11, pt.y + ry * 4)112 path.ellarc(rx * 2, ry * 5 // 2, 0, 0, 1, pt.x + rx * 8, pt.y + ry * 4)113 path.ellarc(rx * 2, ry * 5 // 2, 0, 0, 1, pt.x + rx * 5, pt.y + ry * 4)114 path.ellarc(rx * 2, ry * 5 // 2, 0, 0, 1, pt.x + rx * 2, pt.y + ry * 4)115 path.ellarc(rx * 2, ry, 0, 0, 1, pt.x + rx * 2, pt.y + ry * 2)116117 # draw outline118 if kwargs.get('shadow'):119 if kwargs.get('style') == 'blur':120 drawer.path(path, fill=fill, outline=fill,121 filter='transp-blur')122 else:123 drawer.path(path, fill=fill, outline=fill)124 elif self.node.background:125 drawer.path(path, fill=self.node.color, outline=self.node.color)126 drawer.image(self.textbox, self.node.background)127 drawer.path(path, fill="none", outline=self.node.linecolor,128 style=self.node.style)129 else:130 drawer.path(path, fill=self.node.color,131 outline=self.node.linecolor, style=self.node.style)132133134def setup(self):135 install_renderer('cloud', Cloud)