def add_table(fig, x, y, name, fields): '''draw tabletop''' # (NB: y grows downward) txt = TextElement(x, y, name, True) tt = TabletopElement(x, y) image_map[name] = {'coord': (x, y), 'def': '', 'descr': ''} fig.append(sg.GroupElement([tt, txt])) for f in fields: y += RECT_HEIGHT fig.append(add_field(x, y, f, name))
def add_field(x, y, f, table_name): '''draw a rectangle with field name, return group''' name = f[0] x_shift = 63.150 if table_name == 'message_in' and name == 'id' else 0 txt = TextElement(x + x_shift, y, name) green_key = (table_name.startswith('message_') and name in {'ino', 'mtime', 'pid'} or table_name == name and name == 'domain') rect = RectElement(x, y, green_key) image_map[table_name + '-' + name] = { 'coord': (x, y), 'def': f[1], 'descr': '' } return sg.GroupElement([rect, txt])
def saveSVG(self, drawing, filename=None, path=None): # compute canvas size [xMin, yMin, width, height], strokeWidth = drawing.getViewBox() # create SVG svg = sg.SVGFigure(str(width) + "mm", str(height) + "mm") svg.root.set("viewBox", "%s %s %s %s" % (xMin, yMin, width, height)) svgLines = [] for line in drawing.polylines: # custom path creation points = " ".join( map(lambda x: "{:.3f},{:.3f}".format(x[0], -x[1]), line.getPoints())) linedata = etree.Element( sg.SVG + "polyline", { "points": points, "stroke-width": str(strokeWidth), "stroke-linecap": "square", "stroke": line.color, "fill": "none" }) svgLines.append(sg.FigureElement(linedata)) g = sg.GroupElement(svgLines, {'id': "root"}) svg.append(g) # save generated SVG files if not (path): path = self.rootPath if not (filename): filename = drawing.filename filename = re.sub( r"[^(a-zA-Z0-9\-_)]+", "_", filename ) # make sure that only safe characters are used for filename mkpath(path) filepath = os.path.join(path, filename) + ".svg" drawing.filename = filename drawing.path = path drawing.url = self.pathToURL(filepath) logging.info("drawing.path: " + drawing.path) logging.info("drawing.url: " + drawing.url) svg.save(filepath)
def __init__(self, dx, dy, size=8): self.size = size lines = self._gen_grid(dx, dy) element = _transform.GroupElement(lines) Element.__init__(self, element.root)
def __init__(self, *svgelements): element = _transform.GroupElement(svgelements) Element.__init__(self, element.root)
def compose_view(bg_svgs, fg_svgs, ref=0, out_file='report.svg'): """ Composes the input svgs into one standalone svg and inserts the CSS code for the flickering animation """ import svgutils.transform as svgt if fg_svgs is None: fg_svgs = [] # Merge SVGs and get roots svgs = bg_svgs + fg_svgs roots = [f.getroot() for f in svgs] # Query the size of each sizes = [] for f in svgs: viewbox = [float(v) for v in f.root.get("viewBox").split(" ")] width = int(viewbox[2]) height = int(viewbox[3]) sizes.append((width, height)) nsvgs = len(bg_svgs) sizes = np.array(sizes) # Calculate the scale to fit all widths width = sizes[ref, 0] scales = width / sizes[:, 0] heights = sizes[:, 1] * scales # Compose the views panel: total size is the width of # any element (used the first here) and the sum of heights fig = svgt.SVGFigure(width, heights[:nsvgs].sum()) yoffset = 0 for i, r in enumerate(roots): r.moveto(0, yoffset, scale=scales[i]) if i == (nsvgs - 1): yoffset = 0 else: yoffset += heights[i] # Group background and foreground panels in two groups if fg_svgs: newroots = [ svgt.GroupElement(roots[:nsvgs], {'class': 'background-svg'}), svgt.GroupElement(roots[nsvgs:], {'class': 'foreground-svg'}) ] else: newroots = roots fig.append(newroots) fig.root.attrib.pop("width") fig.root.attrib.pop("height") fig.root.set("preserveAspectRatio", "xMidYMid meet") out_file = op.abspath(out_file) fig.save(out_file) # Post processing with open(out_file, 'r' if PY3 else 'rb') as f: svg = f.read().split('\n') # Remove <?xml... line if svg[0].startswith("<?xml"): svg = svg[1:] # Add styles for the flicker animation if fg_svgs: svg.insert( 2, """\ <style type="text/css"> @keyframes flickerAnimation%s { 0%% {opacity: 1;} 100%% { opacity: 0; }} .foreground-svg { animation: 1s ease-in-out 0s alternate none infinite paused flickerAnimation%s;} .foreground-svg:hover { animation-play-state: running;} </style>""" % tuple([uuid4()] * 2)) with open(out_file, 'w' if PY3 else 'wb') as f: f.write('\n'.join(svg)) return out_file