///|
/// Escapes text for safe insertion into SVG/XML attributes.
pub fn escape_svg(value : String) -> String {
let builder = StringBuilder()
for character in value.to_array() {
match character {
'&' => builder.write_string("&")
'<' => builder.write_string("<")
'>' => builder.write_string(">")
'"' => builder.write_string(""")
'\'' => builder.write_string("'")
_ => builder.write_char(character)
}
}
builder.to_string()
}
///|
/// Adds a line path to a document using a data-driven style.
pub fn SvgDocument::add_line(
self : SvgDocument,
start : Vec2,
end : Vec2,
style : SvgStyle,
) -> Unit {
self.add(
SvgElement::SvgPath(
Path::new().move_to(start.x, start.y).line_to(end.x, end.y),
style,
),
)
}
///|
/// Adds a filled polygon to a document.
pub fn SvgDocument::add_polygon(
self : SvgDocument,
points : Array[Vec2],
style : SvgStyle,
) -> Unit {
self.add(SvgElement::SvgPath(polyline(points, closed=true), style))
}
///|
/// Renders a path with a compact style suitable for machine-generated assets.
pub fn SvgStyle::compact(self : SvgStyle) -> String {
"fill:\{self.fill};stroke:\{self.stroke};stroke-width:\{self.stroke_width};opacity:\{self.opacity}"
}
///|
pub fn SvgDocument::element_count(self : SvgDocument) -> Int {
self.elements.length()
}
///|
pub fn SvgDocument::bounds(self : SvgDocument) -> Rect {
Rect::new(0.0, 0.0, self.width, self.height)
}
///|
/// Serializes a design with a title and metadata block.
pub fn SvgDocument::to_svg_string_with_metadata(
self : SvgDocument,
title : String,
description : String,
) -> String {
let content = self.to_svg_string()
let marker = "