Programmatically generate SVG (vector) images, animations, and interactive Jupyter widgets

Add SVG Use element, allow adding SVG Defs directly to a Drawing

Changed files
+34 -3
+17 -1
drawing.py
···
self.viewBox = (-self.viewBox[0], self.viewBox[1]-self.viewBox[3],
self.viewBox[2], self.viewBox[3])
self.elements = []
+
self.otherDefs = []
self.pixelScale = 1
self.renderWidth = None
self.renderHeight = None
···
self.elements.count(element)
def reverse(self):
self.elements.reverse()
+
def drawDef(self, obj, **kwargs):
+
if not hasattr(obj, 'writeSvgElement'):
+
elements = obj.toDrawables(elements=elementsModule, **kwargs)
+
else:
+
assert len(kwargs) == 0
+
elements = (obj,)
+
self.otherDefs.extend(elements)
+
def appendDef(self, element):
+
self.otherDefs.append(element)
def asSvg(self, outputFile=None):
returnString = outputFile is None
if returnString:
···
idStr = base + str(idIndex)
idIndex += 1
return idStr
-
prevSet = set()
+
prevSet = set((id(defn) for defn in self.otherDefs))
def isDuplicate(obj):
nonlocal prevSet
dup = id(obj) in prevSet
prevSet.add(id(obj))
return dup
+
for element in self.otherDefs:
+
try:
+
element.writeSvgElement(outputFile)
+
outputFile.write('\n')
+
except AttributeError:
+
pass
for element in self.elements:
try:
element.writeSvgDefs(idGen, isDuplicate, outputFile)
+17 -2
elements.py
···
return [v for v in self.args.values() if isinstance(v, defs.DrawingDef)]
def __eq__(self, other):
if isinstance(other, type(self)):
-
return (self.tagName == other.tagName and
+
return (self.TAG_NAME == other.TAG_NAME and
self.args == other.args)
return False
···
super().writeSvgDefs(idGen, isDuplicate, outputFile)
for child in self.children:
child.writeSvgDefs(idGen, isDuplicate, outputFile)
-
outputFile.write('\n')
class NoElement(DrawingElement):
''' A drawing element that has no effect '''
···
Any transform will apply to its children and other attributes will be
inherited by its children. '''
TAG_NAME = 'g'
+
+
class Use(DrawingBasicElement):
+
''' A copy of another element
+
+
Specify the other element by its id: href='#otherElemId'. '''
+
TAG_NAME = 'use'
+
def __init__(self, otherElem, x, y, **kwargs):
+
y = -y
+
if isinstance(otherElem, str):
+
otherElemId = otherElem
+
else:
+
if otherElem.id is None:
+
raise ValueError('otherElem must have an id')
+
otherElemId = otherElem.id
+
href = '#{}'.format(otherElemId)
+
super().__init__(xlink__href=href, x=x, y=y, **kwargs)
class Image(DrawingBasicElement):
''' A linked or embedded raster image '''