@@ -77,7 +77,7 @@ def __init__(
77
77
fill_opacity = 1.0 ,
78
78
** kwargs ,
79
79
):
80
- self .def_id_to_mobject = {}
80
+ self .def_map = {}
81
81
self .file_name = file_name or self .file_name
82
82
self .ensure_valid_file ()
83
83
self .should_center = should_center
@@ -125,17 +125,7 @@ def generate_points(self):
125
125
"""
126
126
doc = minidom_parse (self .file_path )
127
127
for svg in doc .getElementsByTagName ("svg" ):
128
- mobjects = self .get_mobjects_from (
129
- svg ,
130
- # these are the default styling specifications for SVG images,
131
- # according to https://www.w3.org/TR/SVG/painting.html, ctrl-F for "initial"
132
- {
133
- "fill" : "black" ,
134
- "fill-opacity" : "1" ,
135
- "stroke" : "none" ,
136
- "stroke-opacity" : "1" ,
137
- },
138
- )
128
+ mobjects = self .get_mobjects_from (svg , {})
139
129
if self .unpack_groups :
140
130
self .add (* mobjects )
141
131
else :
@@ -182,7 +172,9 @@ def get_mobjects_from(
182
172
elif element .tagName in ["g" , "svg" , "symbol" , "defs" ]:
183
173
result += it .chain (
184
174
* [
185
- self .get_mobjects_from (child , style , within_defs or is_defs )
175
+ self .get_mobjects_from (
176
+ child , style , within_defs = within_defs or is_defs
177
+ )
186
178
for child in element .childNodes
187
179
]
188
180
)
@@ -191,8 +183,8 @@ def get_mobjects_from(
191
183
if temp != "" :
192
184
result .append (self .path_string_to_mobject (temp , style ))
193
185
elif element .tagName == "use" :
194
- # note, style is not passed down to " use" elements
195
- result += self .use_to_mobjects (element )
186
+ # note, style is calcuated in a different way for ` use` elements.
187
+ result += self .use_to_mobjects (element , style )
196
188
elif element .tagName == "rect" :
197
189
result .append (self .rect_to_mobject (element , style ))
198
190
elif element .tagName == "circle" :
@@ -210,7 +202,9 @@ def get_mobjects_from(
210
202
result = [VGroup (* result )]
211
203
212
204
if within_defs and element .hasAttribute ("id" ):
213
- self .def_id_to_mobject [element .getAttribute ("id" )] = result
205
+ # it seems wasteful to throw away the actual element,
206
+ # but I'd like the parsing to be as similar as possible
207
+ self .def_map [element .getAttribute ("id" )] = (style , element )
214
208
if is_defs :
215
209
# defs shouldn't be part of the result tree, only the id dictionary.
216
210
return []
@@ -235,7 +229,9 @@ def path_string_to_mobject(self, path_string: str, style: dict):
235
229
"""
236
230
return SVGPathMobject (path_string , ** parse_style (style ))
237
231
238
- def use_to_mobjects (self , use_element : MinidomElement ) -> List [VMobject ]:
232
+ def use_to_mobjects (
233
+ self , use_element : MinidomElement , local_style : Dict
234
+ ) -> List [VMobject ]:
239
235
"""Converts a SVG <use> element to a collection of VMobjects.
240
236
241
237
Parameters
@@ -244,22 +240,34 @@ def use_to_mobjects(self, use_element: MinidomElement) -> List[VMobject]:
244
240
An SVG <use> element which represents nodes that should be
245
241
duplicated elsewhere.
246
242
243
+ local_style : :class:`Dict`
244
+ The styling using SVG property names at the point the element is `<use>`d.
245
+ Not all values are applied; styles defined when the element is specified in
246
+ the `<def>` tag cannot be overriden here.
247
+
247
248
Returns
248
249
-------
249
250
List[VMobject]
250
- A collection of VMobjects that are copies of the defined objects
251
+ A collection of VMobjects that are a copy of the defined object
251
252
"""
252
253
253
254
# Remove initial "#" character
254
255
ref = use_element .getAttribute ("xlink:href" )[1 :]
255
256
256
257
try :
257
- return [ i . copy () for i in self .def_id_to_mobject [ref ] ]
258
+ def_style , def_element = self .def_map [ref ]
258
259
except KeyError :
259
260
warning_text = f"{ self .file_name } contains a reference to id #{ ref } , which is not recognized"
260
261
warnings .warn (warning_text )
261
262
return []
262
263
264
+ # In short, the def-ed style overrides the new style,
265
+ # in cases when the def-ed styled is defined.
266
+ style = local_style .copy ()
267
+ style .update (def_style )
268
+
269
+ return self .get_mobjects_from (def_element , style )
270
+
263
271
def attribute_to_float (self , attr ):
264
272
"""A helper method which converts the attribute to float.
265
273
@@ -385,20 +393,21 @@ def rect_to_mobject(self, rect_element: MinidomElement, style: dict):
385
393
386
394
corner_radius = float (corner_radius )
387
395
396
+ parsed_style = parse_style (style )
397
+ parsed_style ["stroke_width" ] = stroke_width
398
+
388
399
if corner_radius == 0 :
389
400
mob = Rectangle (
390
401
width = self .attribute_to_float (rect_element .getAttribute ("width" )),
391
402
height = self .attribute_to_float (rect_element .getAttribute ("height" )),
392
- stroke_width = stroke_width ,
393
- ** parse_style (style ),
403
+ ** parsed_style ,
394
404
)
395
405
else :
396
406
mob = RoundedRectangle (
397
407
width = self .attribute_to_float (rect_element .getAttribute ("width" )),
398
408
height = self .attribute_to_float (rect_element .getAttribute ("height" )),
399
- stroke_width = stroke_width ,
400
409
corner_radius = corner_radius ,
401
- ** parse_style ( style ) ,
410
+ ** parsed_style ,
402
411
)
403
412
404
413
mob .shift (mob .get_center () - mob .get_corner (UP + LEFT ))
0 commit comments