Takeshi Komiya avatar Takeshi Komiya committed a110a4a

* node.style supports dash_array format

Comments (0)

Files changed (7)

src/blockdiag/elements.py

         self.drawable = True
 
     def set_style(self, value):
-        if value in ('solid', 'dotted', 'dashed'):
-            self.style = value
+        if re.search('^(?:solid|dotted|dashed|\d+(,\d+)*)$', value, re.I):
+            self.style = value.lower()
         else:
             msg = "WARNING: unknown node style: %s\n" % value
             raise AttributeError(msg)
         self.color = images.color_to_rgb(color)
 
     def set_style(self, value):
-        value = value.lower()
-        if value in ('none', 'solid', 'dotted', 'dashed'):
-            self.style = value
+        if re.search('^(?:none|solid|dotted|dashed|\d+(,\d+)*)$', value, re.I):
+            self.style = value.lower()
         else:
             msg = "WARNING: unknown edge style: %s\n" % value
             raise AttributeError(msg)

src/blockdiag/imagedraw/pdf.py

 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
+import re
 import sys
 from reportlab.pdfgen import canvas
 from reportlab.pdfbase import pdfmetrics
             self.canvas.setDash([2, 2])
         elif style == 'dashed':
             self.canvas.setDash([4, 4])
+        elif re.search('^\d+(,\d+)*$', style or ""):
+            self.canvas.setDash([int(n) for n in style.split(',')])
         else:
             self.canvas.setDash()
 

src/blockdiag/imagedraw/png.py

 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
+import re
 import math
 from itertools import islice, izip, tee
-from blockdiag.utils.myitertools import istep
+from blockdiag.utils.myitertools import istep, stepslice
 from blockdiag.utils.PILTextFolder import PILTextFolder as TextFolder
 try:
     from PIL import Image
         if pt1[1] > pt2[1]:
             pt2, pt1 = line
 
-        r = range(pt1[1], pt2[1], length)
-        for y1, y2 in istep(r):
+        r = stepslice(xrange(pt1[1], pt2[1]), length)
+        for y1, y2 in istep(n for n in r):
             yield [(pt1[0], y1), (pt1[0], y2)]
 
     elif pt1[1] == pt2[1]:  # vertical
         if pt1[0] > pt2[0]:
             pt2, pt1 = line
 
-        r = range(pt1[0], pt2[0], length)
-        for x1, x2 in istep(r):
+        r = stepslice(xrange(pt1[0], pt2[0]), length)
+        for x1, x2 in istep(n for n in r):
             yield [(x1, pt1[1]), (x2, pt1[1])]
     else:  # diagonal
         if pt1[0] > pt2[0]:
             x += 1
             y += m
 
-        for p1, p2 in istep(islice(locus, None, None, length)):
+        for p1, p2 in istep(stepslice(locus, length)):
             yield (p1, p2)
 
 
+def style2cycle(style):
+    if style == 'dotted':
+        length = [2, 2]
+    elif style == 'dashed':
+        length = [4, 4]
+    elif re.search('^\d+(,\d+)*$', style or ""):
+        length = [int(n) for n in style.split(',')]
+    else:
+        length = None
+
+    return length
+
+
 class ImageDrawEx(object):
     def __init__(self, filename, size, **kwargs):
         if kwargs.get('im'):
             del kwargs['style']
 
         if style:
-            if style == 'dotted':
-                length = 2
-            elif style == 'dashed':
-                length = 4
 
             while start > end:
                 end += 360
 
-            for pt in ellipse.dots(box, length, start, end):
+            cycle = style2cycle(style)
+            for pt in ellipse.dots(box, cycle, start, end):
                 self.draw.line([pt, pt], fill=kwargs['fill'])
         else:
             self.draw.arc(box, start, end, **kwargs)
                 kwargs['fill'] = kwargs['outline']
                 del kwargs['outline']
 
-            if style == 'dotted':
-                length = 2
-            elif style == 'dashed':
-                length = 4
-
-            for pt in ellipse.dots(box, length):
+            cycle = style2cycle(style)
+            for pt in ellipse.dots(box, cycle):
                 self.draw.line([pt, pt], fill=kwargs['fill'])
         else:
             if kwargs.get('fill') == 'none':
         style = kwargs.get('style')
         if kwargs.get('fill') == 'none':
             pass
-        elif style in ('dotted', 'dashed'):
+        elif style in ('dotted', 'dashed') or \
+             re.search('^\d+(,\d+)*$', style or ""):
             self.dashed_line(xy, **kwargs)
         else:
             if 'style' in kwargs:
         style = kwargs.get('style')
         del kwargs['style']
 
-        if style == 'dotted':
-            length = 2
-        elif style == 'dashed':
-            length = 4
-
+        cycle = style2cycle(style)
         for line in line_segments(xy):
-            for subline in dashize_line(line, length):
+            for subline in dashize_line(line, cycle):
                 self.line(subline, **kwargs)
 
     def rectangle(self, box, **kwargs):

src/blockdiag/imagedraw/svg.py

             length = 2
         elif name == 'dashed':
             length = 4
+        elif re.search('^\d+(,\d+)*$', name or ""):
+            length = re.sub(',', ' ', name)
         else:
             length = None
 

src/blockdiag/tests/diagrams/node_style_dasharray.diag

+{
+  A [style = "2,2,4,2"];
+  B [shape = diamond, style = "2,2,4,2"];
+  C [shape = ellipse, style = "2,2,4,2"];
+  D [shape = flowchart.database, style = "2,2,4,2"];
+}
+

src/blockdiag/utils/ellipse.py

     height = box[3] - box[1]
     center = XY(box[0] + width / 2, box[1] + height / 2)
 
+    # calcrate rendering pattern from cycle
+    base = 0
+    rendered = []
+    for index in range(0, len(cycle), 2):
+        i, j = cycle[index:index + 2]
+        for n in range(base * 2, (base + i) * 2):
+            rendered.append(n)
+        base += i + j
+
     a = float(width) / 2
     b = float(height) / 2
     du = 1
-
+    _max = sum(cycle) * 2
     for i, coord in enumerate(coordinate(du, a, b, start, end)):
-        i %= cycle * 2
-        if i < cycle:
+        if i % _max in rendered:
             dot = XY(center.x + coord[0], center.y + coord[1])
             yield dot

src/blockdiag/utils/myitertools.py

 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
+from itertools import cycle
+
 
 def istep(seq, step=2):
     iterable = iter(seq)
     while True:
         yield [iterable.next() for i in range(step)]
+
+
+def stepslice(iterable, steps):
+    iterable = iter(iterable)
+    step = cycle(steps)
+    yield iterable.next()
+
+    while True:
+        # skip (1)
+        for i in xrange(step.next() - 1):
+            iterable.next()
+        yield iterable.next()
+
+        # skip (2)
+        for i in xrange(step.next() - 1):
+            iterable.next()
+        yield iterable.next()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.