|
17 | 17 |
|
18 | 18 | from ... import config
|
19 | 19 | from ...constants import *
|
20 |
| -from ...mobject.geometry import Circle, Rectangle, RoundedRectangle |
| 20 | +from ...mobject.geometry import Circle, Line, Rectangle, RoundedRectangle |
21 | 21 | from ...mobject.types.vectorized_mobject import VGroup, VMobject
|
22 | 22 | from .style_utils import cascade_element_style, parse_style
|
23 | 23 | from .svg_path import SVGPathMobject, string_to_numbers
|
@@ -183,6 +183,8 @@ def get_mobjects_from(
|
183 | 183 | elif element.tagName == "use":
|
184 | 184 | # note, style is calcuated in a different way for `use` elements.
|
185 | 185 | result += self.use_to_mobjects(element, style)
|
| 186 | + elif element.tagName in ["line"]: |
| 187 | + result.append(self.line_to_mobject(element, style)) |
186 | 188 | elif element.tagName == "rect":
|
187 | 189 | result.append(self.rect_to_mobject(element, style))
|
188 | 190 | elif element.tagName == "circle":
|
@@ -227,6 +229,24 @@ def path_string_to_mobject(self, path_string: str, style: dict):
|
227 | 229 | """
|
228 | 230 | return SVGPathMobject(path_string, **parse_style(style))
|
229 | 231 |
|
| 232 | + def attribute_to_float(self, attr): |
| 233 | + """A helper method which converts the attribute to float. |
| 234 | +
|
| 235 | + Parameters |
| 236 | + ---------- |
| 237 | + attr : str |
| 238 | + An SVG path attribute. |
| 239 | +
|
| 240 | + Returns |
| 241 | + ------- |
| 242 | + float |
| 243 | + A float representing the attribute string value. |
| 244 | + """ |
| 245 | + stripped_attr = "".join( |
| 246 | + [char for char in attr if char in string.digits + "." + "-"] |
| 247 | + ) |
| 248 | + return float(stripped_attr) |
| 249 | + |
230 | 250 | def use_to_mobjects(
|
231 | 251 | self, use_element: MinidomElement, local_style: Dict
|
232 | 252 | ) -> List[VMobject]:
|
@@ -266,48 +286,78 @@ def use_to_mobjects(
|
266 | 286 |
|
267 | 287 | return self.get_mobjects_from(def_element, style)
|
268 | 288 |
|
269 |
| - def attribute_to_float(self, attr): |
270 |
| - """A helper method which converts the attribute to float. |
| 289 | + def line_to_mobject(self, line_element: MinidomElement, style: dict): |
| 290 | + """Creates a Line VMobject from an SVG <line> element. |
271 | 291 |
|
272 | 292 | Parameters
|
273 | 293 | ----------
|
274 |
| - attr : str |
275 |
| - An SVG path attribute. |
| 294 | + line_element : :class:`minidom.Element` |
| 295 | + An SVG line element. |
| 296 | +
|
| 297 | + style : :class:`dict` |
| 298 | + Style specification, using the SVG names for properties. |
276 | 299 |
|
277 | 300 | Returns
|
278 | 301 | -------
|
279 |
| - float |
280 |
| - A float representing the attribute string value. |
| 302 | + Line |
| 303 | + A Line VMobject |
281 | 304 | """
|
282 |
| - stripped_attr = "".join( |
283 |
| - [char for char in attr if char in string.digits + "." + "-"] |
284 |
| - ) |
285 |
| - return float(stripped_attr) |
| 305 | + x1, y1, x2, y2 = [ |
| 306 | + self.attribute_to_float(line_element.getAttribute(key)) |
| 307 | + if line_element.hasAttribute(key) |
| 308 | + else 0.0 |
| 309 | + for key in ("x1", "y1", "x2", "y2") |
| 310 | + ] |
| 311 | + return Line([x1, -y1, 0], [x2, -y2, 0], **parse_style(style)) |
286 | 312 |
|
287 |
| - def polygon_to_mobject(self, polygon_element: MinidomElement, style: dict): |
288 |
| - """Constructs a VMobject from a SVG <polygon> element. |
| 313 | + def rect_to_mobject(self, rect_element: MinidomElement, style: dict): |
| 314 | + """Converts a SVG <rect> command to a VMobject. |
289 | 315 |
|
290 | 316 | Parameters
|
291 | 317 | ----------
|
292 |
| - polygon_element : :class:`minidom.Element` |
293 |
| - An SVG polygon element. |
| 318 | + rect_element : minidom.Element |
| 319 | + A SVG rect path command. |
294 | 320 |
|
295 |
| - style : :class:`dict` |
| 321 | + style : dict |
296 | 322 | Style specification, using the SVG names for properties.
|
297 | 323 |
|
298 | 324 | Returns
|
299 | 325 | -------
|
300 |
| - VMobjectFromSVGPathstring |
301 |
| - A VMobject representing the polygon. |
| 326 | + Rectangle |
| 327 | + Creates either a Rectangle, or RoundRectangle, VMobject from a |
| 328 | + rect element. |
302 | 329 | """
|
303 |
| - # This seems hacky... yes it is. |
304 |
| - path_string = polygon_element.getAttribute("points").lstrip() |
305 |
| - for digit in string.digits: |
306 |
| - path_string = path_string.replace(" " + digit, " L" + digit) |
307 |
| - path_string = "M" + path_string |
308 |
| - if polygon_element.tagName == "polygon": |
309 |
| - path_string = path_string + "Z" |
310 |
| - return self.path_string_to_mobject(path_string, style) |
| 330 | + |
| 331 | + stroke_width = rect_element.getAttribute("stroke-width") |
| 332 | + corner_radius = rect_element.getAttribute("rx") |
| 333 | + |
| 334 | + if stroke_width in ["", "none", "0"]: |
| 335 | + stroke_width = 0 |
| 336 | + |
| 337 | + if corner_radius in ["", "0", "none"]: |
| 338 | + corner_radius = 0 |
| 339 | + |
| 340 | + corner_radius = float(corner_radius) |
| 341 | + |
| 342 | + parsed_style = parse_style(style) |
| 343 | + parsed_style["stroke_width"] = stroke_width |
| 344 | + |
| 345 | + if corner_radius == 0: |
| 346 | + mob = Rectangle( |
| 347 | + width=self.attribute_to_float(rect_element.getAttribute("width")), |
| 348 | + height=self.attribute_to_float(rect_element.getAttribute("height")), |
| 349 | + **parsed_style, |
| 350 | + ) |
| 351 | + else: |
| 352 | + mob = RoundedRectangle( |
| 353 | + width=self.attribute_to_float(rect_element.getAttribute("width")), |
| 354 | + height=self.attribute_to_float(rect_element.getAttribute("height")), |
| 355 | + corner_radius=corner_radius, |
| 356 | + **parsed_style, |
| 357 | + ) |
| 358 | + |
| 359 | + mob.shift(mob.get_center() - mob.get_corner(UP + LEFT)) |
| 360 | + return mob |
311 | 361 |
|
312 | 362 | def circle_to_mobject(self, circle_element: MinidomElement, style: dict):
|
313 | 363 | """Creates a Circle VMobject from a SVG <circle> command.
|
@@ -362,54 +412,30 @@ def ellipse_to_mobject(self, circle_element: MinidomElement, style: dict):
|
362 | 412 | .shift(x * RIGHT + y * DOWN)
|
363 | 413 | )
|
364 | 414 |
|
365 |
| - def rect_to_mobject(self, rect_element: MinidomElement, style: dict): |
366 |
| - """Converts a SVG <rect> command to a VMobject. |
| 415 | + def polygon_to_mobject(self, polygon_element: MinidomElement, style: dict): |
| 416 | + """Constructs a VMobject from a SVG <polygon> element. |
367 | 417 |
|
368 | 418 | Parameters
|
369 | 419 | ----------
|
370 |
| - rect_element : minidom.Element |
371 |
| - A SVG rect path command. |
| 420 | + polygon_element : :class:`minidom.Element` |
| 421 | + An SVG polygon element. |
372 | 422 |
|
373 |
| - style : dict |
| 423 | + style : :class:`dict` |
374 | 424 | Style specification, using the SVG names for properties.
|
375 | 425 |
|
376 | 426 | Returns
|
377 | 427 | -------
|
378 |
| - Rectangle |
379 |
| - Creates either a Rectangle, or RoundRectangle, VMobject from a |
380 |
| - rect element. |
| 428 | + VMobjectFromSVGPathstring |
| 429 | + A VMobject representing the polygon. |
381 | 430 | """
|
382 |
| - |
383 |
| - stroke_width = rect_element.getAttribute("stroke-width") |
384 |
| - corner_radius = rect_element.getAttribute("rx") |
385 |
| - |
386 |
| - if stroke_width in ["", "none", "0"]: |
387 |
| - stroke_width = 0 |
388 |
| - |
389 |
| - if corner_radius in ["", "0", "none"]: |
390 |
| - corner_radius = 0 |
391 |
| - |
392 |
| - corner_radius = float(corner_radius) |
393 |
| - |
394 |
| - parsed_style = parse_style(style) |
395 |
| - parsed_style["stroke_width"] = stroke_width |
396 |
| - |
397 |
| - if corner_radius == 0: |
398 |
| - mob = Rectangle( |
399 |
| - width=self.attribute_to_float(rect_element.getAttribute("width")), |
400 |
| - height=self.attribute_to_float(rect_element.getAttribute("height")), |
401 |
| - **parsed_style, |
402 |
| - ) |
403 |
| - else: |
404 |
| - mob = RoundedRectangle( |
405 |
| - width=self.attribute_to_float(rect_element.getAttribute("width")), |
406 |
| - height=self.attribute_to_float(rect_element.getAttribute("height")), |
407 |
| - corner_radius=corner_radius, |
408 |
| - **parsed_style, |
409 |
| - ) |
410 |
| - |
411 |
| - mob.shift(mob.get_center() - mob.get_corner(UP + LEFT)) |
412 |
| - return mob |
| 431 | + # This seems hacky... yes it is. |
| 432 | + path_string = polygon_element.getAttribute("points").lstrip() |
| 433 | + for digit in string.digits: |
| 434 | + path_string = path_string.replace(" " + digit, " L" + digit) |
| 435 | + path_string = "M" + path_string |
| 436 | + if polygon_element.tagName == "polygon": |
| 437 | + path_string = path_string + "Z" |
| 438 | + return self.path_string_to_mobject(path_string, style) |
413 | 439 |
|
414 | 440 | def handle_transforms(self, element, mobject):
|
415 | 441 | """Applies the SVG transform to the specified mobject. Transforms include:
|
|
0 commit comments