Source code for svgen.element.path
"""
A module implementing a path element.
"""
# built-in
from enum import StrEnum
from typing import Any
# internal
from svgen.attribute.viewbox import ViewBox
from svgen.cartesian.mutate import Translation
from svgen.cartesian.point import Point
from svgen.color.resolve import get_color
from svgen.element import Element
[docs]
class Path(Element):
"""A path element."""
[docs]
@staticmethod
def create(*cmds: str, **kwargs) -> "Path":
"""A helper for creating path elements."""
return Path(d=" ".join(cmds), **kwargs)
[docs]
class PathCmd(StrEnum):
"""An enumeration of svg path commands."""
MOVE = "M"
LINE = "L"
[docs]
class PathBuilder:
"""A class implementing a path building interface."""
def __init__(self) -> None:
"""Initialize this instance."""
self.cmds: list[str] = []
[docs]
def close(self) -> None:
"""Close the current path."""
self.cmds.append("Z")
[docs]
def horizontal(self, count: float, relative: bool = True) -> None:
"""Issue a horizontal command."""
cmd = "h"
if not relative:
cmd = cmd.upper()
self.cmds.append(f"{cmd} {count}")
[docs]
def vertical(self, count: float, relative: bool = True) -> None:
"""Issue a vertical command."""
cmd = "v"
if not relative:
cmd = cmd.upper()
self.cmds.append(f"{cmd} {count}")
[docs]
def point(self, point: Point, cmd: PathCmd) -> None:
"""Issue a point-based command."""
self.cmds.append(f"{cmd} {point.x} {point.y}")
[docs]
def translation(self, translation: Translation, cmd: PathCmd) -> None:
"""Issue a translation-based command."""
self.cmds.append(f"{cmd.lower()} {translation.dx} {translation.dy}")
[docs]
def path(self, **kwargs) -> Path:
"""Get a path element based on this builder's state."""
return Path.create(*self.cmds, **kwargs)
[docs]
def compose_borders(viewbox: ViewBox, config: dict[str, Any]) -> list[Element]:
"""An example function for composing a document."""
builder = PathBuilder()
builder.point(viewbox.box.top_left, PathCmd.MOVE)
builder.horizontal(viewbox.width)
builder.vertical(viewbox.height)
builder.horizontal(-viewbox.width)
builder.close()
data = {
"fill": "none",
"stroke-width": config.get("stroke_width", 2),
"stroke": get_color(config["color"]),
}
if "opacity" in config:
data["stroke-opacity"] = config["opacity"]
return [builder.path(attrib=data)]