etassia 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +140 -0
- data/LICENSE +25 -0
- data/README.adoc +436 -0
- data/exe/etassia +7 -0
- data/lib/etassia/cli.rb +187 -0
- data/lib/etassia/commands/batch.rb +210 -0
- data/lib/etassia/commands/notation_loader.rb +22 -0
- data/lib/etassia/commands/render.rb +98 -0
- data/lib/etassia/commands/types.rb +33 -0
- data/lib/etassia/commands/version.rb +24 -0
- data/lib/etassia/corpus_type_names.rb +52 -0
- data/lib/etassia/diagram/architecture.rb +108 -0
- data/lib/etassia/diagram/base.rb +61 -0
- data/lib/etassia/diagram/block.rb +102 -0
- data/lib/etassia/diagram/c4.rb +337 -0
- data/lib/etassia/diagram/class_diagram.rb +466 -0
- data/lib/etassia/diagram/class_namespace.rb +17 -0
- data/lib/etassia/diagram/class_note.rb +17 -0
- data/lib/etassia/diagram/containment.rb +107 -0
- data/lib/etassia/diagram/er_diagram.rb +317 -0
- data/lib/etassia/diagram/error.rb +38 -0
- data/lib/etassia/diagram/flowchart.rb +419 -0
- data/lib/etassia/diagram/flowchart_label_text.rb +63 -0
- data/lib/etassia/diagram/gantt.rb +94 -0
- data/lib/etassia/diagram/generic_text.rb +30 -0
- data/lib/etassia/diagram/git_graph.rb +57 -0
- data/lib/etassia/diagram/info.rb +38 -0
- data/lib/etassia/diagram/kanban.rb +198 -0
- data/lib/etassia/diagram/mindmap.rb +71 -0
- data/lib/etassia/diagram/packet.rb +93 -0
- data/lib/etassia/diagram/pie.rb +115 -0
- data/lib/etassia/diagram/quadrant.rb +135 -0
- data/lib/etassia/diagram/radar.rb +65 -0
- data/lib/etassia/diagram/requirement.rb +168 -0
- data/lib/etassia/diagram/sankey.rb +217 -0
- data/lib/etassia/diagram/sequence.rb +299 -0
- data/lib/etassia/diagram/sequence_box.rb +18 -0
- data/lib/etassia/diagram/sequence_frame.rb +37 -0
- data/lib/etassia/diagram/sequence_frame_section.rb +23 -0
- data/lib/etassia/diagram/sequence_text.rb +69 -0
- data/lib/etassia/diagram/sequence_wrap.rb +23 -0
- data/lib/etassia/diagram/state_diagram.rb +282 -0
- data/lib/etassia/diagram/timeline.rb +183 -0
- data/lib/etassia/diagram/treemap.rb +95 -0
- data/lib/etassia/diagram/user_journey.rb +153 -0
- data/lib/etassia/diagram/xy_chart.rb +90 -0
- data/lib/etassia/diagram.rb +8 -0
- data/lib/etassia/diagram_registry.rb +34 -0
- data/lib/etassia/engine.rb +334 -0
- data/lib/etassia/error/diagram_type_error.rb +10 -0
- data/lib/etassia/error/layout_error.rb +12 -0
- data/lib/etassia/error/notation_registration_error.rb +10 -0
- data/lib/etassia/error/parse_error.rb +11 -0
- data/lib/etassia/error/pipeline_error.rb +10 -0
- data/lib/etassia/error/render_error.rb +12 -0
- data/lib/etassia/error/score_error.rb +12 -0
- data/lib/etassia/error.rb +10 -0
- data/lib/etassia/error_report.rb +69 -0
- data/lib/etassia/ir/data.rb +39 -0
- data/lib/etassia/ir/data_value.rb +35 -0
- data/lib/etassia/ir/dimension.rb +10 -0
- data/lib/etassia/ir/edge.rb +34 -0
- data/lib/etassia/ir/graph.rb +28 -0
- data/lib/etassia/ir/integrity.rb +80 -0
- data/lib/etassia/ir/item.rb +46 -0
- data/lib/etassia/ir/model.rb +56 -0
- data/lib/etassia/ir/node.rb +10 -0
- data/lib/etassia/ir/placement.rb +47 -0
- data/lib/etassia/ir/prepositioned.rb +25 -0
- data/lib/etassia/ir/prepositioned_item.rb +26 -0
- data/lib/etassia/ir/property_set.rb +43 -0
- data/lib/etassia/ir/scalar.rb +25 -0
- data/lib/etassia/ir/series.rb +10 -0
- data/lib/etassia/ir.rb +17 -0
- data/lib/etassia/js_math.rb +511 -0
- data/lib/etassia/js_number.rb +64 -0
- data/lib/etassia/layout/architecture.rb +1472 -0
- data/lib/etassia/layout/base.rb +276 -0
- data/lib/etassia/layout/block.rb +738 -0
- data/lib/etassia/layout/c4.rb +876 -0
- data/lib/etassia/layout/c4_boundary_metrics.rb +35 -0
- data/lib/etassia/layout/c4_bounds.rb +106 -0
- data/lib/etassia/layout/c4_intersection.rb +77 -0
- data/lib/etassia/layout/c4_placement.rb +135 -0
- data/lib/etassia/layout/c4_shape_metrics.rb +97 -0
- data/lib/etassia/layout/c4_shape_outline.rb +67 -0
- data/lib/etassia/layout/c4_stereotype.rb +30 -0
- data/lib/etassia/layout/c4_text.rb +54 -0
- data/lib/etassia/layout/class_cell_placement.rb +148 -0
- data/lib/etassia/layout/class_diagram.rb +1116 -0
- data/lib/etassia/layout/class_diagram_namespaces.rb +26 -0
- data/lib/etassia/layout/class_diagram_notes.rb +26 -0
- data/lib/etassia/layout/class_name_advances.rb +31 -0
- data/lib/etassia/layout/class_namespace_box.rb +21 -0
- data/lib/etassia/layout/class_namespace_nodes.rb +197 -0
- data/lib/etassia/layout/class_namespace_placement.rb +71 -0
- data/lib/etassia/layout/class_note.rb +44 -0
- data/lib/etassia/layout/class_note_nodes.rb +84 -0
- data/lib/etassia/layout/elk_notices.rb +48 -0
- data/lib/etassia/layout/elk_placement.rb +197 -0
- data/lib/etassia/layout/er_diagram.rb +1002 -0
- data/lib/etassia/layout/er_diagram_adjacency.rb +20 -0
- data/lib/etassia/layout/er_diagram_alignment.rb +72 -0
- data/lib/etassia/layout/er_diagram_compaction.rb +85 -0
- data/lib/etassia/layout/er_diagram_conflicts.rb +70 -0
- data/lib/etassia/layout/er_diagram_coordinates.rb +104 -0
- data/lib/etassia/layout/er_diagram_entity_size.rb +82 -0
- data/lib/etassia/layout/er_diagram_layering.rb +109 -0
- data/lib/etassia/layout/er_diagram_ordering.rb +143 -0
- data/lib/etassia/layout/er_diagram_placement.rb +163 -0
- data/lib/etassia/layout/er_diagram_placement_node.rb +22 -0
- data/lib/etassia/layout/error.rb +133 -0
- data/lib/etassia/layout/flowchart/brandes_koepf.rb +208 -0
- data/lib/etassia/layout/flowchart/cluster_reach.rb +70 -0
- data/lib/etassia/layout/flowchart/component_packing.rb +129 -0
- data/lib/etassia/layout/flowchart/directed_placement.rb +428 -0
- data/lib/etassia/layout/flowchart/edge_chains.rb +111 -0
- data/lib/etassia/layout/flowchart/edge_order.rb +34 -0
- data/lib/etassia/layout/flowchart/edge_router.rb +533 -0
- data/lib/etassia/layout/flowchart/label_backdrop_geometry.rb +62 -0
- data/lib/etassia/layout/flowchart/layer_spacing.rb +85 -0
- data/lib/etassia/layout/flowchart/level_edges.rb +74 -0
- data/lib/etassia/layout/flowchart/level_frame.rb +47 -0
- data/lib/etassia/layout/flowchart/minimum_rank_spacing.rb +74 -0
- data/lib/etassia/layout/flowchart/row_centering.rb +229 -0
- data/lib/etassia/layout/flowchart.rb +1290 -0
- data/lib/etassia/layout/gantt.rb +814 -0
- data/lib/etassia/layout/gantt_duration.rb +49 -0
- data/lib/etassia/layout/gantt_exclusions.rb +74 -0
- data/lib/etassia/layout/gantt_ticks.rb +165 -0
- data/lib/etassia/layout/git_graph.rb +1075 -0
- data/lib/etassia/layout/grid.rb +165 -0
- data/lib/etassia/layout/info.rb +113 -0
- data/lib/etassia/layout/kanban.rb +452 -0
- data/lib/etassia/layout/kanban_card_text.rb +95 -0
- data/lib/etassia/layout/mindmap.rb +425 -0
- data/lib/etassia/layout/mindmap_cose.rb +81 -0
- data/lib/etassia/layout/mindmap_cose_body.rb +93 -0
- data/lib/etassia/layout/mindmap_cose_geometry.rb +190 -0
- data/lib/etassia/layout/mindmap_cose_grid.rb +96 -0
- data/lib/etassia/layout/mindmap_cose_link.rb +42 -0
- data/lib/etassia/layout/mindmap_cose_relaxation.rb +166 -0
- data/lib/etassia/layout/mindmap_cose_seed.rb +93 -0
- data/lib/etassia/layout/mindmap_cose_wedge.rb +37 -0
- data/lib/etassia/layout/mindmap_node_size.rb +130 -0
- data/lib/etassia/layout/packet.rb +285 -0
- data/lib/etassia/layout/pie.rb +305 -0
- data/lib/etassia/layout/pie_legend.rb +64 -0
- data/lib/etassia/layout/pie_legend_entry.rb +21 -0
- data/lib/etassia/layout/quadrant.rb +402 -0
- data/lib/etassia/layout/radar.rb +442 -0
- data/lib/etassia/layout/requirement.rb +765 -0
- data/lib/etassia/layout/sankey.rb +501 -0
- data/lib/etassia/layout/scene.rb +18 -0
- data/lib/etassia/layout/sequence/actor_gaps.rb +151 -0
- data/lib/etassia/layout/sequence/box_shape.rb +23 -0
- data/lib/etassia/layout/sequence/creations.rb +73 -0
- data/lib/etassia/layout/sequence/frame_divider.rb +22 -0
- data/lib/etassia/layout/sequence/frame_placement.rb +424 -0
- data/lib/etassia/layout/sequence/frame_reader.rb +75 -0
- data/lib/etassia/layout/sequence/frame_shape.rb +45 -0
- data/lib/etassia/layout/sequence/geometry.rb +24 -0
- data/lib/etassia/layout/sequence/message_rows.rb +165 -0
- data/lib/etassia/layout/sequence/note.rb +16 -0
- data/lib/etassia/layout/sequence/note_box.rb +114 -0
- data/lib/etassia/layout/sequence/note_placement.rb +223 -0
- data/lib/etassia/layout/sequence/text_width.rb +69 -0
- data/lib/etassia/layout/sequence/text_wrap.rb +93 -0
- data/lib/etassia/layout/sequence.rb +936 -0
- data/lib/etassia/layout/state_diagram.rb +1277 -0
- data/lib/etassia/layout/timeline.rb +165 -0
- data/lib/etassia/layout/timeline_card.rb +142 -0
- data/lib/etassia/layout/timeline_flow.rb +164 -0
- data/lib/etassia/layout/timeline_line.rb +33 -0
- data/lib/etassia/layout/timeline_rounding.rb +19 -0
- data/lib/etassia/layout/timeline_text.rb +105 -0
- data/lib/etassia/layout/treemap.rb +303 -0
- data/lib/etassia/layout/treemap_placement.rb +52 -0
- data/lib/etassia/layout/treemap_squarify.rb +108 -0
- data/lib/etassia/layout/user_journey.rb +300 -0
- data/lib/etassia/layout/user_journey_face.rb +33 -0
- data/lib/etassia/layout/user_journey_face_geometry.rb +80 -0
- data/lib/etassia/layout/user_journey_geometry.rb +336 -0
- data/lib/etassia/layout/user_journey_legend.rb +84 -0
- data/lib/etassia/layout/xy_chart.rb +620 -0
- data/lib/etassia/layout.rb +19 -0
- data/lib/etassia/lint_debt_scoreboard.rb +219 -0
- data/lib/etassia/markdown_text/emphasis_simulator.rb +373 -0
- data/lib/etassia/markdown_text.rb +393 -0
- data/lib/etassia/notation/builtin.rb +39 -0
- data/lib/etassia/notation/entry.rb +15 -0
- data/lib/etassia/notation/mermaid/class_diagram_config.rb +42 -0
- data/lib/etassia/notation/mermaid/git_graph_config.rb +46 -0
- data/lib/etassia/notation/mermaid/ir_adapter.rb +27 -0
- data/lib/etassia/notation/mermaid/ir_adapters/architecture.rb +196 -0
- data/lib/etassia/notation/mermaid/ir_adapters/block.rb +138 -0
- data/lib/etassia/notation/mermaid/ir_adapters/c4.rb +258 -0
- data/lib/etassia/notation/mermaid/ir_adapters/class_diagram.rb +257 -0
- data/lib/etassia/notation/mermaid/ir_adapters/er_diagram.rb +220 -0
- data/lib/etassia/notation/mermaid/ir_adapters/error.rb +32 -0
- data/lib/etassia/notation/mermaid/ir_adapters/flowchart.rb +208 -0
- data/lib/etassia/notation/mermaid/ir_adapters/gantt.rb +236 -0
- data/lib/etassia/notation/mermaid/ir_adapters/git_graph.rb +186 -0
- data/lib/etassia/notation/mermaid/ir_adapters/info.rb +34 -0
- data/lib/etassia/notation/mermaid/ir_adapters/kanban.rb +110 -0
- data/lib/etassia/notation/mermaid/ir_adapters/mindmap.rb +76 -0
- data/lib/etassia/notation/mermaid/ir_adapters/packet.rb +51 -0
- data/lib/etassia/notation/mermaid/ir_adapters/pie.rb +71 -0
- data/lib/etassia/notation/mermaid/ir_adapters/quadrant.rb +116 -0
- data/lib/etassia/notation/mermaid/ir_adapters/radar.rb +142 -0
- data/lib/etassia/notation/mermaid/ir_adapters/requirement.rb +237 -0
- data/lib/etassia/notation/mermaid/ir_adapters/sankey.rb +74 -0
- data/lib/etassia/notation/mermaid/ir_adapters/sequence.rb +304 -0
- data/lib/etassia/notation/mermaid/ir_adapters/state_diagram.rb +225 -0
- data/lib/etassia/notation/mermaid/ir_adapters/timeline.rb +93 -0
- data/lib/etassia/notation/mermaid/ir_adapters/treemap.rb +143 -0
- data/lib/etassia/notation/mermaid/ir_adapters/user_journey.rb +127 -0
- data/lib/etassia/notation/mermaid/ir_adapters/xychart.rb +131 -0
- data/lib/etassia/notation/mermaid.rb +399 -0
- data/lib/etassia/notation/parsed.rb +31 -0
- data/lib/etassia/notation/plantuml/activity/arrow_head.rb +45 -0
- data/lib/etassia/notation/plantuml/activity/arrow_style.rb +53 -0
- data/lib/etassia/notation/plantuml/activity/bar_columns.rb +75 -0
- data/lib/etassia/notation/plantuml/activity/box.rb +60 -0
- data/lib/etassia/notation/plantuml/activity/builder.rb +77 -0
- data/lib/etassia/notation/plantuml/activity/canvas.rb +117 -0
- data/lib/etassia/notation/plantuml/activity/column_centres.rb +151 -0
- data/lib/etassia/notation/plantuml/activity/columns.rb +224 -0
- data/lib/etassia/notation/plantuml/activity/diagram.rb +35 -0
- data/lib/etassia/notation/plantuml/activity/edge.rb +35 -0
- data/lib/etassia/notation/plantuml/activity/edge_marks.rb +68 -0
- data/lib/etassia/notation/plantuml/activity/exits.rb +61 -0
- data/lib/etassia/notation/plantuml/activity/frame_marks.rb +116 -0
- data/lib/etassia/notation/plantuml/activity/lane_steps.rb +82 -0
- data/lib/etassia/notation/plantuml/activity/lane_titles.rb +46 -0
- data/lib/etassia/notation/plantuml/activity/layout.rb +50 -0
- data/lib/etassia/notation/plantuml/activity/legacy_parser.rb +181 -0
- data/lib/etassia/notation/plantuml/activity/legacy_row_gaps.rb +65 -0
- data/lib/etassia/notation/plantuml/activity/mark.rb +23 -0
- data/lib/etassia/notation/plantuml/activity/marks.rb +62 -0
- data/lib/etassia/notation/plantuml/activity/metrics.rb +169 -0
- data/lib/etassia/notation/plantuml/activity/new_parser/blocks.rb +166 -0
- data/lib/etassia/notation/plantuml/activity/new_parser.rb +177 -0
- data/lib/etassia/notation/plantuml/activity/node.rb +50 -0
- data/lib/etassia/notation/plantuml/activity/node_marks.rb +174 -0
- data/lib/etassia/notation/plantuml/activity/note.rb +27 -0
- data/lib/etassia/notation/plantuml/activity/parser.rb +51 -0
- data/lib/etassia/notation/plantuml/activity/placement.rb +327 -0
- data/lib/etassia/notation/plantuml/activity/ranking.rb +142 -0
- data/lib/etassia/notation/plantuml/activity/reach.rb +58 -0
- data/lib/etassia/notation/plantuml/activity/renderer.rb +220 -0
- data/lib/etassia/notation/plantuml/activity/route.rb +22 -0
- data/lib/etassia/notation/plantuml/activity/router.rb +308 -0
- data/lib/etassia/notation/plantuml/activity/row_gaps.rb +105 -0
- data/lib/etassia/notation/plantuml/activity/row_spread.rb +59 -0
- data/lib/etassia/notation/plantuml/activity/scene.rb +20 -0
- data/lib/etassia/notation/plantuml/activity/text.rb +36 -0
- data/lib/etassia/notation/plantuml/activity.rb +50 -0
- data/lib/etassia/notation/plantuml/arrow.rb +135 -0
- data/lib/etassia/notation/plantuml/caption.rb +50 -0
- data/lib/etassia/notation/plantuml/caption_layout.rb +97 -0
- data/lib/etassia/notation/plantuml/caption_rows.rb +67 -0
- data/lib/etassia/notation/plantuml/class_header.rb +178 -0
- data/lib/etassia/notation/plantuml/class_name.rb +51 -0
- data/lib/etassia/notation/plantuml/component.rb +37 -0
- data/lib/etassia/notation/plantuml/creole.rb +278 -0
- data/lib/etassia/notation/plantuml/creole_icons.rb +33 -0
- data/lib/etassia/notation/plantuml/diagram.rb +60 -0
- data/lib/etassia/notation/plantuml/diagram_builder.rb +442 -0
- data/lib/etassia/notation/plantuml/diagram_name.rb +51 -0
- data/lib/etassia/notation/plantuml/directives.rb +33 -0
- data/lib/etassia/notation/plantuml/drawing/box.rb +28 -0
- data/lib/etassia/notation/plantuml/drawing/face.rb +39 -0
- data/lib/etassia/notation/plantuml/drawing/pen.rb +105 -0
- data/lib/etassia/notation/plantuml/drawing/renderer.rb +36 -0
- data/lib/etassia/notation/plantuml/drawing/scene.rb +28 -0
- data/lib/etassia/notation/plantuml/drawing.rb +19 -0
- data/lib/etassia/notation/plantuml/ebnf/blocks.rb +272 -0
- data/lib/etassia/notation/plantuml/ebnf/layout.rb +117 -0
- data/lib/etassia/notation/plantuml/ebnf/model.rb +22 -0
- data/lib/etassia/notation/plantuml/ebnf/reader.rb +131 -0
- data/lib/etassia/notation/plantuml/ebnf.rb +34 -0
- data/lib/etassia/notation/plantuml/end_texts.rb +78 -0
- data/lib/etassia/notation/plantuml/entity.rb +54 -0
- data/lib/etassia/notation/plantuml/further.rb +38 -0
- data/lib/etassia/notation/plantuml/gantt/layout.rb +269 -0
- data/lib/etassia/notation/plantuml/gantt/reader.rb +210 -0
- data/lib/etassia/notation/plantuml/gantt/renderer.rb +81 -0
- data/lib/etassia/notation/plantuml/gantt.rb +34 -0
- data/lib/etassia/notation/plantuml/include/blocks.rb +66 -0
- data/lib/etassia/notation/plantuml/include/finder.rb +61 -0
- data/lib/etassia/notation/plantuml/include.rb +78 -0
- data/lib/etassia/notation/plantuml/ir_adapter/annotations.rb +40 -0
- data/lib/etassia/notation/plantuml/ir_adapter/links.rb +91 -0
- data/lib/etassia/notation/plantuml/ir_adapter/sink.rb +49 -0
- data/lib/etassia/notation/plantuml/ir_adapter/structure.rb +86 -0
- data/lib/etassia/notation/plantuml/ir_adapter.rb +32 -0
- data/lib/etassia/notation/plantuml/ir_reader/annotations.rb +51 -0
- data/lib/etassia/notation/plantuml/ir_reader/index.rb +49 -0
- data/lib/etassia/notation/plantuml/ir_reader/links.rb +133 -0
- data/lib/etassia/notation/plantuml/ir_reader/structure.rb +83 -0
- data/lib/etassia/notation/plantuml/ir_reader.rb +42 -0
- data/lib/etassia/notation/plantuml/junction.rb +20 -0
- data/lib/etassia/notation/plantuml/klass.rb +41 -0
- data/lib/etassia/notation/plantuml/label_clearance.rb +67 -0
- data/lib/etassia/notation/plantuml/layout.rb +2806 -0
- data/lib/etassia/notation/plantuml/member.rb +37 -0
- data/lib/etassia/notation/plantuml/member_icon.rb +87 -0
- data/lib/etassia/notation/plantuml/member_icon_elements.rb +91 -0
- data/lib/etassia/notation/plantuml/member_pitch.rb +76 -0
- data/lib/etassia/notation/plantuml/member_rule.rb +48 -0
- data/lib/etassia/notation/plantuml/network/grid.rb +170 -0
- data/lib/etassia/notation/plantuml/network/layout.rb +158 -0
- data/lib/etassia/notation/plantuml/network/model.rb +22 -0
- data/lib/etassia/notation/plantuml/network/placement.rb +64 -0
- data/lib/etassia/notation/plantuml/network/reader.rb +126 -0
- data/lib/etassia/notation/plantuml/network/shapes.rb +109 -0
- data/lib/etassia/notation/plantuml/network.rb +37 -0
- data/lib/etassia/notation/plantuml/node_graph/archimate.rb +49 -0
- data/lib/etassia/notation/plantuml/node_graph/box_reader.rb +86 -0
- data/lib/etassia/notation/plantuml/node_graph/cloud.rb +73 -0
- data/lib/etassia/notation/plantuml/node_graph/crows_foot.rb +85 -0
- data/lib/etassia/notation/plantuml/node_graph/curve.rb +66 -0
- data/lib/etassia/notation/plantuml/node_graph/data_reader.rb +77 -0
- data/lib/etassia/notation/plantuml/node_graph/data_shape.rb +39 -0
- data/lib/etassia/notation/plantuml/node_graph/detour.rb +98 -0
- data/lib/etassia/notation/plantuml/node_graph/edge.rb +26 -0
- data/lib/etassia/notation/plantuml/node_graph/entity_metrics.rb +49 -0
- data/lib/etassia/notation/plantuml/node_graph/entity_reader.rb +65 -0
- data/lib/etassia/notation/plantuml/node_graph/entity_shape.rb +111 -0
- data/lib/etassia/notation/plantuml/node_graph/figures.rb +92 -0
- data/lib/etassia/notation/plantuml/node_graph/frame_ports.rb +73 -0
- data/lib/etassia/notation/plantuml/node_graph/graph.rb +40 -0
- data/lib/etassia/notation/plantuml/node_graph/heads.rb +89 -0
- data/lib/etassia/notation/plantuml/node_graph/label_fan.rb +76 -0
- data/lib/etassia/notation/plantuml/node_graph/label_placer.rb +310 -0
- data/lib/etassia/notation/plantuml/node_graph/label_waypoint.rb +47 -0
- data/lib/etassia/notation/plantuml/node_graph/layout.rb +293 -0
- data/lib/etassia/notation/plantuml/node_graph/link.rb +78 -0
- data/lib/etassia/notation/plantuml/node_graph/macros.rb +39 -0
- data/lib/etassia/notation/plantuml/node_graph/metrics.rb +113 -0
- data/lib/etassia/notation/plantuml/node_graph/node.rb +44 -0
- data/lib/etassia/notation/plantuml/node_graph/note_tail.rb +58 -0
- data/lib/etassia/notation/plantuml/node_graph/packer.rb +126 -0
- data/lib/etassia/notation/plantuml/node_graph/parser.rb +309 -0
- data/lib/etassia/notation/plantuml/node_graph/paths.rb +48 -0
- data/lib/etassia/notation/plantuml/node_graph/ranking.rb +231 -0
- data/lib/etassia/notation/plantuml/node_graph/reader.rb +53 -0
- data/lib/etassia/notation/plantuml/node_graph/references.rb +38 -0
- data/lib/etassia/notation/plantuml/node_graph/renderer.rb +160 -0
- data/lib/etassia/notation/plantuml/node_graph/scene.rb +22 -0
- data/lib/etassia/notation/plantuml/node_graph/shapes.rb +302 -0
- data/lib/etassia/notation/plantuml/node_graph/skipped_ranks.rb +61 -0
- data/lib/etassia/notation/plantuml/node_graph/tab.rb +68 -0
- data/lib/etassia/notation/plantuml/node_graph/usecase_ellipse.rb +100 -0
- data/lib/etassia/notation/plantuml/node_graph.rb +38 -0
- data/lib/etassia/notation/plantuml/note.rb +27 -0
- data/lib/etassia/notation/plantuml/note_layout.rb +257 -0
- data/lib/etassia/notation/plantuml/note_outline.rb +68 -0
- data/lib/etassia/notation/plantuml/objects/map_rows.rb +46 -0
- data/lib/etassia/notation/plantuml/objects/reader.rb +208 -0
- data/lib/etassia/notation/plantuml/objects.rb +39 -0
- data/lib/etassia/notation/plantuml/package.rb +45 -0
- data/lib/etassia/notation/plantuml/package_color.rb +32 -0
- data/lib/etassia/notation/plantuml/package_frames.rb +178 -0
- data/lib/etassia/notation/plantuml/parser.rb +622 -0
- data/lib/etassia/notation/plantuml/portion_visibility.rb +91 -0
- data/lib/etassia/notation/plantuml/qualified_association_layout.rb +332 -0
- data/lib/etassia/notation/plantuml/qualifier_box.rb +78 -0
- data/lib/etassia/notation/plantuml/rank_chain.rb +527 -0
- data/lib/etassia/notation/plantuml/rank_hierarchy.rb +347 -0
- data/lib/etassia/notation/plantuml/relation.rb +103 -0
- data/lib/etassia/notation/plantuml/relation_label_separator.rb +199 -0
- data/lib/etassia/notation/plantuml/relation_path_points.rb +84 -0
- data/lib/etassia/notation/plantuml/renderer.rb +490 -0
- data/lib/etassia/notation/plantuml/scene.rb +134 -0
- data/lib/etassia/notation/plantuml/segment_box.rb +85 -0
- data/lib/etassia/notation/plantuml/sequence/activation.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/appearance.rb +71 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_end.rb +23 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_marks.rb +111 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_style.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/arrow_syntax.rb +122 -0
- data/lib/etassia/notation/plantuml/sequence/bar_tracker.rb +59 -0
- data/lib/etassia/notation/plantuml/sequence/box.rb +23 -0
- data/lib/etassia/notation/plantuml/sequence/chrome.rb +60 -0
- data/lib/etassia/notation/plantuml/sequence/chrome_rows.rb +184 -0
- data/lib/etassia/notation/plantuml/sequence/create.rb +34 -0
- data/lib/etassia/notation/plantuml/sequence/delay.rb +19 -0
- data/lib/etassia/notation/plantuml/sequence/destroy.rb +20 -0
- data/lib/etassia/notation/plantuml/sequence/diagram.rb +86 -0
- data/lib/etassia/notation/plantuml/sequence/divider.rb +19 -0
- data/lib/etassia/notation/plantuml/sequence/edge.rb +53 -0
- data/lib/etassia/notation/plantuml/sequence/embedded.rb +77 -0
- data/lib/etassia/notation/plantuml/sequence/fill.rb +56 -0
- data/lib/etassia/notation/plantuml/sequence/fragment.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/fragment_shape.rb +138 -0
- data/lib/etassia/notation/plantuml/sequence/head_style.rb +43 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/blocks.rb +73 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/fills.rb +24 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/items.rb +48 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/messages.rb +62 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/participants.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter/settings.rb +54 -0
- data/lib/etassia/notation/plantuml/sequence/ir_adapter.rb +38 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/blocks.rb +77 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/fills.rb +27 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/index.rb +36 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/items.rb +35 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/messages.rb +70 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/participants.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader/settings.rb +74 -0
- data/lib/etassia/notation/plantuml/sequence/ir_reader.rb +38 -0
- data/lib/etassia/notation/plantuml/sequence/keyword_defaults.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/layout.rb +1567 -0
- data/lib/etassia/notation/plantuml/sequence/message.rb +97 -0
- data/lib/etassia/notation/plantuml/sequence/message_wrap.rb +77 -0
- data/lib/etassia/notation/plantuml/sequence/note.rb +61 -0
- data/lib/etassia/notation/plantuml/sequence/note_fill.rb +35 -0
- data/lib/etassia/notation/plantuml/sequence/note_geometry.rb +126 -0
- data/lib/etassia/notation/plantuml/sequence/note_shape.rb +51 -0
- data/lib/etassia/notation/plantuml/sequence/numbered_label.rb +57 -0
- data/lib/etassia/notation/plantuml/sequence/numbering.rb +49 -0
- data/lib/etassia/notation/plantuml/sequence/outline.rb +204 -0
- data/lib/etassia/notation/plantuml/sequence/page_break.rb +17 -0
- data/lib/etassia/notation/plantuml/sequence/paint.rb +79 -0
- data/lib/etassia/notation/plantuml/sequence/parallel_message.rb +19 -0
- data/lib/etassia/notation/plantuml/sequence/parser.rb +844 -0
- data/lib/etassia/notation/plantuml/sequence/participant.rb +27 -0
- data/lib/etassia/notation/plantuml/sequence/picture.rb +29 -0
- data/lib/etassia/notation/plantuml/sequence/ref.rb +24 -0
- data/lib/etassia/notation/plantuml/sequence/ref_shape.rb +74 -0
- data/lib/etassia/notation/plantuml/sequence/refusals.rb +47 -0
- data/lib/etassia/notation/plantuml/sequence/renderer.rb +501 -0
- data/lib/etassia/notation/plantuml/sequence/scene.rb +200 -0
- data/lib/etassia/notation/plantuml/sequence/skin.rb +76 -0
- data/lib/etassia/notation/plantuml/sequence/spacing.rb +28 -0
- data/lib/etassia/notation/plantuml/sequence/style.rb +151 -0
- data/lib/etassia/notation/plantuml/sequence/tab_size.rb +42 -0
- data/lib/etassia/notation/plantuml/sequence/walker.rb +1190 -0
- data/lib/etassia/notation/plantuml/sequence.rb +47 -0
- data/lib/etassia/notation/plantuml/source_lines.rb +33 -0
- data/lib/etassia/notation/plantuml/state/axis_solver.rb +272 -0
- data/lib/etassia/notation/plantuml/state/cluster_padding.rb +75 -0
- data/lib/etassia/notation/plantuml/state/curve.rb +73 -0
- data/lib/etassia/notation/plantuml/state/dot_axis.rb +248 -0
- data/lib/etassia/notation/plantuml/state/extent.rb +42 -0
- data/lib/etassia/notation/plantuml/state/hierarchy.rb +355 -0
- data/lib/etassia/notation/plantuml/state/label_clearance.rb +148 -0
- data/lib/etassia/notation/plantuml/state/label_reach.rb +139 -0
- data/lib/etassia/notation/plantuml/state/layout.rb +173 -0
- data/lib/etassia/notation/plantuml/state/level_edges.rb +113 -0
- data/lib/etassia/notation/plantuml/state/look.rb +36 -0
- data/lib/etassia/notation/plantuml/state/note_shape.rb +73 -0
- data/lib/etassia/notation/plantuml/state/plane.rb +85 -0
- data/lib/etassia/notation/plantuml/state/ranking.rb +181 -0
- data/lib/etassia/notation/plantuml/state/reader.rb +310 -0
- data/lib/etassia/notation/plantuml/state/renderer.rb +253 -0
- data/lib/etassia/notation/plantuml/state/route_detour.rb +115 -0
- data/lib/etassia/notation/plantuml/state/route_geometry.rb +186 -0
- data/lib/etassia/notation/plantuml/state/routes.rb +196 -0
- data/lib/etassia/notation/plantuml/state/row.rb +88 -0
- data/lib/etassia/notation/plantuml/state/rows.rb +50 -0
- data/lib/etassia/notation/plantuml/state/stretch.rb +71 -0
- data/lib/etassia/notation/plantuml/state.rb +62 -0
- data/lib/etassia/notation/plantuml/stereotype_head.rb +58 -0
- data/lib/etassia/notation/plantuml/style/bound.rb +34 -0
- data/lib/etassia/notation/plantuml/style/colour.rb +41 -0
- data/lib/etassia/notation/plantuml/style/colour_names.rb +89 -0
- data/lib/etassia/notation/plantuml/style/defaults.rb +33 -0
- data/lib/etassia/notation/plantuml/style/inline.rb +56 -0
- data/lib/etassia/notation/plantuml/style/reader.rb +242 -0
- data/lib/etassia/notation/plantuml/style/sheet.rb +103 -0
- data/lib/etassia/notation/plantuml/style.rb +32 -0
- data/lib/etassia/notation/plantuml/style_reader.rb +160 -0
- data/lib/etassia/notation/plantuml/style_sheet.rb +27 -0
- data/lib/etassia/notation/plantuml/styled_relation_curve.rb +71 -0
- data/lib/etassia/notation/plantuml/timing/arrows.rb +81 -0
- data/lib/etassia/notation/plantuml/timing/axis.rb +100 -0
- data/lib/etassia/notation/plantuml/timing/layout.rb +172 -0
- data/lib/etassia/notation/plantuml/timing/model.rb +34 -0
- data/lib/etassia/notation/plantuml/timing/reader.rb +173 -0
- data/lib/etassia/notation/plantuml/timing/signals.rb +328 -0
- data/lib/etassia/notation/plantuml/timing.rb +38 -0
- data/lib/etassia/notation/plantuml/tree/layout.rb +276 -0
- data/lib/etassia/notation/plantuml/tree/mindmap_layout.rb +157 -0
- data/lib/etassia/notation/plantuml/tree/reader.rb +186 -0
- data/lib/etassia/notation/plantuml/tree/renderer.rb +67 -0
- data/lib/etassia/notation/plantuml/tree/role.rb +57 -0
- data/lib/etassia/notation/plantuml/tree/rules.rb +156 -0
- data/lib/etassia/notation/plantuml/tree/wbs_layout.rb +164 -0
- data/lib/etassia/notation/plantuml/tree.rb +41 -0
- data/lib/etassia/notation/plantuml/unsupported_construct_error.rb +39 -0
- data/lib/etassia/notation/plantuml/unsupported_constructs.rb +103 -0
- data/lib/etassia/notation/plantuml/usecase.rb +36 -0
- data/lib/etassia/notation/plantuml.rb +132 -0
- data/lib/etassia/notation/plantuml_data/boxes/frames.rb +101 -0
- data/lib/etassia/notation/plantuml_data/boxes/graph_layout.rb +348 -0
- data/lib/etassia/notation/plantuml_data/boxes/heads.rb +65 -0
- data/lib/etassia/notation/plantuml_data/boxes/highlights.rb +70 -0
- data/lib/etassia/notation/plantuml_data/boxes/inline_rows.rb +99 -0
- data/lib/etassia/notation/plantuml_data/boxes/json_reader.rb +24 -0
- data/lib/etassia/notation/plantuml_data/boxes/link_text.rb +94 -0
- data/lib/etassia/notation/plantuml_data/boxes/marks.rb +76 -0
- data/lib/etassia/notation/plantuml_data/boxes/ornaments.rb +130 -0
- data/lib/etassia/notation/plantuml_data/boxes/renderer.rb +95 -0
- data/lib/etassia/notation/plantuml_data/boxes/row_alignment.rb +58 -0
- data/lib/etassia/notation/plantuml_data/boxes/row_bend.rb +43 -0
- data/lib/etassia/notation/plantuml_data/boxes/scene.rb +27 -0
- data/lib/etassia/notation/plantuml_data/boxes/table.rb +56 -0
- data/lib/etassia/notation/plantuml_data/boxes/table_box.rb +355 -0
- data/lib/etassia/notation/plantuml_data/boxes/text.rb +101 -0
- data/lib/etassia/notation/plantuml_data/boxes/tree_builder.rb +82 -0
- data/lib/etassia/notation/plantuml_data/boxes/tree_layout.rb +82 -0
- data/lib/etassia/notation/plantuml_data/boxes/yaml_reader.rb +105 -0
- data/lib/etassia/notation/plantuml_data/openiconic.LICENSE +6 -0
- data/lib/etassia/notation/plantuml_data/openiconic.json +1 -0
- data/lib/etassia/notation/plantuml_data.rb +84 -0
- data/lib/etassia/notation/plantuml_salt/block.rb +80 -0
- data/lib/etassia/notation/plantuml_salt/box.rb +30 -0
- data/lib/etassia/notation/plantuml_salt/font_metrics.rb +28 -0
- data/lib/etassia/notation/plantuml_salt/grid_marks.rb +66 -0
- data/lib/etassia/notation/plantuml_salt/group_marks.rb +77 -0
- data/lib/etassia/notation/plantuml_salt/layout.rb +206 -0
- data/lib/etassia/notation/plantuml_salt/mark.rb +36 -0
- data/lib/etassia/notation/plantuml_salt/markup.rb +57 -0
- data/lib/etassia/notation/plantuml_salt/parser.rb +239 -0
- data/lib/etassia/notation/plantuml_salt/renderer.rb +138 -0
- data/lib/etassia/notation/plantuml_salt/row.rb +19 -0
- data/lib/etassia/notation/plantuml_salt/run.rb +34 -0
- data/lib/etassia/notation/plantuml_salt/scene.rb +23 -0
- data/lib/etassia/notation/plantuml_salt/scroll_marks.rb +94 -0
- data/lib/etassia/notation/plantuml_salt/tab_marks.rb +74 -0
- data/lib/etassia/notation/plantuml_salt/tree_marks.rb +127 -0
- data/lib/etassia/notation/plantuml_salt/widget.rb +40 -0
- data/lib/etassia/notation/plantuml_salt/widget_marks.rb +319 -0
- data/lib/etassia/notation/plantuml_salt.rb +66 -0
- data/lib/etassia/notation/plugin_failure.rb +42 -0
- data/lib/etassia/notation.rb +289 -0
- data/lib/etassia/parser/architecture.rb +25 -0
- data/lib/etassia/parser/atoms/delimited_run.rb +82 -0
- data/lib/etassia/parser/atoms/greedy_run.rb +116 -0
- data/lib/etassia/parser/atoms/joined.rb +47 -0
- data/lib/etassia/parser/atoms/trimmed_run.rb +47 -0
- data/lib/etassia/parser/base.rb +258 -0
- data/lib/etassia/parser/block.rb +32 -0
- data/lib/etassia/parser/builders/architecture.rb +135 -0
- data/lib/etassia/parser/builders/block.rb +288 -0
- data/lib/etassia/parser/builders/c4.rb +275 -0
- data/lib/etassia/parser/builders/capture_string.rb +17 -0
- data/lib/etassia/parser/builders/class_diagram.rb +539 -0
- data/lib/etassia/parser/builders/er_diagram.rb +308 -0
- data/lib/etassia/parser/builders/error.rb +51 -0
- data/lib/etassia/parser/builders/flowchart.rb +1150 -0
- data/lib/etassia/parser/builders/gantt.rb +267 -0
- data/lib/etassia/parser/builders/git_graph.rb +301 -0
- data/lib/etassia/parser/builders/info.rb +57 -0
- data/lib/etassia/parser/builders/kanban.rb +411 -0
- data/lib/etassia/parser/builders/mindmap.rb +271 -0
- data/lib/etassia/parser/builders/packet.rb +85 -0
- data/lib/etassia/parser/builders/pie.rb +105 -0
- data/lib/etassia/parser/builders/quadrant.rb +165 -0
- data/lib/etassia/parser/builders/radar.rb +157 -0
- data/lib/etassia/parser/builders/requirement.rb +230 -0
- data/lib/etassia/parser/builders/sankey.rb +142 -0
- data/lib/etassia/parser/builders/sequence.rb +431 -0
- data/lib/etassia/parser/builders/sequence_blocks.rb +117 -0
- data/lib/etassia/parser/builders/sequence_box_title.rb +57 -0
- data/lib/etassia/parser/builders/state_diagram.rb +364 -0
- data/lib/etassia/parser/builders/timeline.rb +133 -0
- data/lib/etassia/parser/builders/treemap.rb +138 -0
- data/lib/etassia/parser/builders/xy_chart.rb +148 -0
- data/lib/etassia/parser/c4.rb +37 -0
- data/lib/etassia/parser/class_diagram.rb +58 -0
- data/lib/etassia/parser/class_namespaces.rb +62 -0
- data/lib/etassia/parser/class_notes.rb +54 -0
- data/lib/etassia/parser/er_diagram.rb +28 -0
- data/lib/etassia/parser/error.rb +30 -0
- data/lib/etassia/parser/flowchart.rb +87 -0
- data/lib/etassia/parser/gantt.rb +43 -0
- data/lib/etassia/parser/git_graph.rb +106 -0
- data/lib/etassia/parser/grammars/architecture.rb +165 -0
- data/lib/etassia/parser/grammars/block.rb +190 -0
- data/lib/etassia/parser/grammars/c4.rb +229 -0
- data/lib/etassia/parser/grammars/class_diagram.rb +606 -0
- data/lib/etassia/parser/grammars/common.rb +107 -0
- data/lib/etassia/parser/grammars/er_diagram.rb +232 -0
- data/lib/etassia/parser/grammars/error.rb +32 -0
- data/lib/etassia/parser/grammars/flowchart.rb +1722 -0
- data/lib/etassia/parser/grammars/gantt.rb +198 -0
- data/lib/etassia/parser/grammars/git_graph.rb +234 -0
- data/lib/etassia/parser/grammars/info.rb +53 -0
- data/lib/etassia/parser/grammars/kanban.rb +417 -0
- data/lib/etassia/parser/grammars/mermaid_unicode_text.rb +108 -0
- data/lib/etassia/parser/grammars/mindmap.rb +220 -0
- data/lib/etassia/parser/grammars/packet.rb +71 -0
- data/lib/etassia/parser/grammars/pie.rb +128 -0
- data/lib/etassia/parser/grammars/quadrant.rb +202 -0
- data/lib/etassia/parser/grammars/radar.rb +158 -0
- data/lib/etassia/parser/grammars/requirement.rb +258 -0
- data/lib/etassia/parser/grammars/sankey.rb +104 -0
- data/lib/etassia/parser/grammars/sequence.rb +940 -0
- data/lib/etassia/parser/grammars/state_diagram.rb +382 -0
- data/lib/etassia/parser/grammars/timeline.rb +153 -0
- data/lib/etassia/parser/grammars/treemap.rb +122 -0
- data/lib/etassia/parser/grammars/xy_chart.rb +119 -0
- data/lib/etassia/parser/info.rb +32 -0
- data/lib/etassia/parser/kanban.rb +131 -0
- data/lib/etassia/parser/mermaid_shapes.rb +106 -0
- data/lib/etassia/parser/metadata_yaml.rb +452 -0
- data/lib/etassia/parser/mindmap.rb +92 -0
- data/lib/etassia/parser/native/builders/architecture.rb +103 -0
- data/lib/etassia/parser/native/builders/block.rb +68 -0
- data/lib/etassia/parser/native/builders/c4.rb +16 -0
- data/lib/etassia/parser/native/builders/class_diagram.rb +63 -0
- data/lib/etassia/parser/native/builders/er_diagram.rb +47 -0
- data/lib/etassia/parser/native/builders/flowchart.rb +58 -0
- data/lib/etassia/parser/native/builders/gantt.rb +35 -0
- data/lib/etassia/parser/native/builders/gitgraph.rb +35 -0
- data/lib/etassia/parser/native/builders/info.rb +30 -0
- data/lib/etassia/parser/native/builders/kanban.rb +37 -0
- data/lib/etassia/parser/native/builders/mindmap.rb +26 -0
- data/lib/etassia/parser/native/builders/packet.rb +63 -0
- data/lib/etassia/parser/native/builders/pie.rb +82 -0
- data/lib/etassia/parser/native/builders/quadrant.rb +27 -0
- data/lib/etassia/parser/native/builders/radar.rb +84 -0
- data/lib/etassia/parser/native/builders/requirement.rb +25 -0
- data/lib/etassia/parser/native/builders/sankey.rb +18 -0
- data/lib/etassia/parser/native/builders/sequence.rb +48 -0
- data/lib/etassia/parser/native/builders/state_diagram.rb +61 -0
- data/lib/etassia/parser/native/builders/timeline.rb +46 -0
- data/lib/etassia/parser/native/builders/treemap.rb +60 -0
- data/lib/etassia/parser/native/builders/user_journey.rb +83 -0
- data/lib/etassia/parser/native/builders/xy_chart.rb +94 -0
- data/lib/etassia/parser/native/declined.rb +12 -0
- data/lib/etassia/parser/native/mermaid.json +1 -0
- data/lib/etassia/parser/native/text.rb +31 -0
- data/lib/etassia/parser/native.rb +99 -0
- data/lib/etassia/parser/packet.rb +56 -0
- data/lib/etassia/parser/pie.rb +32 -0
- data/lib/etassia/parser/quadrant.rb +77 -0
- data/lib/etassia/parser/radar.rb +99 -0
- data/lib/etassia/parser/requirement.rb +32 -0
- data/lib/etassia/parser/sankey.rb +47 -0
- data/lib/etassia/parser/sequence.rb +34 -0
- data/lib/etassia/parser/state_diagram.rb +29 -0
- data/lib/etassia/parser/timeline.rb +40 -0
- data/lib/etassia/parser/treemap.rb +25 -0
- data/lib/etassia/parser/user_journey.rb +253 -0
- data/lib/etassia/parser/xy_chart.rb +98 -0
- data/lib/etassia/parser.rb +18 -0
- data/lib/etassia/renderer/architecture.rb +232 -0
- data/lib/etassia/renderer/architecture_edge_router.rb +379 -0
- data/lib/etassia/renderer/base.rb +295 -0
- data/lib/etassia/renderer/block.rb +157 -0
- data/lib/etassia/renderer/c4.rb +294 -0
- data/lib/etassia/renderer/class_diagram.rb +671 -0
- data/lib/etassia/renderer/er_diagram.rb +842 -0
- data/lib/etassia/renderer/error.rb +131 -0
- data/lib/etassia/renderer/flowchart.rb +315 -0
- data/lib/etassia/renderer/gantt.rb +177 -0
- data/lib/etassia/renderer/git_graph.rb +224 -0
- data/lib/etassia/renderer/info.rb +59 -0
- data/lib/etassia/renderer/kanban.rb +157 -0
- data/lib/etassia/renderer/line_break_text.rb +56 -0
- data/lib/etassia/renderer/markdown_text.rb +106 -0
- data/lib/etassia/renderer/mindmap.rb +290 -0
- data/lib/etassia/renderer/packet.rb +87 -0
- data/lib/etassia/renderer/pie.rb +113 -0
- data/lib/etassia/renderer/quadrant.rb +189 -0
- data/lib/etassia/renderer/radar.rb +191 -0
- data/lib/etassia/renderer/requirement.rb +209 -0
- data/lib/etassia/renderer/sankey.rb +114 -0
- data/lib/etassia/renderer/sequence/frame_drawing.rb +169 -0
- data/lib/etassia/renderer/sequence/note_drawing.rb +69 -0
- data/lib/etassia/renderer/sequence.rb +490 -0
- data/lib/etassia/renderer/state_diagram.rb +202 -0
- data/lib/etassia/renderer/timeline.rb +134 -0
- data/lib/etassia/renderer/timeline_palette.rb +18 -0
- data/lib/etassia/renderer/treemap/section_total.rb +33 -0
- data/lib/etassia/renderer/treemap.rb +128 -0
- data/lib/etassia/renderer/user_journey.rb +209 -0
- data/lib/etassia/renderer/xy_chart.rb +180 -0
- data/lib/etassia/renderer.rb +22 -0
- data/lib/etassia/runtime.rb +125 -0
- data/lib/etassia/source/frontmatter.rb +501 -0
- data/lib/etassia/source.rb +224 -0
- data/lib/etassia/svg/arrowhead.rb +205 -0
- data/lib/etassia/svg/circle.rb +19 -0
- data/lib/etassia/svg/document.rb +106 -0
- data/lib/etassia/svg/element.rb +209 -0
- data/lib/etassia/svg/ellipse.rb +23 -0
- data/lib/etassia/svg/escaping.rb +149 -0
- data/lib/etassia/svg/group.rb +64 -0
- data/lib/etassia/svg/line.rb +21 -0
- data/lib/etassia/svg/numbers.rb +53 -0
- data/lib/etassia/svg/path.rb +67 -0
- data/lib/etassia/svg/path_geometry.rb +378 -0
- data/lib/etassia/svg/polygon.rb +25 -0
- data/lib/etassia/svg/polyline.rb +28 -0
- data/lib/etassia/svg/rect.rb +34 -0
- data/lib/etassia/svg/style.rb +50 -0
- data/lib/etassia/svg/text.rb +181 -0
- data/lib/etassia/svg/tspan.rb +48 -0
- data/lib/etassia/svg.rb +38 -0
- data/lib/etassia/text_measurement/arial_advances.rb +122 -0
- data/lib/etassia/text_measurement/dejavu_advances.rb +111 -0
- data/lib/etassia/text_measurement/times_advances.rb +64 -0
- data/lib/etassia/text_measurement/trebuchet_advances.rb +53 -0
- data/lib/etassia/text_measurement/trebuchet_kerning.rb +29 -0
- data/lib/etassia/text_measurement.rb +198 -0
- data/lib/etassia/theme/builtin/dark.yml +229 -0
- data/lib/etassia/theme/builtin/default.yml +239 -0
- data/lib/etassia/theme/builtin/high_contrast.yml +231 -0
- data/lib/etassia/theme/builtin/light.yml +229 -0
- data/lib/etassia/theme/color_palette.rb +97 -0
- data/lib/etassia/theme/completion.rb +50 -0
- data/lib/etassia/theme/effect_styles.rb +34 -0
- data/lib/etassia/theme/registry.rb +45 -0
- data/lib/etassia/theme/shape_styles.rb +34 -0
- data/lib/etassia/theme/spacing_config.rb +30 -0
- data/lib/etassia/theme/typography.rb +40 -0
- data/lib/etassia/theme.rb +73 -0
- data/lib/etassia/version.rb +5 -0
- data/lib/etassia.rb +40 -0
- metadata +865 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
4
|
+
require_relative "../js_math"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# Where a path starts and ends, and which way it is travelling there.
|
|
9
|
+
# Only the two ends matter (for drawing an arrowhead), so this walks
|
|
10
|
+
# commands for the current point and never builds the curves.
|
|
11
|
+
#
|
|
12
|
+
# An arc's chord is not its tangent, so it yields NO heading rather
|
|
13
|
+
# than guessing wrong -- don't add arc tangents without the centre
|
|
14
|
+
# parameterisation.
|
|
15
|
+
#
|
|
16
|
+
# An unrecognised byte is skipped and following numbers are read as
|
|
17
|
+
# more arguments for the command in force -- deliberate leniency,
|
|
18
|
+
# reachable only by a caller assigning a hand-built `d` string
|
|
19
|
+
# directly (Path.from_xml no longer exists as a way in).
|
|
20
|
+
class PathGeometry
|
|
21
|
+
# One anchor: a point on the path and the unit direction of travel
|
|
22
|
+
# through it.
|
|
23
|
+
Anchor = Struct.new(:x, :y, :dx, :dy)
|
|
24
|
+
|
|
25
|
+
# Command letter to the number of numbers it consumes. Repeated
|
|
26
|
+
# argument groups are the SVG rule, so `L 1 2 3 4` is two segments.
|
|
27
|
+
ARITY = {
|
|
28
|
+
"m" => 2, "l" => 2, "h" => 1, "v" => 1, "c" => 6,
|
|
29
|
+
"s" => 4, "q" => 4, "t" => 2, "a" => 7, "z" => 0
|
|
30
|
+
}.freeze
|
|
31
|
+
private_constant :ARITY
|
|
32
|
+
|
|
33
|
+
TOKEN = /([MmLlHhVvCcSsQqTtAaZz])|
|
|
34
|
+
([-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?)/x
|
|
35
|
+
private_constant :TOKEN
|
|
36
|
+
|
|
37
|
+
# Arc flags are single digits even when no separator follows, so they
|
|
38
|
+
# cannot use the generic number scan at their two argument positions.
|
|
39
|
+
ARC_FLAG_TOKEN = /([MmLlHhVvCcSsQqTtAaZz])|([01])/
|
|
40
|
+
private_constant :ARC_FLAG_TOKEN
|
|
41
|
+
|
|
42
|
+
# A move followed by more coordinates draws lines: only the first
|
|
43
|
+
# group of `M 1 2 3 4` is a move. Every other command simply repeats.
|
|
44
|
+
AFTER_FIRST = { "M" => "L", "m" => "l" }.freeze
|
|
45
|
+
REFERENCE_BUILDERS = {
|
|
46
|
+
"l" => :line_references,
|
|
47
|
+
"h" => :horizontal_references,
|
|
48
|
+
"v" => :vertical_references,
|
|
49
|
+
"c" => :cubic_references,
|
|
50
|
+
"s" => :smooth_cubic_references,
|
|
51
|
+
"q" => :quadratic_references,
|
|
52
|
+
"t" => :smooth_quadratic_references,
|
|
53
|
+
}.freeze
|
|
54
|
+
private_constant :AFTER_FIRST, :REFERENCE_BUILDERS
|
|
55
|
+
|
|
56
|
+
# @param data [String, nil] the `d` attribute
|
|
57
|
+
def initialize(data)
|
|
58
|
+
@point = [0.0, 0.0]
|
|
59
|
+
@subpath_start = @point
|
|
60
|
+
@origin = nil
|
|
61
|
+
@terminus = nil
|
|
62
|
+
@origin_direction = nil
|
|
63
|
+
@recent_direction = nil
|
|
64
|
+
@quadratic_control = nil
|
|
65
|
+
@cubic_control = nil
|
|
66
|
+
walk(data.to_s)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Anchor, nil] the first point, pointing along the first segment
|
|
70
|
+
def origin
|
|
71
|
+
# `false` means a command that anchors nothing came first, so the
|
|
72
|
+
# segment after it must not be promoted to the start of the path.
|
|
73
|
+
return nil unless @origin
|
|
74
|
+
|
|
75
|
+
start, reference = @origin
|
|
76
|
+
heading(start, start, reference) ||
|
|
77
|
+
(@origin_direction && heading(start, *@origin_direction))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Anchor, nil] the last point, pointing along the last segment
|
|
81
|
+
def terminus
|
|
82
|
+
return nil unless @terminus
|
|
83
|
+
|
|
84
|
+
reference, finish = @terminus
|
|
85
|
+
heading(finish, reference, finish) ||
|
|
86
|
+
(@recent_direction && heading(finish, *@recent_direction))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def walk(data)
|
|
92
|
+
each_command(data) { |letter, args| apply(letter, args) }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Yields one command letter and one full argument group at a time,
|
|
96
|
+
# repeating the letter while arguments remain. A bare `M` with four
|
|
97
|
+
# numbers draws a line after the move, which is the SVG rule and the
|
|
98
|
+
# reason this cannot just split on letters.
|
|
99
|
+
def each_command(data, &)
|
|
100
|
+
letter = nil
|
|
101
|
+
numbers = []
|
|
102
|
+
scanner = StringScanner.new(data)
|
|
103
|
+
while scan_token(scanner, letter, numbers)
|
|
104
|
+
letter, numbers = consume_token(scanner, letter, numbers, &)
|
|
105
|
+
end
|
|
106
|
+
flush(letter, numbers, &)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# An invalid byte sequence makes the scan regex itself raise rather
|
|
110
|
+
# than simply fail to match. Stop as a genuine non-match would instead
|
|
111
|
+
# of letting a foreign document's garbage encoding escape raw.
|
|
112
|
+
def scan_token(scanner, letter, numbers)
|
|
113
|
+
token = arc_flag_position?(letter, numbers) ? ARC_FLAG_TOKEN : TOKEN
|
|
114
|
+
scanner.scan_until(token)
|
|
115
|
+
rescue ArgumentError
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def consume_token(scanner, letter, numbers, &)
|
|
120
|
+
command = scanner[1]
|
|
121
|
+
return append_number(scanner[2], letter, numbers) unless command
|
|
122
|
+
|
|
123
|
+
flush(letter, numbers, &)
|
|
124
|
+
[command, []]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def append_number(number, letter, numbers)
|
|
128
|
+
numbers << number.to_f
|
|
129
|
+
[letter, numbers]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def arc_flag_position?(letter, numbers)
|
|
133
|
+
return false unless letter&.downcase == "a"
|
|
134
|
+
|
|
135
|
+
(numbers.length % ARITY.fetch("a")).between?(3, 4)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# A group with too few numbers is dropped, and the walk carries on with
|
|
139
|
+
# the next command. An arrowhead placed off a half-read command would
|
|
140
|
+
# be worse than none. A conformant renderer is stricter still — it
|
|
141
|
+
# abandons the whole path from the first error — but Etassia never emits
|
|
142
|
+
# malformed data, and reading the rest costs nothing.
|
|
143
|
+
def flush(letter, numbers)
|
|
144
|
+
return if letter.nil?
|
|
145
|
+
|
|
146
|
+
size = ARITY.fetch(letter.downcase)
|
|
147
|
+
return yield(letter, []) if size.zero?
|
|
148
|
+
|
|
149
|
+
numbers.each_slice(size).with_index do |group, index|
|
|
150
|
+
break if group.size < size
|
|
151
|
+
|
|
152
|
+
yield(index.zero? ? letter : AFTER_FIRST.fetch(letter, letter), group)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def apply(letter, args)
|
|
157
|
+
lower = letter.downcase
|
|
158
|
+
args = relative(letter, lower, args)
|
|
159
|
+
clear_unrelated_control(lower)
|
|
160
|
+
return move(args) if lower == "m"
|
|
161
|
+
return close if lower == "z"
|
|
162
|
+
return arc(args) if lower == "a"
|
|
163
|
+
|
|
164
|
+
segment(*references(lower, args))
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Smooth commands may only reflect a control from the same curve
|
|
168
|
+
# family immediately before them; retaining either control through a
|
|
169
|
+
# different command would bend a later shorthand curve unexpectedly.
|
|
170
|
+
def clear_unrelated_control(lower)
|
|
171
|
+
case lower
|
|
172
|
+
when "q", "t" then @cubic_control = nil
|
|
173
|
+
when "c", "s" then @quadratic_control = nil
|
|
174
|
+
else
|
|
175
|
+
@quadratic_control = nil
|
|
176
|
+
@cubic_control = nil
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# SVG gives an arc two degenerate forms, and they are not the same
|
|
181
|
+
# thing. An arc whose endpoints coincide is omitted entirely, so it must
|
|
182
|
+
# not disturb the anchors either: the segment before it is still the end
|
|
183
|
+
# of the path and the segment after it is still the start. Only the
|
|
184
|
+
# zero-radius form becomes a straight line. Handling one and not the
|
|
185
|
+
# other silently dropped the arrowhead off
|
|
186
|
+
# `M 0 0 L 10 0 A 5 5 0 0 1 10 0`.
|
|
187
|
+
#
|
|
188
|
+
# Exact equality, because a relative endpoint of `0 0` is computed as
|
|
189
|
+
# `@point + 0.0` and lands on the current point exactly.
|
|
190
|
+
def arc(args)
|
|
191
|
+
end_point = [args[5], args[6]]
|
|
192
|
+
return if end_point == @point
|
|
193
|
+
return segment(*straight(end_point)) if args[0].zero? || args[1].zero?
|
|
194
|
+
|
|
195
|
+
traverse(end_point)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Moves the current point along a segment that offers no usable
|
|
199
|
+
# tangent. The point has to advance or every command after it lands in
|
|
200
|
+
# the wrong place, but neither end of an arc may anchor an arrowhead.
|
|
201
|
+
#
|
|
202
|
+
# A break in continuity before a pending origin gains a usable direction
|
|
203
|
+
# closes the question rather than letting a later segment supply that
|
|
204
|
+
# direction. An arc always breaks it because the path starts on that
|
|
205
|
+
# unanchorable segment. A later move breaks it only after a zero-length
|
|
206
|
+
# segment has recorded an origin; moves alone leave the question open for
|
|
207
|
+
# the first real segment.
|
|
208
|
+
def traverse(end_point)
|
|
209
|
+
@origin = false if @origin_direction.nil?
|
|
210
|
+
@terminus = nil
|
|
211
|
+
@recent_direction = nil
|
|
212
|
+
@point = end_point
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# The segment a command draws, as [outgoing reference, incoming
|
|
216
|
+
# reference, end point]. A straight segment is its own tangent, so both
|
|
217
|
+
# references are the far end of it; a curve takes the control point
|
|
218
|
+
# nearest each end.
|
|
219
|
+
#
|
|
220
|
+
# Smooth curves reflect the preceding control in absolute space so
|
|
221
|
+
# relative and absolute commands follow the same geometry. An arc gives
|
|
222
|
+
# no references at all — see the note on the class.
|
|
223
|
+
def references(lower, args)
|
|
224
|
+
send(REFERENCE_BUILDERS.fetch(lower), args)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def line_references(args)
|
|
228
|
+
straight(args.values_at(0, 1))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def horizontal_references(args)
|
|
232
|
+
straight([args[0], @point[1]])
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def vertical_references(args)
|
|
236
|
+
straight([@point[0], args[0]])
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def cubic_references(args)
|
|
240
|
+
@cubic_control = args.values_at(2, 3)
|
|
241
|
+
[args.values_at(0, 1), @cubic_control, args.values_at(4, 5)]
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def smooth_cubic_references(args)
|
|
245
|
+
outgoing = reflection(@cubic_control)
|
|
246
|
+
@cubic_control = args.values_at(0, 1)
|
|
247
|
+
[outgoing, @cubic_control, args.values_at(2, 3)]
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def quadratic_references(args)
|
|
251
|
+
@quadratic_control = args.values_at(0, 1)
|
|
252
|
+
[@quadratic_control, @quadratic_control, args.values_at(2, 3)]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# ARITY and TOKEN admit no other reference-bearing command here.
|
|
256
|
+
def smooth_quadratic_references(args)
|
|
257
|
+
@quadratic_control = reflection(@quadratic_control)
|
|
258
|
+
[@quadratic_control, @quadratic_control, args.values_at(0, 1)]
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Reflecting a control point through the current point. Written as
|
|
262
|
+
# `point + (point - source)` rather than `2 * point - source`, which is
|
|
263
|
+
# the same number but overflows on the way: at `M 1e308 0 S …` the
|
|
264
|
+
# source IS the current point, so the reflection is that point, and
|
|
265
|
+
# doubling it reached Infinity and pointed the head backwards.
|
|
266
|
+
def reflection(control)
|
|
267
|
+
source = control || @point
|
|
268
|
+
@point.zip(source).map { |point, original| point + (point - original) }
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def straight(destination)
|
|
272
|
+
[destination, @point, destination]
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Relative commands offset from the current point. On an arc only the
|
|
276
|
+
# final coordinate pair is a point; the radii and flags are not.
|
|
277
|
+
def relative(letter, lower, args)
|
|
278
|
+
return args if letter == letter.upcase
|
|
279
|
+
|
|
280
|
+
case lower
|
|
281
|
+
when "h" then offset_coordinate(args, 0)
|
|
282
|
+
when "v" then offset_coordinate(args, 1)
|
|
283
|
+
when "a" then relative_arc(args)
|
|
284
|
+
else relative_points(args)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def offset_coordinate(args, axis)
|
|
289
|
+
[args[0] + @point[axis]]
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def relative_arc(args)
|
|
293
|
+
args[0, 5] + relative_points(args.drop(5))
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def relative_points(args)
|
|
297
|
+
args.each_slice(2).flat_map do |x, y|
|
|
298
|
+
[x + @point[0], y + @point[1]]
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def move(args)
|
|
303
|
+
@origin = false if @origin && @origin_direction.nil?
|
|
304
|
+
@point = [args[0], args[1]]
|
|
305
|
+
@subpath_start = @point
|
|
306
|
+
@terminus = nil
|
|
307
|
+
@recent_direction = nil
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def close
|
|
311
|
+
segment(@subpath_start, @point, @subpath_start)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def segment(out_reference, in_reference, end_point)
|
|
315
|
+
@origin = [@point, out_reference] if @origin.nil?
|
|
316
|
+
remember_directions(@point, out_reference, in_reference, end_point)
|
|
317
|
+
@terminus = [in_reference, end_point]
|
|
318
|
+
@point = end_point
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Degenerate endpoint derivatives still have a direction when another
|
|
322
|
+
# edge of the same control polygon, or an earlier segment, establishes
|
|
323
|
+
# one. Keeping the pair instead of an anchor lets the true endpoint be
|
|
324
|
+
# supplied only when the caller asks for it. For a straight segment the
|
|
325
|
+
# middle pair is reversed, but the first and third pairs are the same,
|
|
326
|
+
# so the reversed one can never be `directions.first` or
|
|
327
|
+
# `directions.last`.
|
|
328
|
+
def remember_directions(*points)
|
|
329
|
+
directions = points.each_cons(2).select do |from, to|
|
|
330
|
+
heading(to, from, to)
|
|
331
|
+
end
|
|
332
|
+
return if directions.empty?
|
|
333
|
+
|
|
334
|
+
@origin_direction ||= directions.first
|
|
335
|
+
@recent_direction = directions.last
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Where the anchor sits is not where its direction comes from: the last
|
|
339
|
+
# point heads AWAY from the control point behind it, while the first
|
|
340
|
+
# heads TOWARDS the one in front. Both are the direction of travel, so
|
|
341
|
+
# both are read from the same pair, and the point is passed separately
|
|
342
|
+
# rather than assumed to be one end of it.
|
|
343
|
+
#
|
|
344
|
+
# @param at [Array] the point the anchor sits on
|
|
345
|
+
# @param from [Array] the tail of the direction of travel
|
|
346
|
+
# @param to [Array] the head of the direction of travel
|
|
347
|
+
# @return [Anchor, nil] nil when the two coincide, which leaves no
|
|
348
|
+
# direction to point an arrowhead along
|
|
349
|
+
def heading(at, from, to)
|
|
350
|
+
dx, dy = direction(from, to)
|
|
351
|
+
length = JsMath.hypot(dx, dy)
|
|
352
|
+
return nil unless usable_heading?(at, length)
|
|
353
|
+
|
|
354
|
+
Anchor.new(at[0], at[1], dx / length, dy / length)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def direction(from, to)
|
|
358
|
+
delta = to.zip(from).map { |finish, start| finish - start }
|
|
359
|
+
return delta if delta.all?(&:finite?)
|
|
360
|
+
|
|
361
|
+
# Two finite coordinates can still overflow the distance between them:
|
|
362
|
+
# `M -1e308 0 L 1e308 0` is 2e308 apart. A direction does not change
|
|
363
|
+
# with scale, so halving both ends brings the difference back into
|
|
364
|
+
# range and answers the same question. Only reached on overflow, so
|
|
365
|
+
# nothing else loses precision to it.
|
|
366
|
+
to.zip(from).map { |finish, start| (finish / 2) - (start / 2) }
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def usable_heading?(at, length)
|
|
370
|
+
# Not merely non-zero: path data carrying an out-of-range exponent
|
|
371
|
+
# can put Infinity in the anchor or in a coordinate delta. The guard
|
|
372
|
+
# keeps Infinity/Infinity out of the heading and a non-finite anchor
|
|
373
|
+
# out of the polygon's points.
|
|
374
|
+
at.all?(&:finite?) && length.finite? && length.positive?
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Polygon element <polygon>
|
|
9
|
+
#
|
|
10
|
+
# Represents a closed shape defined by a series of points.
|
|
11
|
+
class Polygon < Element
|
|
12
|
+
attribute :points, :string
|
|
13
|
+
|
|
14
|
+
writes_attributes :points
|
|
15
|
+
|
|
16
|
+
# Helper to build points string from coordinates array
|
|
17
|
+
#
|
|
18
|
+
# @param coords [Array<Array>] Array of [x, y] coordinates
|
|
19
|
+
# @return [String] Points string for polygon
|
|
20
|
+
def self.build_points(coords)
|
|
21
|
+
coords.map { |x, y| "#{x},#{y}" }.join(" ")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Polyline element <polyline>
|
|
9
|
+
#
|
|
10
|
+
# Represents an open shape defined by a series of connected points.
|
|
11
|
+
class Polyline < Element
|
|
12
|
+
attribute :points, :string
|
|
13
|
+
|
|
14
|
+
# Emitted nothing before this: a Polyline rendered as
|
|
15
|
+
# `<polyline stroke="blue"/>` with no points, and
|
|
16
|
+
# renderer/xy_chart.rb:337 draws line series with it.
|
|
17
|
+
writes_attributes :points
|
|
18
|
+
|
|
19
|
+
# Helper to build points string from coordinates array
|
|
20
|
+
#
|
|
21
|
+
# @param coords [Array<Array>] Array of [x, y] coordinates
|
|
22
|
+
# @return [String] Points string for polyline
|
|
23
|
+
def self.build_points(coords)
|
|
24
|
+
coords.map { |x, y| "#{x},#{y}" }.join(" ")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
|
|
6
|
+
module Etassia
|
|
7
|
+
module Svg
|
|
8
|
+
# SVG Rectangle element <rect>
|
|
9
|
+
#
|
|
10
|
+
# Represents a rectangle shape with position, dimensions, and optional
|
|
11
|
+
# rounded corners.
|
|
12
|
+
class Rect < Element
|
|
13
|
+
attribute :x, :float
|
|
14
|
+
attribute :y, :float
|
|
15
|
+
attribute :width, :float
|
|
16
|
+
attribute :height, :float
|
|
17
|
+
attribute :rx, :float
|
|
18
|
+
attribute :ry, :float
|
|
19
|
+
attribute :stroke_dasharray, :string
|
|
20
|
+
attribute :fill_opacity, :string
|
|
21
|
+
|
|
22
|
+
# fill-opacity is NOT listed here. Element already emits it for every
|
|
23
|
+
# element, and listing it again produced
|
|
24
|
+
# `fill-opacity="0.5" fill-opacity="0.5"` — the last 5 malformed cases
|
|
25
|
+
# in the corpus.
|
|
26
|
+
#
|
|
27
|
+
# The attribute declaration above stays so `fill_opacity=` is still a
|
|
28
|
+
# settable Ruby accessor -- from_xml no longer works on Rect at all
|
|
29
|
+
# (Lutaml::Model::TypeOnlyMappingError, no `root` declared). It still
|
|
30
|
+
# re-emits through Element exactly once, whichever way it was set.
|
|
31
|
+
writes_attributes :x, :y, :width, :height, :rx, :ry, :stroke_dasharray
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Etassia
|
|
6
|
+
module Svg
|
|
7
|
+
# Represents CSS styling for SVG elements
|
|
8
|
+
#
|
|
9
|
+
# Encapsulates style properties that can be applied to SVG elements
|
|
10
|
+
# as inline styles or style attributes.
|
|
11
|
+
class Style < Lutaml::Model::Serializable
|
|
12
|
+
attribute :fill, :string
|
|
13
|
+
attribute :stroke, :string
|
|
14
|
+
attribute :stroke_width, :float
|
|
15
|
+
attribute :stroke_dasharray, :string
|
|
16
|
+
attribute :opacity, :float
|
|
17
|
+
attribute :fill_opacity, :float
|
|
18
|
+
attribute :stroke_opacity, :float
|
|
19
|
+
attribute :font_family, :string
|
|
20
|
+
attribute :font_size, :float
|
|
21
|
+
attribute :font_weight, :string
|
|
22
|
+
attribute :text_anchor, :string
|
|
23
|
+
|
|
24
|
+
CSS_PROPERTIES = {
|
|
25
|
+
fill: "fill",
|
|
26
|
+
stroke: "stroke",
|
|
27
|
+
stroke_width: "stroke-width",
|
|
28
|
+
stroke_dasharray: "stroke-dasharray",
|
|
29
|
+
opacity: "opacity",
|
|
30
|
+
fill_opacity: "fill-opacity",
|
|
31
|
+
stroke_opacity: "stroke-opacity",
|
|
32
|
+
font_family: "font-family",
|
|
33
|
+
font_size: "font-size",
|
|
34
|
+
font_weight: "font-weight",
|
|
35
|
+
text_anchor: "text-anchor",
|
|
36
|
+
}.freeze
|
|
37
|
+
private_constant :CSS_PROPERTIES
|
|
38
|
+
|
|
39
|
+
# Convert style to CSS string for inline style attribute
|
|
40
|
+
#
|
|
41
|
+
# @return [String] CSS style string
|
|
42
|
+
def to_css
|
|
43
|
+
CSS_PROPERTIES.filter_map do |attribute, property|
|
|
44
|
+
value = public_send(attribute)
|
|
45
|
+
"#{property}:#{value}" if value
|
|
46
|
+
end.join(";")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "element"
|
|
5
|
+
require_relative "numbers"
|
|
6
|
+
require_relative "tspan"
|
|
7
|
+
|
|
8
|
+
module Etassia
|
|
9
|
+
module Svg
|
|
10
|
+
# SVG Text element <text>
|
|
11
|
+
#
|
|
12
|
+
# Displays text content at specified coordinates with optional styling
|
|
13
|
+
# and anchoring. Used for labels, annotations, and textual content.
|
|
14
|
+
class Text < Element
|
|
15
|
+
attribute :x, :float
|
|
16
|
+
attribute :y, :float
|
|
17
|
+
attribute :dx, :float
|
|
18
|
+
attribute :dy, :float
|
|
19
|
+
attribute :text_anchor, :string
|
|
20
|
+
attribute :font_family, :string
|
|
21
|
+
attribute :font_size, :string
|
|
22
|
+
attribute :font_weight, :string
|
|
23
|
+
attribute :font_style, :string
|
|
24
|
+
attribute :text_decoration, :string
|
|
25
|
+
# `textLength` and `lengthAdjust`: the width the text must fill, so a
|
|
26
|
+
# viewer's font cannot move what follows it.
|
|
27
|
+
attribute :text_length, :float
|
|
28
|
+
attribute :length_adjust, :string
|
|
29
|
+
attribute :dominant_baseline, :string
|
|
30
|
+
attribute :content, :string, collection: true
|
|
31
|
+
attribute :tspans, Tspan, collection: true
|
|
32
|
+
# "preserve" keeps the spaces at the edges of tspan runs.
|
|
33
|
+
attribute :xml_space, :string
|
|
34
|
+
|
|
35
|
+
# How far below `y` the baseline sits, in ems -- stands in for
|
|
36
|
+
# `dominant-baseline` (rejected under :metanorma). Conventional
|
|
37
|
+
# approximations, NOT font metrics: `central` is deliberately
|
|
38
|
+
# collapsed onto `middle` since Etassia has none. An unnamed value
|
|
39
|
+
# stays on the alphabetic baseline (deliberate for `mathematical`).
|
|
40
|
+
#
|
|
41
|
+
# Needs a unitless font size in user units; a relative size from
|
|
42
|
+
# a foreign document (`2em`) has no parent to resolve against and
|
|
43
|
+
# reads as the bare number.
|
|
44
|
+
BASELINE_SHIFTS = {
|
|
45
|
+
"middle" => 0.35,
|
|
46
|
+
"central" => 0.35,
|
|
47
|
+
"hanging" => 0.8,
|
|
48
|
+
"text-before-edge" => 0.8,
|
|
49
|
+
"text-after-edge" => -0.2,
|
|
50
|
+
"ideographic" => -0.2,
|
|
51
|
+
}.freeze
|
|
52
|
+
|
|
53
|
+
# The CSS initial font-size, used when a Text carries a baseline
|
|
54
|
+
# request but no size of its own. Every renderer sets one; this keeps
|
|
55
|
+
# a hand-built element from shifting by an arbitrary amount.
|
|
56
|
+
DEFAULT_FONT_SIZE = 16.0
|
|
57
|
+
|
|
58
|
+
# One line of a multi-line label, in ems (the former `dy="1.2em"`).
|
|
59
|
+
LINE_HEIGHT_EMS = 1.2
|
|
60
|
+
private_constant :BASELINE_SHIFTS, :DEFAULT_FONT_SIZE, :LINE_HEIGHT_EMS
|
|
61
|
+
|
|
62
|
+
# `dx` and `dy` are folded into x/y rather than emitted, never written
|
|
63
|
+
# out directly.
|
|
64
|
+
#
|
|
65
|
+
# Written out rather than declared with .writes_attributes, because
|
|
66
|
+
# `x` and `y` are emitted from computed readers — see #offset_x and
|
|
67
|
+
# #baseline_y.
|
|
68
|
+
ATTRIBUTE_PAIRS = [
|
|
69
|
+
["x", :offset_x],
|
|
70
|
+
["y", :baseline_y],
|
|
71
|
+
["text-anchor", :text_anchor],
|
|
72
|
+
["font-family", :font_family],
|
|
73
|
+
["font-size", :font_size],
|
|
74
|
+
["font-weight", :font_weight],
|
|
75
|
+
["font-style", :font_style],
|
|
76
|
+
["text-decoration", :text_decoration],
|
|
77
|
+
["textLength", :text_length],
|
|
78
|
+
["lengthAdjust", :length_adjust],
|
|
79
|
+
["xml:space", :xml_space],
|
|
80
|
+
].map(&:freeze).freeze
|
|
81
|
+
private_constant :ATTRIBUTE_PAIRS
|
|
82
|
+
|
|
83
|
+
protected
|
|
84
|
+
|
|
85
|
+
# A text element carries content, so it is not the self-closing tag
|
|
86
|
+
# the base class writes.
|
|
87
|
+
#
|
|
88
|
+
# `content` is declared `collection: true`. Renderers assign a plain
|
|
89
|
+
# String, so join rather than interpolate — Array(content).join is a
|
|
90
|
+
# no-op for a plain string and correct if content is ever multi-valued.
|
|
91
|
+
# Content may hold newlines, so this is the one entry in #xml_lines
|
|
92
|
+
# that is not a single line. It is why Group indents entries rather
|
|
93
|
+
# than lines.
|
|
94
|
+
#
|
|
95
|
+
# Every renderer call site sets exactly one of `content`/`tspans`.
|
|
96
|
+
#
|
|
97
|
+
# @return [String] XML string
|
|
98
|
+
def element_markup
|
|
99
|
+
"<text#{build_attributes}>#{body}</text>"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def element_attributes
|
|
103
|
+
attribute_pairs(ATTRIBUTE_PAIRS)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# SVG dx/dy are per-glyph offset lists. Their :float declarations make
|
|
107
|
+
# lutaml keep only the leading number before this method sees the value.
|
|
108
|
+
def offset_x
|
|
109
|
+
offset = Numbers.read(dx)
|
|
110
|
+
return x if offset.nil?
|
|
111
|
+
|
|
112
|
+
computed_x = (Numbers.read(x) || 0.0) + offset
|
|
113
|
+
return x unless computed_x.finite?
|
|
114
|
+
|
|
115
|
+
Numbers.write(computed_x)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# `y` with the baseline request folded in.
|
|
119
|
+
#
|
|
120
|
+
# Returns the reader untouched when there is no shift, so a Text that
|
|
121
|
+
# never asked for one serialises exactly as it did before. It is also
|
|
122
|
+
# the only usable fallback when the computed coordinate overflows.
|
|
123
|
+
#
|
|
124
|
+
# @return [Object, nil] the y attribute value
|
|
125
|
+
def baseline_y
|
|
126
|
+
shift = baseline_shift
|
|
127
|
+
offset = Numbers.read(dy)
|
|
128
|
+
return y if shift.zero? && offset.nil?
|
|
129
|
+
|
|
130
|
+
computed_y = (Numbers.read(y) || 0.0) + (offset || 0.0) + shift
|
|
131
|
+
return y unless computed_y.finite?
|
|
132
|
+
|
|
133
|
+
Numbers.write(computed_y)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
# Every renderer call site sets exactly one of `content`/`tspans`.
|
|
139
|
+
#
|
|
140
|
+
# @return [String]
|
|
141
|
+
def body
|
|
142
|
+
place_lines
|
|
143
|
+
escaped_content = Escaping.escape_text(Array(content).join)
|
|
144
|
+
escaped_content + Array(tspans).map(&:to_xml).join
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Gives each run that starts a new line an absolute `y`: this text's
|
|
148
|
+
# baseline plus the lines accumulated so far. Idempotent, so repeated
|
|
149
|
+
# serialisation writes the same values.
|
|
150
|
+
def place_lines
|
|
151
|
+
lines = 0
|
|
152
|
+
Array(tspans).each do |run|
|
|
153
|
+
next unless run.line_shift
|
|
154
|
+
|
|
155
|
+
lines += run.line_shift
|
|
156
|
+
run.y = line_y(lines)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def line_y(lines)
|
|
161
|
+
size = Numbers.read(font_size) || DEFAULT_FONT_SIZE
|
|
162
|
+
base = Numbers.read(baseline_y) || 0.0
|
|
163
|
+
placed = base + (lines * LINE_HEIGHT_EMS * size)
|
|
164
|
+
placed.finite? ? placed.round(4) : nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# May be non-finite when the font size is: #baseline_y is the one place
|
|
168
|
+
# that can fall back, so the check lives there rather than here too.
|
|
169
|
+
#
|
|
170
|
+
# @return [Float] the baseline offset in user units
|
|
171
|
+
def baseline_shift
|
|
172
|
+
return 0.0 if Escaping.blank?(dominant_baseline)
|
|
173
|
+
|
|
174
|
+
ems = BASELINE_SHIFTS.fetch(dominant_baseline.to_s.strip.downcase, 0.0)
|
|
175
|
+
return 0.0 if ems.zero?
|
|
176
|
+
|
|
177
|
+
ems * (Numbers.read(font_size) || DEFAULT_FONT_SIZE)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|