### Diagram Initialization for Text Rendering Example Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/mod.rs.html Sets up a simple two-node, one-edge diagram for testing text rendering functionality. This example demonstrates basic diagram construction. ```rust use mmdflux::graph::geometry::{ EngineHints, FRect, GraphGeometry, LayeredHints, LayoutEdge, PositionedNode, }; use mmdflux::render::graph::{render_text_from_geometry, TextRenderOptions}; use mmdflux::{Diagram, Direction, Edge, Node, Shape}; use std::collections::{HashMap, HashSet}; let mut diagram = Diagram::new(Direction::LeftRight); diagram.add_node(Node::new("A")); diagram.add_node(Node::new("B")); diagram.add_edge(Edge::new("A", "B")); let geometry = GraphGeometry { nodes: HashMap::from([ ( "A".to_string(), PositionedNode { id: "A".to_string(), rect: FRect::new(0.0, 0.0, 9.0, 3.0), shape: Shape::Rectangle, label: "A".to_string(), parent: None, }, ), ( "B".to_string(), PositionedNode { id: "B".to_string(), rect: FRect::new(20.0, 0.0, 9.0, 3.0), shape: Shape::Rectangle, label: "B".to_string(), parent: None, }, ), ]), // ... other fields omitted for brevity }; ``` -------------------------------- ### Setup Graph and Run Layering Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/order.rs.html Initializes a LayoutGraph from a Digraph, runs the acyclic and rank algorithms, normalizes the layout, and then applies the compound normalization and final ordering. This is a common setup for testing ordering algorithms. ```rust let mut lg = LayoutGraph::from_digraph(&graph, |_, _| (10.0, 10.0)); crate::engines::graph::algorithms::layered::acyclic::run(&mut lg); rank::run(&mut lg, &LayoutConfig::default()); rank::normalize(&mut lg); crate::engines::graph::algorithms::layered::normalize::run( &mut lg, &std::collections::HashMap::new(), false, ); ``` -------------------------------- ### Start Activation Bar in SVG Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/timeline/svg_layout.rs.html Records the start of an activation bar for a participant, pushing its starting y-coordinate and depth onto a stack. ```rust SequenceEvent::ActivateStart { participant } => { let depth = activation_depth[*participant]; activation_stacks[*participant].push((last_message_y, depth)); activation_depth[*participant] += 1; } ``` -------------------------------- ### Compute Layer Starts for Grid Projection Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/grid/derive/mod.rs.html Calculates the starting positions for each layer based on the grid projection, node bounds, and layout orientation. This is used for transforming waypoints. ```rust let layer_starts = grid_projection .map(|projection| compute_layer_starts(&projection.node_ranks, &node_bounds, is_vertical)) .unwrap_or_default(); ``` -------------------------------- ### Autonumbering Start, Step, Off, and Resume Source: https://docs.rs/mmdflux/latest/src/mmdflux/diagrams/sequence/compiler.rs.html Tests the behavior of autonumbering with custom start and step values, disabling it, and then resuming it. ```rust let model = compile_input("\nsequenceDiagram\n autonumber 5 2 participant A participant B A->>B: first B->>A: second autonumber off A->>B: third autonumber A->>B: fourth"); let numbers: Vec<_> = model .events .iter() .filter_map(|event| match event { SequenceEvent::Message { number, .. } => Some(*number), _ => None, }) .collect(); assert_eq!(numbers, vec![Some(5), Some(7), None, Some(9)]); assert_eq!(model.autonumber, AutonumberState { enabled: true, next: 10, ``` -------------------------------- ### Get Segment Start Cell Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/grid/label_placement.rs.html Extracts the starting GridCell from a Segment, handling both Horizontal and Vertical segments. ```rust fn segment_start_cell(seg: &Segment) -> GridCell { match *seg { Segment::Horizontal { y, x_start, .. } => (x_start, y), Segment::Vertical { x, y_start, .. } => (x, y_start), } } ``` -------------------------------- ### Helper: Simple A->B Tree Setup Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/network_simplex.rs.html Sets up a basic directed graph with two nodes (A, B) and one edge (A->B), along with a SpanningTree structure, for testing simple tree scenarios. ```rust /// Helper: A->B, ranks 0,1. Tree: A(root)->B. fn make_simple_ab_tree() -> (LayoutGraph, SpanningTree) { let mut g: DiGraph<()> = DiGraph::new(); g.add_node("A", ()); g.add_node("B", ()); ``` -------------------------------- ### Insert Basis Start Cap If Needed Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/basis.rs.html Inserts a control point at the start of a path if the first segment is shorter than the minimum stem length and collinear with subsequent segments. Ensures a minimum stem length from the start. ```rust fn insert_basis_start_cap_if_needed(points: &mut Vec, min_stem: f64) { const EPS: f64 = 1e-6; if points.len() < 2 || min_stem <= 0.0 { return; } let base_vec = Point { x: points[1].x - points[0].x, y: points[1].y - points[0].y, }; let first_segment_len = (base_vec.x * base_vec.x + base_vec.y * base_vec.y).sqrt(); if first_segment_len <= EPS || first_segment_len + EPS >= min_stem { return; } let mut traversed = 0.0; for seg_idx in 0..(points.len() - 1) { let seg_vec = Point { x: points[seg_idx + 1].x - points[seg_idx].x, y: points[seg_idx + 1].y - points[seg_idx].y, }; let seg_len = (seg_vec.x * seg_vec.x + seg_vec.y * seg_vec.y).sqrt(); if seg_len <= EPS { continue; } if !vectors_share_ray(base_vec, seg_vec) { break; } if traversed + seg_len + EPS >= min_stem { let t = ((min_stem - traversed) / seg_len).clamp(0.0, 1.0); if t >= 1.0 - EPS { return; } let cap = Point { x: points[seg_idx].x + seg_vec.x * t, y: points[seg_idx].y + seg_vec.y * t, }; if !points_approx_equal(cap, points[seg_idx]) && !points_approx_equal(cap, points[seg_idx + 1]) { points.insert(seg_idx + 1, cap); } return; } traversed += seg_len; } } ``` -------------------------------- ### Test Setup for Graph Layering Algorithms Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/order.rs.html Sets up a directed graph with nodes and edges for testing layering algorithms. It initializes a DiGraph and adds nodes and edges. ```rust fn setup_graph_and_run( nodes: &[&str], edges_list: &[(&str, &str)], ) -> (LayoutGraph, Vec>) { let mut graph: DiGraph<()> = DiGraph::new(); for &n in nodes { graph.add_node(n, ()); } for &(from, to) in edges_list { graph.add_edge(from, to); } ``` -------------------------------- ### Start State Node Test Source: https://docs.rs/mmdflux/latest/src/mmdflux/diagrams/state/compiler.rs.html Checks that the start state ('[*]') is correctly compiled into a node with the 'SmallCircle' shape. ```rust let graph = compile_state("stateDiagram-v2\n [*] --> Idle"); let start_node = graph.nodes.values().find(|n| n.shape == Shape::SmallCircle); assert!(start_node.is_some()); assert_eq!(graph.edges[0].to, "Idle"); ``` -------------------------------- ### Build LayoutGraph with Label Dummies Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/compartment_spacing.rs.html Constructs a LayoutGraph from edges and attaches label dummy nodes. Used to set up graph structures for projection algorithms. Requires a `DiGraph` and a list of label parameters. ```rust fn build_with_label_dummies( edges: &[(&str, &str)], labels: &[(usize, i32, f64, f64, f64)], ) -> (LayoutGraph, std::collections::HashMap) { let mut g: DiGraph<(f64, f64)> = DiGraph::new(); let mut seen = std::collections::HashSet::new(); for (src, tgt) in edges { if seen.insert(*src) { g.add_node(*src, (40.0, 20.0)); } if seen.insert(*tgt) { g.add_node(*tgt, (40.0, 20.0)); } g.add_edge(*src, *tgt); } let mut lg = LayoutGraph::from_digraph(&g, |_, dims| *dims); let mut cross = std::collections::HashMap::new(); for (edge_index, rank, width, height, cross_center) in labels { let dummy_id = NodeId::from(format!( ``` ```rust _label{}\n lg.node_ids.len()) ; let dummy_idx = lg.node_ids.len(); let dummy_node = DummyNode::edge_label(*edge_index, *rank, *width, *height, LabelPos::Center); lg.node_ids.push(dummy_id.clone()); lg.node_index.insert(dummy_id.clone(), dummy_idx); lg.ranks.push(*rank); lg.order.push(dummy_idx); lg.positions.push(Point::default()); lg.dimensions.push((*width, *height)); lg.original_has_predecessor.push(false); lg.parents.push(None); lg.model_order.push(None); lg.dummy_nodes.insert(dummy_id, dummy_node); cross.insert(dummy_idx, *cross_center); } (lg, cross) } ``` -------------------------------- ### Create New DiagramRegistry Source: https://docs.rs/mmdflux/latest/mmdflux/registry/struct.DiagramRegistry.html Instantiates a new, empty DiagramRegistry. Use this to start managing diagram types. ```rust pub fn new() -> Self ``` -------------------------------- ### OrthogonalRoutingOptions Preview Method Source: https://docs.rs/mmdflux/latest/mmdflux/graph/routing/struct.OrthogonalRoutingOptions.html Provides a conservative preview of orthogonal routing for forward edges only. Use this to initialize routing options with default behavior. ```rust pub fn preview() -> Self ``` -------------------------------- ### Get Cause for ParseError (Deprecated) Source: https://docs.rs/mmdflux/latest/mmdflux/mmds/struct.ParseError.html Deprecated method to get the underlying cause of the error. Replaced by Error::source. ```rust fn cause(&self) -> Option<&dyn Error> ``` -------------------------------- ### Get Description for ParseError (Deprecated) Source: https://docs.rs/mmdflux/latest/mmdflux/mmds/struct.ParseError.html Deprecated method to get a string description of the error. Use the Display implementation or to_string() instead. ```rust fn description(&self) -> &str ``` -------------------------------- ### Start SVG with Root Style Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/svg/mod.rs.html Begins an SVG document, setting up the root tag with specified dimensions, font properties, and root styling. Includes optional CSS style block. ```rust pub(crate) fn start_svg_with_root_style( &mut self, width: f64, height: f64, font_family: &str, font_size: f64, root_style: &SvgRootStyle, ) { let view_width = fmt_f64(width); let view_height = fmt_f64(height); let view_box = format!("0 0 {view_width} {view_height}"); let mut style_parts = vec![ format!("max-width: {view_width}px"), format!( "background-color: {}", root_style .background_color .as_deref() .unwrap_or("transparent") ), ]; style_parts.extend( root_style .css_variables .iter() .map(|(name, value)| format!("{name}:{value}")), ); let style = format!("{};", style_parts.join("; ")); let line = format!( "", view_box = view_box, style = style, font = escape_text(font_family), font_size = fmt_f64(font_size) ); self.push_line(&line); self.indent += 1; if let Some(style_block) = &root_style.style_block { self.start_tag(""); } } ``` -------------------------------- ### Clip Edge Points to Start of Rectangle Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/endpoints.rs.html Clips a sequence of points representing an edge path so that the starting point lies within the specified rectangle. If the start point is outside, the original points are returned. If the path segment exiting the rectangle is found, an intersection point is calculated. ```rust pub(super) fn clip_points_to_rect_start(points: &[Point], rect: &Rect) -> Vec { if points.len() < 2 { return points.to_vec(); } if !point_inside_rect(rect, points[0]) { return points.to_vec(); } let mut idx = 0usize; while idx + 1 < points.len() && point_inside_rect(rect, points[idx]) { idx += 1; } if idx == 0 || idx >= points.len() { return points.to_vec(); } let inside = points[idx - 1]; let outside = points[idx]; let intersection = segment_rect_intersection(inside, outside, rect).unwrap_or(inside); let mut out = Vec::new(); out.push(intersection); out.extend_from_slice(&points[idx..]); out } ``` -------------------------------- ### Initialize SvgBounds Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/bounds.rs.html Creates a new `SvgBounds` instance with infinite initial values, ready to track minimum and maximum coordinates. ```rust fn new() -> Self { Self { min_x: f64::INFINITY, min_y: f64::INFINITY, max_x: f64::NEG_INFINITY, max_y: f64::NEG_INFINITY, } } ``` -------------------------------- ### Build LayoutGraph and Run Pipeline Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/parent_dummy_chains.rs.html Constructs a `LayoutGraph` from a `DiGraph`, applies various layout algorithms including `parent_dummy_chains`, and returns the processed graph. ```rust fn build_external_node_subgraph_after_parent_dummy_chains() -> LayoutGraph { let mut g = DiGraph::new(); // Add nodes g.add_node("us-east", (0, 0)); g.add_node("us-west", (0, 0)); // Titles g.set_has_title("Cloud"); g.set_has_title("us-east"); g.set_has_title("us-west"); // Parent relationships for nodes g.set_parent("A", "us-east"); g.set_parent("B", "us-east"); g.set_parent("C", "us-west"); g.set_parent("D", "us-west"); // Parent relationships for nested subgraphs g.set_parent("us-east", "Cloud"); g.set_parent("us-west", "Cloud"); // Edges: A→B (0), C→D (1), E→A (2), E→C (3) g.add_edge("A", "B"); g.add_edge("C", "D"); g.add_edge("E", "A"); g.add_edge("E", "C"); let mut lg = LayoutGraph::from_digraph(&g, |_, dims| (dims.0 as f64, dims.1 as f64)); // Run pipeline up through parent_dummy_chains (matching layout_with_labels) extract_self_edges(&mut lg); crate::engines::graph::algorithms::layered::acyclic::run(&mut lg); make_space_for_edge_labels(&mut lg); crate::engines::graph::algorithms::layered::nesting::run(&mut lg); rank::run(&mut lg, &LayoutConfig::default()); rank::remove_empty_ranks(&mut lg); crate::engines::graph::algorithms::layered::nesting::cleanup(&mut lg); rank::normalize(&mut lg); crate::engines::graph::algorithms::layered::nesting::insert_title_nodes(&mut lg); rank::normalize(&mut lg); crate::engines::graph::algorithms::layered::nesting::assign_rank_minmax(&mut lg); normalize::run(&mut lg, &HashMap::new(), false); run(&mut lg); lg } ``` -------------------------------- ### Parse Block Start Source: https://docs.rs/mmdflux/latest/src/mmdflux/mermaid/sequence/mod.rs.html Parses the start of control flow blocks like 'loop', 'alt', and 'opt'. Extracts the block kind and its optional label. ```rust fn try_parse_block_start(line: &str) -> Option { parse_keyword_line(line, "loop") .map(|label| SequenceStatement::BlockStart { kind: BlockKind::Loop, label, }) .or_else(|| { parse_keyword_line(line, "alt").map(|label| SequenceStatement::BlockStart { kind: BlockKind::Alt, label, }) }) .or_else(|| { parse_keyword_line(line, "opt").map(|label| SequenceStatement::BlockStart { kind: BlockKind::Opt, label, }) }) .or_else(|| { // ... other block types like 'par' could be added here }) } ``` -------------------------------- ### Test Compiler Lollipop Edge (Start) Source: https://docs.rs/mmdflux/latest/src/mmdflux/diagrams/class/compiler.rs.html Tests lollipop edges ('()--') where the circle marker is at the start, ensuring correct arrow and endpoint shape. ```rust #[test] fn compiler_lollipop_edge_uses_circle_marker_at_start() { let diagram = compile_class("classDiagram\nfoo ()-- Class01"); assert_eq!(diagram.edges[0].arrow_start, Arrow::Circle); assert_eq!(diagram.edges[0].arrow_end, Arrow::None); assert!(!diagram.nodes.contains_key("foo")); let endpoint = &diagram.nodes[&diagram.edges[0].from]; assert_eq!(endpoint.shape, Shape::TextBlock); assert_eq!(endpoint.label, "foo"); assert_eq!(diagram.nodes["Class01"].shape, Shape::Rectangle); } ``` -------------------------------- ### FPoint::new Source: https://docs.rs/mmdflux/latest/mmdflux/graph/space/struct.FPoint.html Constructor for creating a new FPoint instance. ```APIDOC ### impl FPoint #### pub fn new(x: f64, y: f64) -> Self Creates a new FPoint with the given x and y coordinates. ``` -------------------------------- ### Rebuild Points with Start Cap Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/basis.rs.html Reconstructs a list of points by inserting a new start cap point into an existing sequence. Ensures the new sequence is deduplicated. ```rust fn rebuild_with_start_cap(points: &[Point], seg_idx: usize, cap: Point) -> Vec { if points.len() < 2 || seg_idx >= points.len() - 1 { return points.to_vec(); } let mut rebuilt = Vec::with_capacity(points.len() + 1); rebuilt.push(points[0]); rebuilt.push(cap); rebuilt.extend_from_slice(&points[(seg_idx + 1)..]); dedup_consecutive_svg_points(&rebuilt) } ``` -------------------------------- ### FRect constructor and methods Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/space.rs.html Provides a constructor for FRect and methods to calculate the center x, center y, and center point of the rectangle. ```rust impl FRect { pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self { Self { x, y, width, height, } } pub fn center_x(&self) -> f64 { self.x + self.width / 2.0 } pub fn center_y(&self) -> f64 { self.y + self.height / 2.0 } pub fn center(&self) -> FPoint { FPoint { x: self.center_x(), y: self.center_y(), } } } ``` -------------------------------- ### Segment Start Point Retrieval Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/grid/routing/types.rs.html Returns the starting `Point` of the segment. For vertical segments, `x` is fixed and `y` is `y_start`. For horizontal segments, `y` is fixed and `x` is `x_start`. ```rust pub fn start_point(&self) -> Point { match self { Segment::Vertical { x, y_start, .. } => Point { x: *x, y: *y_start }, Segment::Horizontal { y, x_start, .. } => Point { x: *x_start, y: *y }, } } ``` -------------------------------- ### Build Compound Graph for Ordering Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/order.rs.html Constructs a sample `LayoutGraph` with nested subgraphs and edges to test ordering algorithms. This setup is used to verify the placement of border nodes. ```rust fn build_compound_for_ordering() -> LayoutGraph { let mut g: DiGraph<()> = DiGraph::new(); g.add_node("X", ()); g.add_node("A", ()); g.add_node("B", ()); g.add_node("sg1", ()); g.add_edge("X", "A"); g.add_edge("A", "B"); g.set_parent("A", "sg1"); g.set_parent("B", "sg1"); let mut lg = LayoutGraph::from_digraph(&g, |_, _| (10.0, 10.0)); nesting::run(&mut lg); rank::run(&mut lg, &LayoutConfig::default()); rank::normalize(&mut lg); nesting::cleanup(&mut lg); nesting::assign_rank_minmax(&mut lg); border::add_segments(&mut lg); lg } ``` -------------------------------- ### Parse Full Example State Diagram Source: https://docs.rs/mmdflux/latest/src/mmdflux/mermaid/state/mod.rs.html Parses a comprehensive state diagram with multiple states and transitions. Asserts the total number of statements. ```rust let input = "stateDiagram-v2 [*] --> Idle Idle --> Processing : submit Processing --> Done : complete Done --> [*]"; let result = parse_state_diagram(input).unwrap(); assert_eq!(result.model.statements.len(), 4); ``` -------------------------------- ### Draw Source Launch Point for Edges Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/text/edge.rs.html Draws the starting point of an edge if it has no start arrow, is not a self-loop, and has segments. It uses the `source_connection` function to determine the connection type. ```rust fn draw_source_launch( canvas: &mut Canvas, routed: &RoutedEdge, charset: &CharSet, edge_color: Option<(u8, u8, u8)>, ) { if routed.edge.arrow_start != Arrow::None || routed.is_self_edge || routed.segments.is_empty() { return; } let Some(direction) = routed.source_connection else { return; }; if canvas.set_with_connection( routed.start.x, routed.start.y, source_connection(direction), charset, routed.edge.stroke, ) { merge_edge_fg(canvas, routed.start.x, routed.start.y, edge_color); } } ``` -------------------------------- ### Run Layered Layout Computation Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/pipeline.rs.html Main entry point for layout computation. Takes a directed graph, configuration, and a function to get node dimensions. Returns a LayoutResult. ```rust pub fn run_layered_layout( graph: &DiGraph, config: &LayoutConfig, get_dimensions: F, ) -> LayoutResult where F: Fn(&NodeId, &N) -> (f64, f64), { layout(graph, config, get_dimensions) } ``` -------------------------------- ### Rect Transformation: Setting Start Position Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/routing/label_clamp.rs.html Creates a new FRect with a specified start position along a given axis. This is used to adjust the position of a rectangle after clamping. ```rust fn rect_with_axis_start(rect: FRect, axis: Axis, new_start: f64) -> FRect { match axis { Axis::Y => FRect::new(rect.x, new_start, rect.width, rect.height), Axis::X => FRect::new(new_start, rect.y, rect.width, rect.height), } } ``` -------------------------------- ### Build Path from Hints with Degenerate Layout Hint Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/routing/mod.rs.html Builds a path from hints, falling back to nodes and waypoints when the layout hint is degenerate. The fallback uses provided waypoints. ```rust geom.edges[0].layout_path_hint = Some(vec![FPoint::new(70.0, 35.0), FPoint::new(70.0, 35.0)]); geom.edges[0].waypoints = vec![FPoint::new(60.0, 55.0)]; let path = orthogonal::hints::build_path_from_hints(&geom.edges[0], &geom); assert_eq!( path, vec![ FPoint::new(70.0, 35.0), FPoint::new(60.0, 55.0), FPoint::new(70.0, 85.0), ] ); ``` -------------------------------- ### Handle Out-of-Bounds Coordinates Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/text/canvas.rs.html Demonstrates attempting to set or get a cell outside the canvas dimensions. `set` returns false, and `get` returns None for out-of-bounds access. ```rust let mut canvas = Canvas::new(5, 5); assert!(!canvas.set(10, 10, 'X')); assert!(canvas.get(10, 10).is_none()); ``` -------------------------------- ### Path from Prepared Points (Curved Mode) Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/path_emit.rs.html Generates an SVG path using prepared points with the 'Basis' curve mode. Verifies the path starts correctly and includes a curve command ('C'). ```rust let path = path_from_prepared_points( &[ Point { x: 0.0, y: 0.0 }, Point { x: 10.0, y: 0.0 }, Point { x: 10.0, y: 10.0 }, ], &Edge::new("A", "B"), 1.0, Curve::Basis, 4.0, false, false, ); assert!(path.starts_with("M0.00,0.00")); assert!(path.contains('C')); ``` -------------------------------- ### MermaidLayeredEngine Initialization Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/mermaid.rs.html Provides a constructor for creating a new instance of the MermaidLayeredEngine. ```rust impl MermaidLayeredEngine { /// Create the Mermaid-compatible graph engine adapter. pub fn new() -> Self { Self } } ``` -------------------------------- ### Test Additional Block Starts Parsing Source: https://docs.rs/mmdflux/latest/src/mmdflux/mermaid/sequence/mod.rs.html Verifies the parsing of various block start statements like 'par', 'critical', and 'break', ensuring their kinds and labels are correctly identified. ```rust #[test] fn parse_additional_block_starts() { let stmts = parse_stmts( "sequenceDiagram\npar notifications\ncritical establish connection\nbreak success", ); assert_eq!( stmts, vec![ SequenceStatement::BlockStart { kind: BlockKind::Par, label: "notifications".to_string(), }, SequenceStatement::BlockStart { kind: BlockKind::Critical, label: "establish connection".to_string(), }, SequenceStatement::BlockStart { kind: BlockKind::Break, label: "success".to_string(), }, ] ); } ``` -------------------------------- ### Path from Prepared Points (Rounded Mode) Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/path_emit.rs.html Generates an SVG path using prepared points with a rounded corner style. Asserts the path starts correctly and uses quadratic Bezier curves ('Q'). ```rust let path = path_from_prepared_points( &[ Point { x: 0.0, y: 0.0 }, Point { x: 10.0, y: 0.0 }, Point { x: 10.0, y: 10.0 }, ], &Edge::new("A", "B"), 1.0, Curve::Linear(CornerStyle::Rounded), 4.0, false, false, ); assert!(path.starts_with("M0.00,0.00")); assert!(path.contains('Q')); ``` -------------------------------- ### High-Level API: Customizing Output with RenderConfig Source: https://docs.rs/mmdflux/latest/index.html Shows how to customize the rendering process using `RenderConfig`, including options for routing style, padding, and layout parameters. ```APIDOC ## Customizing output Use `RenderConfig` to control layout direction, engine selection, edge routing, padding, color mode, and more: ```rust use mmdflux::{OutputFormat, RenderConfig, render_diagram}; use mmdflux::LayoutConfig; use mmdflux::format::RoutingStyle; let config = RenderConfig { routing_style: Some(RoutingStyle::Direct), padding: Some(2), layout: LayoutConfig { rank_sep: 30.0, ..LayoutConfig::default() }, ..RenderConfig::default() }; let output = render_diagram("graph LR\n A-->B-->C", OutputFormat::Text, &config).unwrap(); println!("{output}"); ``` ``` -------------------------------- ### Concurrent Regions with Independent Star Scopes Source: https://docs.rs/mmdflux/latest/src/mmdflux/diagrams/state/compiler.rs.html Tests concurrent regions where each region has its own independent start and end pseudo-states. Verifies the correct number of start and end nodes are generated. ```rust #[test] fn compiler_concurrent_regions_independent_star_scopes() { let input = "\ stateDiagram-v2 state Active { [*] --> A1 A1 --> [*] -- [*] --> B1 B1 --> [*] }"; let graph = compile_state(input); // Each region should have its own start and end pseudo-states. let start_nodes: Vec<_> = graph .nodes .values() .filter(|n| n.shape == Shape::SmallCircle) .collect(); let end_nodes: Vec<_> = graph .nodes .values() .filter(|n| n.shape == Shape::FramedCircle) .collect(); // Two start nodes (one per region) and two end nodes. assert_eq!(start_nodes.len(), 2); assert_eq!(end_nodes.len(), 2); } ``` -------------------------------- ### Parse Start Arrow Head Source: https://docs.rs/mmdflux/latest/src/mmdflux/mermaid/flowchart.rs.html Parses the starting arrow head for a link, considering the first character of the input string. It maps characters like '<', 'x', and 'o' to specific ArrowHead variants. ```rust fn parse_start_arrow_head(s: &str) -> ArrowHead { match s.chars().next() { Some('<') => ArrowHead::Normal, Some('x') => ArrowHead::Cross, Some('o') => ArrowHead::Circle, _ => ArrowHead::None, } } ``` -------------------------------- ### into_render_config Method Source: https://docs.rs/mmdflux/latest/mmdflux/struct.RuntimeConfigInput.html This method validates and converts a RuntimeConfigInput into a typed RenderConfig. ```APIDOC ### impl RuntimeConfigInput #### pub fn into_render_config(self) -> Result Validate and convert into a typed `RenderConfig`. ``` -------------------------------- ### Compute Tail Label Position for Vertical Path Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/routing/mod.rs.html Computes the position for the tail label near the start of a vertical path. Ensures the label is close to the path's starting point. ```rust let path = vec![FPoint::new(50.0, 0.0), FPoint::new(50.0, 100.0)]; let (_head, tail) = compute_end_label_positions(&path); let tail = tail.unwrap(); assert!(tail.y < 20.0, "tail near start, got y={}", tail.y); ``` -------------------------------- ### Example Theme Definition: zinc-light Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/svg/theme.rs.html Defines the 'zinc-light' theme using a `ThemeSeed`. This is a predefined theme with specific background and foreground colors. ```rust named_theme( "zinc-light", ThemeSeed { bg: "#ffffff", fg: "#27272a", line: None, accent: None, muted: None, surface: None, border: None, }, ), ``` -------------------------------- ### Direct Route Graph Geometry Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/routing/mod.rs.html Demonstrates setting up `GraphGeometry` with nodes and edges for direct routing. Asserts the expected path of the routed edge. ```rust let mut diagram = Graph::new(crate::graph::Direction::TopDown); diagram.add_node(crate::graph::Node::new("A")); diagram.add_node(crate::graph::Node::new("B")); diagram.add_edge(crate::graph::Edge::new("A", "B")); let mut nodes = HashMap::new(); nodes.insert( "A".into(), PositionedNode { id: "A".into(), rect: FRect::new(0.0, 0.0, 40.0, 20.0), shape: crate::graph::Shape::Rectangle, label: "A".into(), parent: None, }, ); nodes.insert( "B".into(), PositionedNode { id: "B".into(), rect: FRect::new(100.0, 0.0, 40.0, 20.0), shape: crate::graph::Shape::Rectangle, label: "B".into(), parent: None, }, ); let mut node_directions = HashMap::new(); node_directions.insert("A".into(), crate::graph::Direction::LeftRight); node_directions.insert("B".into(), crate::graph::Direction::LeftRight); let geom = GraphGeometry { nodes, edges: vec![LayoutEdge { index: 0, from: "A".into(), to: "B".into(), waypoints: vec![], label_position: None, label_side: None, from_subgraph: None, to_subgraph: None, layout_path_hint: None, preserve_orthogonal_topology: false, label_geometry: None, effective_wrapped_lines: None, }], subgraphs: HashMap::new(), self_edges: vec![], direction: crate::graph::Direction::TopDown, node_directions, bounds: FRect::new(0.0, 0.0, 140.0, 20.0), reversed_edges: vec![], engine_hints: None, grid_projection: None, rerouted_edges: std::collections::HashSet::new(), enhanced_backward_routing: false, }; let routed = route_graph_geometry( &diagram, &geom, EdgeRouting::DirectRoute, &default_proportional_text_metrics(), ); assert_eq!( routed.edges[0].path, vec![FPoint::new(40.0, 10.0), FPoint::new(100.0, 10.0)] ); ``` -------------------------------- ### Draw Edge Path and Arrows Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/text/edge.rs.html Renders the main path of an edge, including drawing each segment and placing arrows at the start and end points if configured. It also calls `draw_source_launch` for the starting point. ```rust fn draw_edge_path_and_arrows(canvas: &mut Canvas, routed: &RoutedEdge, charset: &CharSet) { let edge_color = resolved_edge_stroke_color(routed); for segment in &routed.segments { draw_segment(canvas, segment, routed.edge.stroke, charset, edge_color); } draw_source_launch(canvas, routed, charset, edge_color); if routed.edge.arrow_end != Arrow::None { draw_arrow_with_entry( canvas, &routed.end, routed.entry_direction, charset, routed.edge.arrow_end, edge_color, ); } if routed.edge.arrow_start != Arrow::None && !routed.is_self_edge { let exit_direction = exit_direction_from_segments(&routed.segments); draw_arrow_with_entry( canvas, &routed.start, exit_direction, charset, routed.edge.arrow_start, edge_color, ); } } ``` -------------------------------- ### PathSimplification Simplify Method Source: https://docs.rs/mmdflux/latest/src/mmdflux/simplification.rs.html Simplifies a slice of points based on the `PathSimplification` level. For `Lossy`, it retains start, midpoint, and end. For `Minimal`, it retains only start and end. Other levels return a clone of the original points. ```rust pub fn simplify(&self, points: &[T]) -> Vec { match self { PathSimplification::None => points.to_vec(), PathSimplification::Lossless => points.to_vec(), PathSimplification::Lossy if points.len() > 3 => { let mid = points.len() / 2; vec![ points[0].clone(), points[mid].clone(), points[points.len() - 1].clone(), ] } PathSimplification::Minimal if points.len() > 2 => { vec![points[0].clone(), points[points.len() - 1].clone()] } _ => points.to_vec(), } } ``` -------------------------------- ### Test Dummy Node Initialization Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/graph.rs.html Verifies the correct initialization and identification of dummy nodes within the layout graph structure. ```rust lg.original_has_predecessor.push(false); lg.dummy_nodes.insert(dummy_id, DummyNode::edge(0, 1)); // Now index 2 is a dummy assert!(lg.is_dummy_index(2)); assert!(!lg.is_dummy_index(0)); ``` -------------------------------- ### Set and Get Cell Content Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/text/canvas.rs.html Modifies a character at a specific coordinate on the canvas or retrieves it. Returns true on successful set, false if out of bounds. `get` returns an Option containing the Cell if within bounds. ```rust let mut canvas = Canvas::new(5, 5); assert!(canvas.set(2, 3, 'X')); assert_eq!(canvas.get(2, 3).unwrap().ch, 'X'); ``` -------------------------------- ### FRect::new Source: https://docs.rs/mmdflux/latest/mmdflux/graph/space/struct.FRect.html Creates a new FRect instance with the specified coordinates and dimensions. ```APIDOC ### pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self Creates a new FRect instance. ``` -------------------------------- ### Path from Prepared Points (Straight Mode) Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/path_emit.rs.html Generates an SVG path using prepared points with a sharp corner style, resulting in straight lines. Verifies the path starts correctly and does not contain curve commands ('Q', 'C'), ending with a line command ('L'). ```rust let path = path_from_prepared_points( &[ Point { x: 0.0, y: 0.0 }, Point { x: 10.0, y: 0.0 }, Point { x: 10.0, y: 10.0 }, ], &Edge::new("A", "B"), 1.0, Curve::Linear(CornerStyle::Sharp), 4.0, false, false, ); assert!(path.starts_with("M0.00,0.00")); assert!(!path.contains('Q')); assert!(!path.contains('C')); assert!(path.ends_with("L10.00,10.00")); ``` -------------------------------- ### Calculate Start Cap Point on Existing Run Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/basis.rs.html Calculates the starting cap point for an existing run of points based on a minimum stem length. Returns the segment index and the cap point, or None if conditions are not met. ```rust fn start_cap_point_on_existing_run(points: &[Point], min_stem: f64) -> Option<(usize, Point)> { const EPS: f64 = 1e-6; if points.len() < 2 || min_stem <= 0.0 { return None; } let base_vec = Point { x: points[1].x - points[0].x, y: points[1].y - points[0].y, }; let first_segment_len = (base_vec.x * base_vec.x + base_vec.y * base_vec.y).sqrt(); if first_segment_len <= EPS { return None; } let mut traversed = 0.0; let mut last_seg_idx_on_ray = 0usize; for seg_idx in 0..(points.len() - 1) { let seg_vec = Point { x: points[seg_idx + 1].x - points[seg_idx].x, y: points[seg_idx + 1].y - points[seg_idx].y, }; let seg_len = (seg_vec.x * seg_vec.x + seg_vec.y * seg_vec.y).sqrt(); if seg_len <= EPS { continue; } if !vectors_share_ray(base_vec, seg_vec) { break; } last_seg_idx_on_ray = seg_idx; if traversed + seg_len + EPS >= min_stem { let t = ((min_stem - traversed) / seg_len).clamp(0.0, 1.0); let cap = Point { x: points[seg_idx].x + seg_vec.x * t, y: points[seg_idx].y + seg_vec.y * t, }; return Some((seg_idx, cap)); } traversed += seg_len; } Some((last_seg_idx_on_ray, points[last_seg_idx_on_ray + 1])) } ``` -------------------------------- ### Helper: Dummy LayoutGraph for Sorting Tests Source: https://docs.rs/mmdflux/latest/src/mmdflux/engines/graph/algorithms/layered/kernel/order.rs.html Creates a dummy `LayoutGraph` with a specified number of nodes, each having a sequential `model_order` for use in sorting tests. ```rust /// Create a dummy LayoutGraph with enough nodes for sort_entries tests. /// Node indices 0..=max_node are created with sequential model_order. fn dummy_graph_for_sort(max_node: usize) -> LayoutGraph { let mut graph: DiGraph<()> = DiGraph::new(); let names: Vec = (0..=max_node).map(|i| format!("n{i}")).collect(); for name in &names { graph.add_node(name.as_str(), ()); } LayoutGraph::from_digraph(&graph, |_, _| (10.0, 10.0)) } ``` -------------------------------- ### PathSimplification Enum Definition Source: https://docs.rs/mmdflux/latest/src/mmdflux/simplification.rs.html Defines the levels of path simplification available for MMDS and SVG output. Use `Lossless` by default for no visible change, `Lossy` to reduce points to start, midpoint, and end, or `Minimal` for just start and end points. ```rust pub enum PathSimplification { /// No simplification. All routed waypoints are retained. None, /// Lossless: remove redundant collinear and duplicate interior points. #[default] Lossless, /// Lossy: reduce to start, midpoint, and end (3 points max). Lossy, /// Minimal: start and end only (2 points max). Minimal, } ``` -------------------------------- ### LayoutEdge with Optional Path Hint Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/geometry.rs.html Illustrates the construction of a LayoutEdge, highlighting that the layout_path_hint field is optional and defaults to None. ```rust let edge = LayoutEdge { index: 0, from: "A".into(), to: "B".into(), waypoints: vec![FPoint::new(1.0, 2.0)], label_position: None, label_side: None, from_subgraph: None, to_subgraph: None, layout_path_hint: None, preserve_orthogonal_topology: false, label_geometry: None, effective_wrapped_lines: None, }; assert!(edge.layout_path_hint.is_none()); assert_eq!(edge.waypoints.len(), 1); ``` -------------------------------- ### Find a point adjacent to another point at a given distance Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/svg/edges/endpoints.rs.html Calculates a new point that is a specified distance away from a starting point, along the line defined by the starting point and a second reference point. Handles cases where the points are coincident. ```rust fn find_adjacent_point(point_a: Point, point_b: Point, distance: f64) -> Point { let x_diff = point_b.x - point_a.x; let y_diff = point_b.y - point_a.y; let length = (x_diff * x_diff + y_diff * y_diff).sqrt(); if length <= f64::EPSILON { return point_b; } let ratio = distance / length; Point { x: point_b.x - ratio * x_diff, y: point_b.y - ratio * y_diff, } } ``` -------------------------------- ### ForkJoin Shape Example Source: https://docs.rs/mmdflux/latest/mmdflux/graph/enum.Shape.html Represents a fork or join bar. ```rust @{shape: fork} ``` -------------------------------- ### Self Edges Routing Test Setup Source: https://docs.rs/mmdflux/latest/src/mmdflux/graph/routing/mod.rs.html Initializes a graph and geometry for testing self-edge routing. Includes adding a self-edge with specified points. ```rust let (diagram, mut geom) = simple_geometry(); geom.self_edges.push(SelfEdgeGeometry { node_id: "A".into(), edge_index: 1, points: vec![ ``` -------------------------------- ### Compile Open Solid Edge with Default Minlen Source: https://docs.rs/mmdflux/latest/src/mmdflux/diagrams/flowchart/compiler.rs.html Tests the compilation of an open solid edge (represented by '---'), verifying its default minimum length behavior. ```rust fn test_build_diagram_open_solid_edge_default_minlen() { let flowchart = parse_flowchart("graph TD A --- B ").unwrap(); ``` -------------------------------- ### TextBlock Shape Example Source: https://docs.rs/mmdflux/latest/mmdflux/graph/enum.Shape.html Represents a text block with no border. ```rust @{shape: text} ``` -------------------------------- ### Compact Bottom Launch Rendering Source: https://docs.rs/mmdflux/latest/src/mmdflux/render/graph/text/edge.rs.html Tests the rendering of a compact bottom launch edge, verifying the corner is positioned at the start cell. ```rust let charset = CharSet::unicode(); let mut canvas = Canvas::new(12, 8); let routed = RoutedEdge { edge: Edge::new("A", "B"), start: Point::new(2, 3), end: Point::new(8, 6), segments: vec![ Segment::Horizontal { y: 3, x_start: 2, x_end: 8, }, Segment::Vertical { x: 8, y_start: 3, y_end: 6, }, ], source_connection: Some(AttachDirection::Top), entry_direction: AttachDirection::Top, is_backward: false, is_self_edge: false, ``` -------------------------------- ### Diamond Shape Example Source: https://docs.rs/mmdflux/latest/mmdflux/graph/enum.Shape.html Represents a diamond or decision shape. ```rust {text} ```