diff --git a/etch/src/svg.rs b/etch/src/svg.rs index b0bbb95..ff7460a 100644 --- a/etch/src/svg.rs +++ b/etch/src/svg.rs @@ -12,11 +12,23 @@ use crate::layout::GraphLayout; // Public types // --------------------------------------------------------------------------- +/// SVG shape element for a node — replaces the default ``. +/// +/// The shape provider returns raw SVG element(s) as a string. +/// The string is inserted directly into the SVG `` for the node, +/// replacing the default rectangle. +pub type ShapeProvider = Box String + Send + Sync>; + /// Options that control SVG rendering. -#[derive(Debug, Clone)] pub struct SvgOptions { /// Map from node type to fill colour (CSS value). pub type_colors: HashMap, + /// Map from node type to custom SVG shape provider. + /// + /// The function receives `(node_type, x, y, width, height, fill, stroke_color)` + /// and returns raw SVG element string (e.g. ``). + /// If no provider is set for a type, the default `` is used. + pub type_shapes: HashMap, /// Font family for all text. pub font_family: String, /// Font size in px. @@ -43,6 +55,7 @@ impl Default for SvgOptions { fn default() -> Self { Self { type_colors: HashMap::new(), + type_shapes: HashMap::new(), font_family: "system-ui, -apple-system, sans-serif".into(), font_size: 13.0, padding: 20.0, @@ -57,6 +70,20 @@ impl Default for SvgOptions { } } +// SvgOptions can't derive Debug/Clone due to Box +impl std::fmt::Debug for SvgOptions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SvgOptions") + .field("type_colors", &self.type_colors) + .field( + "type_shapes", + &format!("<{} providers>", self.type_shapes.len()), + ) + .field("font_family", &self.font_family) + .finish() + } +} + // --------------------------------------------------------------------------- // Public entry point // --------------------------------------------------------------------------- @@ -142,7 +169,7 @@ fn write_style(svg: &mut String, options: &SvgOptions) { write!( svg, "