clone

a browser-first diagram editor with live svg previews, local drafts and encrypted, accountless sharing

main
diagramzip / renderers / python / blockdiag-family / src / seqdiag / drawer.py
drawer.py 6.5K
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.1516import blockdiag.drawer17from blockdiag.utils import XY1819from seqdiag.metrics import DiagramMetrics202122class DiagramDraw(blockdiag.drawer.DiagramDraw):23 def create_metrics(self, *args, **kwargs):24 return DiagramMetrics(*args, **kwargs)2526 def _draw_background(self):27 for node in self.nodes:28 node.activities.sort(key=lambda x: x['level'])2930 if self.diagram.shadow_style != 'none':31 for node in self.nodes:32 for activity in node.activities:33 self.node_activity_shadow(node, activity)3435 if self.diagram.shadow_style != 'none':36 for edge in self.edges:37 self.edge_shadow(edge)3839 super(DiagramDraw, self)._draw_background()4041 def _draw_elements(self, **kwargs):42 for block in self.diagram.altblocks:43 self.altblock(block)4445 for node in self.nodes:46 self.lifelines(node)4748 super(DiagramDraw, self)._draw_elements(**kwargs)4950 for sep in self.diagram.separators:51 self.separator(sep)5253 for group in self.diagram.groups:54 self.group_label(group, **kwargs)5556 def node_activity_shadow(self, node, activity):57 box = self.metrics.activity_shadow(node, activity)58 if self.diagram.shadow_style == 'solid':59 self.drawer.rectangle(box, fill=self.shadow)60 else:61 self.drawer.rectangle(box, fill=self.shadow, filter='transp-blur')6263 def node_activity(self, node, activity):64 box = self.metrics.activity_box(node, activity)65 self.drawer.rectangle(box, width=1, outline=self.diagram.linecolor,66 fill='moccasin')6768 def lifelines(self, node):69 for line, style in self.metrics.lifeline(node):70 self.drawer.line(line, fill=self.diagram.linecolor, style=style)7172 for activity in node.activities:73 self.node_activity(node, activity)7475 def edge_shadow(self, edge):76 m = self.metrics77 dx, dy = m.shadow_offset7879 if edge.leftnote:80 polygon = m.edge(edge).leftnoteshape81 shadow = [XY(pt.x + dx, pt.y + dy) for pt in polygon]82 if self.diagram.shadow_style == 'solid':83 self.drawer.polygon(shadow, fill=self.shadow,84 outline=self.shadow)85 else:86 self.drawer.polygon(shadow, fill=self.shadow,87 outline=self.shadow, filter='transp-blur')8889 if edge.rightnote:90 polygon = m.edge(edge).rightnoteshape91 shadow = [XY(pt.x + dx, pt.y + dy) for pt in polygon]92 if self.diagram.shadow_style == 'solid':93 self.drawer.polygon(shadow, fill=self.shadow,94 outline=self.shadow)95 else:96 self.drawer.polygon(shadow, fill=self.shadow,97 outline=self.shadow, filter='transp-blur')9899 def edge(self, edge):100 # render shaft of edges101 m = self.metrics.edge(edge)102 shaft = m.shaft103 self.drawer.line(shaft, fill=edge.color, style=edge.style)104105 # render head of edges106 head = m.head107 if edge.asynchronous:108 self.drawer.line((head[0], head[1]), fill=edge.color)109 self.drawer.line((head[1], head[2]), fill=edge.color)110 else:111 self.drawer.polygon(head, outline=edge.color, fill=edge.color)112113 if edge.failed:114 for line in m.failedmark:115 self.drawer.line(line, fill=edge.color)116117 if edge.leftnote:118 polygon = m.leftnoteshape119 self.drawer.polygon(polygon, fill=edge.notecolor,120 outline=self.fill)121122 folded = [polygon[1], XY(polygon[1].x, polygon[2].y), polygon[2]]123 self.drawer.line(folded, fill=self.fill)124125 self.drawer.textarea(m.leftnotebox, edge.leftnote,126 self.metrics.font_for(edge),127 fill=edge.color, halign='left')128129 if edge.rightnote:130 polygon = m.rightnoteshape131 self.drawer.polygon(polygon, fill=edge.notecolor,132 outline=self.fill)133134 folded = [polygon[1], XY(polygon[1].x, polygon[2].y), polygon[2]]135 self.drawer.line(folded, fill=self.fill)136137 self.drawer.textarea(m.rightnotebox, edge.rightnote,138 self.metrics.font_for(edge),139 fill=edge.color, halign='left')140141 def edge_label(self, edge):142 m = self.metrics.edge(edge)143144 if edge.label:145 if edge.direction in ('right', 'self'):146 halign = 'left'147 else:148 halign = 'right'149150 self.drawer.textarea(m.textbox, edge.label,151 self.metrics.font_for(edge),152 fill=edge.color, halign=halign)153154 def separator(self, sep):155 m = self.metrics.separator(sep)156 for line in m.lines:157 self.drawer.line(line, fill=self.fill, style=sep.style)158159 if sep.type == 'delay':160 self.drawer.rectangle(m.labelbox, fill='white', outline='white')161 elif sep.type == 'divider':162 self.drawer.rectangle(m.labelbox, fill=sep.color,163 outline=sep.linecolor)164165 self.drawer.textarea(m.labelbox, sep.label,166 self.metrics.font_for(sep), fill=sep.textcolor)167168 def altblock(self, block):169 m = self.metrics.cell(block)170 self.drawer.rectangle(m, outline=block.linecolor)171172 box = m.textbox173 line = [XY(box.x1, box.y2),174 XY(box.x2, box.y2),175 XY(box.x2 + self.metrics.cellsize * 2, box.y1)]176 self.drawer.line(line, fill=block.linecolor)177 self.drawer.textarea(box, block.type, fill=block.textcolor,178 font=self.metrics.font_for(block))