From cc0a04875745bfb1ea06e537c2251e99efa6b479 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 12 Jan 2023 10:29:13 -0800 Subject: [PATCH 01/37] test --- d2renderers/d2svg/style.css | 12 ++++++++++++ .../dagre_edge_label_spacing/dagre/sketch.exp.svg | 12 ++++++++++++ .../dagre_edge_label_spacing/elk/sketch.exp.svg | 12 ++++++++++++ .../dagre_special_ids/dagre/sketch.exp.svg | 12 ++++++++++++ .../regression/dagre_special_ids/elk/sketch.exp.svg | 12 ++++++++++++ .../regression/elk_alignment/dagre/sketch.exp.svg | 12 ++++++++++++ .../regression/elk_alignment/elk/sketch.exp.svg | 12 ++++++++++++ .../elk_img_empty_label_panic/dagre/sketch.exp.svg | 12 ++++++++++++ .../elk_img_empty_label_panic/elk/sketch.exp.svg | 12 ++++++++++++ .../regression/elk_order/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/regression/elk_order/elk/sketch.exp.svg | 12 ++++++++++++ .../regression/empty_sequence/dagre/sketch.exp.svg | 12 ++++++++++++ .../regression/empty_sequence/elk/sketch.exp.svg | 12 ++++++++++++ .../regression/no-lexer/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/regression/no-lexer/elk/sketch.exp.svg | 12 ++++++++++++ .../only_header_class_table/dagre/sketch.exp.svg | 12 ++++++++++++ .../only_header_class_table/elk/sketch.exp.svg | 12 ++++++++++++ .../overlapping-edge-label/dagre/sketch.exp.svg | 12 ++++++++++++ .../overlapping-edge-label/elk/sketch.exp.svg | 12 ++++++++++++ .../query_param_escape/dagre/sketch.exp.svg | 12 ++++++++++++ .../regression/query_param_escape/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_name_crash/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_name_crash/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_no_message/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_no_message/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_span_cover/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_span_cover/elk/sketch.exp.svg | 12 ++++++++++++ .../sql_table_overflow/dagre/sketch.exp.svg | 12 ++++++++++++ .../regression/sql_table_overflow/elk/sketch.exp.svg | 12 ++++++++++++ .../unnamed_class_table_code/dagre/sketch.exp.svg | 12 ++++++++++++ .../unnamed_class_table_code/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/sanity/1_to_2/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/sanity/basic/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/sanity/basic/elk/sketch.exp.svg | 12 ++++++++++++ .../sanity/child_to_child/dagre/sketch.exp.svg | 12 ++++++++++++ .../sanity/child_to_child/elk/sketch.exp.svg | 12 ++++++++++++ .../sanity/connection_label/dagre/sketch.exp.svg | 12 ++++++++++++ .../sanity/connection_label/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/sanity/empty/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/sanity/empty/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/all_shapes/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/all_shapes/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/all_shapes_multiple/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/all_shapes_multiple/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/all_shapes_shadow/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/all_shapes_shadow/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/arrowhead_adjustment/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/arrowhead_adjustment/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/arrowhead_labels/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/arrowhead_labels/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/binary_tree/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/binary_tree/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/chaos1/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/chaos1/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/chaos2/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/child_parent_edges/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/child_parent_edges/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/circular_dependency/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/circular_dependency/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/class/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/class/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/code_snippet/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/code_snippet/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/connected_container/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/connected_container/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/constant_near_stress/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/constant_near_stress/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/constant_near_title/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/constant_near_title/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/container_edges/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/container_edges/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/crow_foot_arrowhead/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/crow_foot_arrowhead/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/dense/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/dense/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/different_subgraphs/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/different_subgraphs/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/direction/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/direction/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/font_colors/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/font_colors/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/font_sizes/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/font_sizes/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/giant_markdown_test/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/giant_markdown_test/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/hr/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/hr/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/icon-label/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/icon-label/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/images/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/images/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/investigate/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/investigate/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/large_arch/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/large_arch/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/latex/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/latex/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li1/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li1/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li2/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li2/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li3/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li3/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li4/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/li4/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/links/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/links/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/lone_h1/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/lone_h1/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/markdown/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/markdown/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/markdown_stroke_fill/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/markdown_stroke_fill/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/md_2space_newline/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/md_2space_newline/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/md_backslash_newline/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/md_backslash_newline/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/md_code_block_fenced/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/md_code_block_fenced/elk/sketch.exp.svg | 12 ++++++++++++ .../md_code_block_indented/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/md_code_block_indented/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/md_code_inline/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/md_code_inline/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/multiline_text/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/multiline_text/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/multiple_trees/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/multiple_trees/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/n22_e32/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/n22_e32/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/number_connections/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/number_connections/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/one_container_loop/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/one_container_loop/elk/sketch.exp.svg | 12 ++++++++++++ .../one_three_one_container/dagre/sketch.exp.svg | 12 ++++++++++++ .../one_three_one_container/elk/sketch.exp.svg | 12 ++++++++++++ .../dagre/sketch.exp.svg | 12 ++++++++++++ .../elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/p/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/p/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/pre/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/pre/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/self-referencing/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/self-referencing/elk/sketch.exp.svg | 12 ++++++++++++ .../dagre/sketch.exp.svg | 12 ++++++++++++ .../elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_all_shapes/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_all_shapes/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_distance/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_distance/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_groups/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_groups/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_long_note/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_long_note/elk/sketch.exp.svg | 12 ++++++++++++ .../dagre/sketch.exp.svg | 12 ++++++++++++ .../elk/sketch.exp.svg | 12 ++++++++++++ .../dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_nested_span/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_note/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/sequence_diagram_note/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_real/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/sequence_diagram_real/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_self_edges/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_self_edges/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_simple/dagre/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_simple/elk/sketch.exp.svg | 12 ++++++++++++ .../sequence_diagram_span/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/sequence_diagram_span/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/sequence_diagrams/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/sequence_diagrams/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/sql_tables/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/sql_tables/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/square_3d/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/square_3d/elk/sketch.exp.svg | 12 ++++++++++++ .../dagre/sketch.exp.svg | 12 ++++++++++++ .../straight_hierarchy_container/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/stylish/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/stylish/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/text_font_sizes/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/text_font_sizes/elk/sketch.exp.svg | 12 ++++++++++++ .../testdata/stable/tooltips/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/tooltips/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/transparent_3d/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/transparent_3d/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/unnamed_only_height/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/unnamed_only_height/elk/sketch.exp.svg | 12 ++++++++++++ .../stable/unnamed_only_width/dagre/sketch.exp.svg | 12 ++++++++++++ .../stable/unnamed_only_width/elk/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/us_map/dagre/sketch.exp.svg | 12 ++++++++++++ e2etests/testdata/stable/us_map/elk/sketch.exp.svg | 12 ++++++++++++ .../todo/container_child_edge/dagre/sketch.exp.svg | 12 ++++++++++++ .../todo/container_child_edge/elk/sketch.exp.svg | 12 ++++++++++++ .../font_sizes_containers_large/dagre/sketch.exp.svg | 12 ++++++++++++ .../font_sizes_containers_large/elk/sketch.exp.svg | 12 ++++++++++++ .../todo/font_sizes_large/dagre/sketch.exp.svg | 12 ++++++++++++ .../todo/font_sizes_large/elk/sketch.exp.svg | 12 ++++++++++++ .../dagre/sketch.exp.svg | 12 ++++++++++++ .../elk/sketch.exp.svg | 12 ++++++++++++ .../todo/shape_set_width_height/dagre/sketch.exp.svg | 12 ++++++++++++ .../todo/shape_set_width_height/elk/sketch.exp.svg | 12 ++++++++++++ .../todo/tall_edge_label/dagre/sketch.exp.svg | 12 ++++++++++++ .../testdata/todo/tall_edge_label/elk/sketch.exp.svg | 12 ++++++++++++ 203 files changed, 2436 insertions(+) diff --git a/d2renderers/d2svg/style.css b/d2renderers/d2svg/style.css index 2476c6ae7..5a7bc3b10 100644 --- a/d2renderers/d2svg/style.css +++ b/d2renderers/d2svg/style.css @@ -10,3 +10,15 @@ mix-blend-mode: multiply; opacity: 0.5; } + + +@keyframes dashdraw { + from { + stroke-dashoffset: 30; + } +} + +path[stroke-dasharray] { + stroke-dasharray: 15 15; + animation: dashdraw 0.5s linear infinite; +} diff --git a/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg index 1e7b73085..24918268a 100644 --- a/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg @@ -18,6 +18,18 @@ width="2832" height="441" viewBox="-102 -102 2832 441">your love life will behappyharmonious + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/animated/elk/board.exp.json b/e2etests/testdata/stable/animated/elk/board.exp.json new file mode 100644 index 000000000..89d3c0453 --- /dev/null +++ b/e2etests/testdata/stable/animated/elk/board.exp.json @@ -0,0 +1,214 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "your love life will be", + "type": "", + "pos": { + "x": 111, + "y": 12 + }, + "width": 247, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "your love life will be", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 147, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "happy", + "type": "", + "pos": { + "x": 12, + "y": 238 + }, + "width": 149, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "happy", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 49, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "harmonious", + "type": "", + "pos": { + "x": 181, + "y": 238 + }, + "width": 190, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "harmonious", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 90, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(your love life will be -> happy)[0]", + "src": "your love life will be", + "srcArrow": "none", + "srcLabel": "", + "dst": "happy", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 193.66666666666669, + "y": 138 + }, + { + "x": 193.66666666666669, + "y": 188 + }, + { + "x": 86.5, + "y": 188 + }, + { + "x": 86.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(your love life will be -> harmonious)[0]", + "src": "your love life will be", + "srcArrow": "none", + "srcLabel": "", + "dst": "harmonious", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 276, + "y": 138 + }, + { + "x": 276, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/animated/elk/sketch.exp.svg b/e2etests/testdata/stable/animated/elk/sketch.exp.svg new file mode 100644 index 000000000..6adb4db90 --- /dev/null +++ b/e2etests/testdata/stable/animated/elk/sketch.exp.svg @@ -0,0 +1,62 @@ + +your love life will behappyharmonious + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg index 048039058..90796e221 100644 --- a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg @@ -18,18 +18,6 @@ width="494" height="793" viewBox="-108 -107 494 793">your love life will behappyharmonious - - +]]>your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear + + \ No newline at end of file diff --git a/e2etests/testdata/stable/animated/elk/board.exp.json b/e2etests/testdata/stable/animated/elk/board.exp.json index 89d3c0453..92badcbf0 100644 --- a/e2etests/testdata/stable/animated/elk/board.exp.json +++ b/e2etests/testdata/stable/animated/elk/board.exp.json @@ -121,6 +121,406 @@ "labelPosition": "INSIDE_MIDDLE_CENTER", "zIndex": 0, "level": 1 + }, + { + "id": "boredom", + "type": "", + "pos": { + "x": 402, + "y": 12 + }, + "width": 168, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "boredom", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 68, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "immortality", + "type": "", + "pos": { + "x": 391, + "y": 238 + }, + "width": 191, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "immortality", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 91, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Friday", + "type": "", + "pos": { + "x": 607, + "y": 12 + }, + "width": 150, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Friday", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 50, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Monday", + "type": "", + "pos": { + "x": 602, + "y": 238 + }, + "width": 161, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Monday", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 61, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Insomnia", + "type": "", + "pos": { + "x": 935, + "y": 12 + }, + "width": 170, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Insomnia", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 70, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Sleep", + "type": "", + "pos": { + "x": 783, + "y": 238 + }, + "width": 145, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Sleep", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 45, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Wake", + "type": "", + "pos": { + "x": 948, + "y": 238 + }, + "width": 144, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Wake", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 44, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Dream", + "type": "", + "pos": { + "x": 1112, + "y": 238 + }, + "width": 151, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Dream", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 51, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Listen", + "type": "", + "pos": { + "x": 1225, + "y": 12 + }, + "width": 148, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Listen", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 48, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Talk", + "type": "", + "pos": { + "x": 1231, + "y": 464 + }, + "width": 136, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Talk", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 36, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 } ], "connections": [ @@ -150,11 +550,11 @@ "labelPercentage": 0, "route": [ { - "x": 193.66666666666669, + "x": 193.66666666666652, "y": 138 }, { - "x": 193.66666666666669, + "x": 193.66666666666652, "y": 188 }, { @@ -197,7 +597,7 @@ "labelPercentage": 0, "route": [ { - "x": 276, + "x": 275.9999999999999, "y": 138 }, { @@ -209,6 +609,256 @@ "tooltip": "", "icon": null, "zIndex": 0 + }, + { + "id": "(boredom <- immortality)[0]", + "src": "boredom", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "immortality", + "dstArrow": "none", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 486.5, + "y": 138 + }, + { + "x": 486.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Friday <-> Monday)[0]", + "src": "Friday", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "Monday", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 682.5, + "y": 138 + }, + { + "x": 682.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Insomnia -- Sleep)[0]", + "src": "Insomnia", + "srcArrow": "none", + "srcLabel": "", + "dst": "Sleep", + "dstArrow": "none", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 977.5, + "y": 138 + }, + { + "x": 977.5, + "y": 188 + }, + { + "x": 855.5, + "y": 188 + }, + { + "x": 855.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Insomnia -- Wake)[0]", + "src": "Insomnia", + "srcArrow": "none", + "srcLabel": "", + "dst": "Wake", + "dstArrow": "none", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1020, + "y": 138 + }, + { + "x": 1020, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Insomnia -- Dream)[0]", + "src": "Insomnia", + "srcArrow": "none", + "srcLabel": "", + "dst": "Dream", + "dstArrow": "none", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 8, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1062.5, + "y": 138 + }, + { + "x": 1062.5, + "y": 188 + }, + { + "x": 1187.5, + "y": 188 + }, + { + "x": 1187.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Listen <-> Talk)[0]", + "src": "Listen", + "srcArrow": "cf-one", + "srcLabel": "", + "dst": "Talk", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "hear", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 32, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1299, + "y": 138 + }, + { + "x": 1299, + "y": 464 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 } ] } diff --git a/e2etests/testdata/stable/animated/elk/sketch.exp.svg b/e2etests/testdata/stable/animated/elk/sketch.exp.svg index 6adb4db90..5d3c01de3 100644 --- a/e2etests/testdata/stable/animated/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/animated/elk/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="563" height="556" viewBox="-90 -90 563 556"> \ No newline at end of file From 2d43fbdb6413136d31bcc5097982a7055557844c Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 12 Jan 2023 11:11:58 -0800 Subject: [PATCH 04/37] changelog --- ci/release/changelogs/next.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 489a520f2..4d0ab566d 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -1,5 +1,7 @@ #### Features 🚀 +- `animated` keyword implemented for connections. [#652](https://github.com/terrastruct/d2/pull/652) + #### Improvements 🧹 - ELK layouts tuned to have better defaults. [#627](https://github.com/terrastruct/d2/pull/627) From 48c9cc792972ea8f0c6917d1c88c70129f2ba573 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 12 Jan 2023 11:20:18 -0800 Subject: [PATCH 05/37] sketch --- d2renderers/d2sketch/sketch.go | 22 ++---- d2renderers/d2sketch/sketch_test.go | 5 ++ .../d2sketch/testdata/animated/sketch.exp.svg | 77 +++++++++++++++++++ d2renderers/d2svg/d2svg.go | 28 +------ d2target/d2target.go | 27 +++++++ 5 files changed, 116 insertions(+), 43 deletions(-) create mode 100644 d2renderers/d2sketch/testdata/animated/sketch.exp.svg diff --git a/d2renderers/d2sketch/sketch.go b/d2renderers/d2sketch/sketch.go index 4c4913a2b..ea9b7035b 100644 --- a/d2renderers/d2sketch/sketch.go +++ b/d2renderers/d2sketch/sketch.go @@ -163,20 +163,6 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) { return output, nil } -func connectionStyle(connection d2target.Connection) string { - out := "" - - out += fmt.Sprintf(`stroke:%s;`, connection.Stroke) - out += fmt.Sprintf(`opacity:%f;`, connection.Opacity) - out += fmt.Sprintf(`stroke-width:%d;`, connection.StrokeWidth) - if connection.StrokeDash != 0 { - dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), connection.StrokeDash) - out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize) - } - - return out -} - func Connection(r *Runner, connection d2target.Connection, path, attrs string) (string, error) { roughness := 1.0 js := fmt.Sprintf(`node = rc.path("%s", {roughness: %f, seed: 1});`, path, roughness) @@ -185,10 +171,14 @@ func Connection(r *Runner, connection d2target.Connection, path, attrs string) ( return "", err } output := "" + animatedClass := "" + if connection.Animated { + animatedClass = " animated-connection" + } for _, p := range paths { output += fmt.Sprintf( - ``, - p, connectionStyle(connection), attrs, + ``, + animatedClass, p, connection.CSSStyle(), attrs, ) } return output, nil diff --git a/d2renderers/d2sketch/sketch_test.go b/d2renderers/d2sketch/sketch_test.go index c2b8dadea..f35eb1be7 100644 --- a/d2renderers/d2sketch/sketch_test.go +++ b/d2renderers/d2sketch/sketch_test.go @@ -39,6 +39,11 @@ func TestSketch(t *testing.T) { script: `winter.snow -> summer.sun `, }, + { + name: "animated", + script: `winter.snow -> summer.sun -> trees -> winter.snow: { style.animated: true } + `, + }, { name: "connection label", script: `a -> b: hello diff --git a/d2renderers/d2sketch/testdata/animated/sketch.exp.svg b/d2renderers/d2sketch/testdata/animated/sketch.exp.svg new file mode 100644 index 000000000..25a6c8c99 --- /dev/null +++ b/d2renderers/d2sketch/testdata/animated/sketch.exp.svg @@ -0,0 +1,77 @@ + + + + + + +wintersummertreessnowsun + + + \ No newline at end of file diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index b4b352b67..0f28eccb2 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -466,7 +466,7 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co animatedClass = " animated-connection" } fmt.Fprintf(writer, ``, - path, animatedClass, connectionStyle(connection), attrs) + path, animatedClass, connection.CSSStyle(), attrs) } if connection.Label != "" { @@ -966,32 +966,6 @@ func shapeStyle(shape d2target.Shape) string { return out } -func connectionStyle(connection d2target.Connection) string { - out := "" - - out += fmt.Sprintf(`stroke:%s;`, connection.Stroke) - out += fmt.Sprintf(`opacity:%f;`, connection.Opacity) - out += fmt.Sprintf(`stroke-width:%d;`, connection.StrokeWidth) - strokeDash := connection.StrokeDash - if strokeDash == 0 && connection.Animated { - strokeDash = 5 - } - if strokeDash != 0 { - dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), strokeDash) - out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize) - - if connection.Animated { - dashOffset := -10 - if connection.SrcArrow != d2target.NoArrowhead && connection.DstArrow == d2target.NoArrowhead { - dashOffset = 10 - } - out += fmt.Sprintf(`stroke-dashoffset:%f;`, float64(dashOffset)*(dashSize+gapSize)) - out += fmt.Sprintf(`animation: dashdraw %fs linear infinite;`, gapSize*0.5) - } - } - return out -} - func embedFonts(buf *bytes.Buffer, fontFamily *d2fonts.FontFamily) { content := buf.String() buf.WriteString(`acb12d line 1line 2line 3line 4 + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json new file mode 100644 index 000000000..7c00e2724 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json @@ -0,0 +1,381 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 490, + "height": 878, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 17, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "a.c", + "type": "", + "pos": { + "x": 106, + "y": 539 + }, + "width": 264, + "height": 276, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "white", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.c.d", + "type": "", + "pos": { + "x": 181, + "y": 614 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "d", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "a.b", + "type": "", + "pos": { + "x": 87, + "y": 87 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.1", + "type": "", + "pos": { + "x": 182, + "y": 313 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.2", + "type": "", + "pos": { + "x": 314, + "y": 313 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "2", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "a.(b -> c)[0]", + "src": "a.b", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "red", + "label": "line 1\nline 2\nline 3\nline 4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "red", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 36, + "labelHeight": 69, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 143.5, + "y": 213 + }, + { + "x": 143.5, + "y": 489 + }, + { + "x": 172.5, + "y": 489 + }, + { + "x": 172.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(1 -> c)[0]", + "src": "a.1", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 238.5, + "y": 439 + }, + { + "x": 238.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(2 <-> c)[0]", + "src": "a.2", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 371, + "y": 439 + }, + { + "x": 371, + "y": 489 + }, + { + "x": 304.5, + "y": 489 + }, + { + "x": 304.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg new file mode 100644 index 000000000..1160dee24 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg @@ -0,0 +1,66 @@ + +acb12d line 1line 2line 3line 4 + + + \ No newline at end of file From 25e37fd0c4803102b2e7cc982c463f7203356fcb Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 11 Jan 2023 15:31:27 -0800 Subject: [PATCH 08/37] handle straight line --- d2layouts/d2dagrelayout/layout.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 0d5c5d569..34b87fcd6 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -263,18 +263,20 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err path := make([]*geo.Point, 0) path = append(path, points[0]) - path = append(path, points[0].AddVector(vectors[0].Multiply(.8))) - for i := 1; i < len(vectors)-2; i++ { - p := points[i] - v := vectors[i] - path = append(path, p.AddVector(v.Multiply(.2))) - path = append(path, p.AddVector(v.Multiply(.5))) - path = append(path, p.AddVector(v.Multiply(.8))) + if len(vectors) > 1 { + path = append(path, points[0].AddVector(vectors[0].Multiply(.8))) + for i := 1; i < len(vectors)-2; i++ { + p := points[i] + v := vectors[i] + path = append(path, p.AddVector(v.Multiply(.2))) + path = append(path, p.AddVector(v.Multiply(.5))) + path = append(path, p.AddVector(v.Multiply(.8))) + } + path = append(path, points[len(points)-2].AddVector(vectors[len(vectors)-1].Multiply(.2))) + edge.IsCurve = true } - path = append(path, points[len(points)-2].AddVector(vectors[len(vectors)-1].Multiply(.2))) path = append(path, points[len(points)-1]) - edge.IsCurve = true edge.Route = path // compile needs to assign edge label positions if edge.Attributes.Label.Value != "" { From 54f34d72ad92a4f8c7a4d9772536eb61660b1af8 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 11 Jan 2023 20:21:47 -0800 Subject: [PATCH 09/37] extend previous segment to target if last segment is very short --- d2layouts/d2dagrelayout/layout.go | 43 +++++++++++++++++++++++++++++++ lib/geo/point.go | 6 ++--- lib/geo/point_test.go | 2 +- lib/geo/segment.go | 8 ++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 34b87fcd6..7ac2a44e4 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -30,6 +30,8 @@ var setupJS string //go:embed dagre.js var dagreJS string +const MIN_SEGMENT_LEN = 10 + type ConfigurableOpts struct { NodeSep int `json:"nodesep"` EdgeSep int `json:"edgesep"` @@ -247,6 +249,47 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err } } + // arrowheads can appear broken if segments are very short from dagre routing a point just outside the shape + // to fix this, we try extending the previous segment into the shape instead of having a very short segment + if !start.Equals(points[0]) && startIndex+2 < len(points) { + newStartingSegment := *geo.NewSegment(start, points[startIndex+1]) + if newStartingSegment.Length() < MIN_SEGMENT_LEN { + // we don't want a very short segment right next to the source because it will mess up the arrowhead + // instead we want to extend the next segment into the shape border if possible + nextStart := points[startIndex+1] + nextEnd := points[startIndex+2] + + // Note: in other direction to extend towards source + nextSegment := *geo.NewSegment(nextStart, nextEnd) + v := nextSegment.ToVector() + extendedStart := nextEnd.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint() + extended := *geo.NewSegment(nextEnd, extendedStart) + + if intersections := edge.Src.Box.Intersections(extended); len(intersections) > 0 { + start = intersections[0] + startIndex += 1 + } + } + } + if !end.Equals(points[len(points)-1]) && endIndex-2 >= 0 { + newEndingSegment := *geo.NewSegment(end, points[endIndex-1]) + if newEndingSegment.Length() < MIN_SEGMENT_LEN { + // extend the prev segment into the shape border if possible + prevStart := points[endIndex-2] + prevEnd := points[endIndex-1] + + prevSegment := *geo.NewSegment(prevStart, prevEnd) + v := prevSegment.ToVector() + extendedEnd := prevStart.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint() + extended := *geo.NewSegment(prevStart, extendedEnd) + + if intersections := edge.Dst.Box.Intersections(extended); len(intersections) > 0 { + end = intersections[0] + endIndex -= 1 + } + } + } + srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Attributes.Shape.Value)], edge.Src.Box) dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Attributes.Shape.Value)], edge.Dst.Box) diff --git a/lib/geo/point.go b/lib/geo/point.go index 13275db79..0acc5021b 100644 --- a/lib/geo/point.go +++ b/lib/geo/point.go @@ -187,12 +187,12 @@ func (p *Point) DistanceToLine(p1, p2 *Point) float64 { // Moves the given point by Vector func (start *Point) AddVector(v Vector) *Point { - return start.toVector().Add(v).ToPoint() + return start.ToVector().Add(v).ToPoint() } // Creates a Vector of the size between start and endpoint, pointing to endpoint func (start *Point) VectorTo(endpoint *Point) Vector { - return endpoint.toVector().Minus(start.toVector()) + return endpoint.ToVector().Minus(start.ToVector()) } func (p *Point) FormattedCoordinates() string { @@ -205,7 +205,7 @@ func (q *Point) OnSegment(p, r *Point) bool { } // Creates a Vector pointing to point -func (endpoint *Point) toVector() Vector { +func (endpoint *Point) ToVector() Vector { return []float64{endpoint.X, endpoint.Y} } diff --git a/lib/geo/point_test.go b/lib/geo/point_test.go index 259975897..343f8bb30 100644 --- a/lib/geo/point_test.go +++ b/lib/geo/point_test.go @@ -29,7 +29,7 @@ func TestAddVector(t *testing.T) { func TestToVector(t *testing.T) { p := &Point{3.5, 6.7} - v := p.toVector() + v := p.ToVector() if v[0] != p.X || v[1] != p.Y { t.Fatalf("Expected Vector (%v) coordinates to match the point (%v)", p, v) diff --git a/lib/geo/segment.go b/lib/geo/segment.go index 473cb12e8..df6f64a5c 100644 --- a/lib/geo/segment.go +++ b/lib/geo/segment.go @@ -114,3 +114,11 @@ func (segment *Segment) GetBounds(segments []*Segment, buffer float64) (float64, } return floor, ceil } + +func (segment Segment) Length() float64 { + return EuclideanDistance(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y) +} + +func (segment Segment) ToVector() Vector { + return NewVector(segment.End.X-segment.Start.X, segment.End.Y-segment.Start.Y) +} From d59fa7fd0b68ed3c370ea38c6806ef8f479b7f4a Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 11 Jan 2023 20:26:50 -0800 Subject: [PATCH 10/37] update test --- .../dagre_broken_arrowhead/dagre/board.exp.json | 14 +++++++------- .../dagre_broken_arrowhead/dagre/sketch.exp.svg | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json index f6d941eba..5a05fac5f 100644 --- a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json @@ -278,11 +278,11 @@ "y": 251.9 }, { - "x": 120.2, - "y": 358.7 + "x": 120, + "y": 287.5 }, { - "x": 121, + "x": 120, "y": 359.5 } ], @@ -327,7 +327,7 @@ }, { "x": 292.5, - "y": 358.7 + "y": 287.5 }, { "x": 292.5, @@ -374,11 +374,11 @@ "y": 251.9 }, { - "x": 464.8, - "y": 358.7 + "x": 465, + "y": 287.5 }, { - "x": 464, + "x": 465, "y": 359.5 } ], diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg index 5cc5284f5..657dbb9f6 100644 --- a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="775" height="852" viewBox="-102 -102 775 852">aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 +aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 diff --git a/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json b/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json index d64f023cc..29604db23 100644 --- a/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json +++ b/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json @@ -361,20 +361,11 @@ "x": 243.66666666666669, "y": 238 }, - { - "x": 243.93333333333334, - "y": 237.99628770301624 - }, - { - "x": 243.73333333333335, - "y": 237.99907192575407 - }, { "x": 244, "y": 237.9953596287703 } ], - "isCurve": true, "animated": false, "tooltip": "", "icon": null, diff --git a/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg b/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg index c157addac..f8a893097 100644 --- a/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="698" height="630" viewBox="-102 -102 698 630">xy + + + + + + + + + + + + + + +I like turtles + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json new file mode 100644 index 000000000..d54413e03 --- /dev/null +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json @@ -0,0 +1,78 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "sql_table", + "pos": { + "x": 12, + "y": 12 + }, + "width": 60, + "height": 72, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "I like turtles", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "y", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 10, + "labelHeight": 26 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "" + } + ], + "label": "x", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 17, + "labelHeight": 36, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" + } + ], + "connections": [] +} diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg new file mode 100644 index 000000000..2517048ed --- /dev/null +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg @@ -0,0 +1,70 @@ + +xy + + + + + + + + + + + + + + +I like turtles + + + \ No newline at end of file From adee356d81b8b5c6cdc1502674975d1df269ea33 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Fri, 13 Jan 2023 08:21:32 -0800 Subject: [PATCH 14/37] fix sql attributes --- d2compiler/compile.go | 2 +- d2compiler/compile_test.go | 19 + e2etests/stable_test.go | 9 + .../dagre/board.exp.json | 124 +++- .../dagre/sketch.exp.svg | 14 +- .../elk/board.exp.json | 115 +++- .../elk/sketch.exp.svg | 14 +- .../table_connection_attr.exp.json | 570 ++++++++++++++++++ 8 files changed, 856 insertions(+), 11 deletions(-) create mode 100644 testdata/d2compiler/TestCompile/table_connection_attr.exp.json diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 48498a767..38c1f68d6 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -763,7 +763,7 @@ func flattenContainer(g *d2graph.Graph, obj *d2graph.Object) { newEdge.DstTableColumnIndex = new(int) *newEdge.DstTableColumnIndex = *e.DstTableColumnIndex } - newEdge.Attributes.Label = e.Attributes.Label + newEdge.Attributes = e.Attributes newEdge.References = e.References } updatedEdges := []*d2graph.Edge{} diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 81db413f2..a432f078e 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1597,6 +1597,25 @@ b`, g.Objects[0].Attributes.Label.Value) } }, }, + { + name: "table_connection_attr", + + text: `x: { + shape: sql_table + y +} +a: { + shape: sql_table + b +} +x.y -> a.b: { + style.animated: true +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "true", g.Edges[0].Attributes.Style.Animated.Value) + }, + }, { name: "class_paren", diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index c65582e72..24981d9fe 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -1805,6 +1805,15 @@ x: { y tooltip: I like turtles } + +a: { + shape: sql_table + b +} + +x.y -> a.b: { + style.animated: true +} `, }, } diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json index 5cacce054..93aba66a4 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json @@ -54,7 +54,7 @@ "labelHeight": 0 }, "constraint": "", - "reference": "" + "reference": "a.b" } ], "label": "x", @@ -72,7 +72,127 @@ "primaryAccentColor": "#0D32B2", "secondaryAccentColor": "#4A6FF3", "neutralAccentColor": "#676C7E" + }, + { + "id": "a", + "type": "sql_table", + "pos": { + "x": 0, + "y": 172 + }, + "width": 60, + "height": 72, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "b", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 10, + "labelHeight": 26 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "" + } + ], + "label": "a", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 16, + "labelHeight": 36, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" } ], - "connections": [] + "connections": [ + { + "id": "(x -> a)[0]", + "src": "x", + "srcArrow": "none", + "srcLabel": "", + "dst": "a", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 30, + "y": 72 + }, + { + "x": 30, + "y": 112 + }, + { + "x": 30, + "y": 132 + }, + { + "x": 30, + "y": 172 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] } diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg index 45bf8f483..4c942441c 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="280" height="292" viewBox="-102 -118 280 292"> \ No newline at end of file diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json index d54413e03..315f66a6c 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json @@ -54,7 +54,7 @@ "labelHeight": 0 }, "constraint": "", - "reference": "" + "reference": "a.b" } ], "label": "x", @@ -72,7 +72,118 @@ "primaryAccentColor": "#0D32B2", "secondaryAccentColor": "#4A6FF3", "neutralAccentColor": "#676C7E" + }, + { + "id": "a", + "type": "sql_table", + "pos": { + "x": 12, + "y": 184 + }, + "width": 60, + "height": 72, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "b", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 10, + "labelHeight": 26 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "" + } + ], + "label": "a", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 16, + "labelHeight": 36, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" } ], - "connections": [] + "connections": [ + { + "id": "(x -> a)[0]", + "src": "x", + "srcArrow": "none", + "srcLabel": "", + "dst": "a", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 42, + "y": 84 + }, + { + "x": 42, + "y": 184 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] } diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg index 2517048ed..0efc20882 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="280" height="292" viewBox="-90 -106 280 292"> \ No newline at end of file diff --git a/testdata/d2compiler/TestCompile/table_connection_attr.exp.json b/testdata/d2compiler/TestCompile/table_connection_attr.exp.json new file mode 100644 index 000000000..2dc6c143d --- /dev/null +++ b/testdata/d2compiler/TestCompile/table_connection_attr.exp.json @@ -0,0 +1,570 @@ +{ + "graph": { + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-11:0:99", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-3:1:29", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:3:3-3:0:28", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:2:7-1:18:23", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:2:7-1:7:12", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:2:7-1:7:12", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:9:14-1:18:23", + "value": [ + { + "string": "sql_table", + "raw_string": "sql_table" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,2:2:26-2:3:27", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,2:2:26-2:3:27", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,2:2:26-2:3:27", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-7:1:59", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:3:33-7:0:58", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:2:37-5:18:53", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:2:37-5:7:42", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:2:37-5:7:42", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:9:44-5:18:53", + "value": [ + { + "string": "sql_table", + "raw_string": "sql_table" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,6:2:56-6:3:57", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,6:2:56-6:3:57", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,6:2:56-6:3:57", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-10:1:98", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:10:70", + "src": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:4:64", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:1:61", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:2:62-8:3:63", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:6:66-8:10:70", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:7:67-8:8:68", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:9:69-8:10:70", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:12:72-10:0:97", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:2:76-9:22:96", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:2:76-9:16:90", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:2:76-9:7:81", + "value": [ + { + "string": "style", + "raw_string": "style" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:8:82-9:16:90", + "value": [ + { + "string": "animated", + "raw_string": "animated" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "boolean": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:18:92-9:22:96", + "value": true + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "attributes": { + "label": { + "value": "" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + }, + "edges": [ + { + "index": 0, + "minWidth": 0, + "minHeight": 0, + "srcTableColumnIndex": 0, + "dstTableColumnIndex": 0, + "label_dimensions": { + "width": 0, + "height": 0 + }, + "isCurve": false, + "src_arrow": false, + "dst_arrow": true, + "references": [ + { + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "" + }, + "style": { + "animated": { + "value": "true" + } + }, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + } + ], + "objects": [ + { + "id": "x", + "id_val": "x", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + }, + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:4:64", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:1:61", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:2:62-8:3:63", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "sql_table": { + "columns": [ + { + "name": { + "label": "y", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "a.b" + } + ] + }, + "attributes": { + "label": { + "value": "x" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "sql_table" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + }, + { + "id": "a", + "id_val": "a", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + }, + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:6:66-8:10:70", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:7:67-8:8:68", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:9:69-8:10:70", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "sql_table": { + "columns": [ + { + "name": { + "label": "b", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "" + } + ] + }, + "attributes": { + "label": { + "value": "a" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "sql_table" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + } + ] + }, + "err": null +} From 1420dab5a92ef4e638e9d2be7fbad7744e13feb9 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Fri, 13 Jan 2023 08:26:38 -0800 Subject: [PATCH 15/37] also transfer arrowheads --- d2compiler/compile.go | 2 ++ e2etests/stable_test.go | 1 + .../stable/sql_table_tooltip_animated/dagre/board.exp.json | 2 +- .../stable/sql_table_tooltip_animated/dagre/sketch.exp.svg | 2 +- .../stable/sql_table_tooltip_animated/elk/board.exp.json | 2 +- .../stable/sql_table_tooltip_animated/elk/sketch.exp.svg | 2 +- 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 38c1f68d6..c89a4853e 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -757,10 +757,12 @@ func flattenContainer(g *d2graph.Graph, obj *d2graph.Object) { // TODO more attributes if e.SrcTableColumnIndex != nil { newEdge.SrcTableColumnIndex = new(int) + newEdge.SrcArrowhead = e.SrcArrowhead *newEdge.SrcTableColumnIndex = *e.SrcTableColumnIndex } if e.DstTableColumnIndex != nil { newEdge.DstTableColumnIndex = new(int) + newEdge.DstArrowhead = e.DstArrowhead *newEdge.DstTableColumnIndex = *e.DstTableColumnIndex } newEdge.Attributes = e.Attributes diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index 24981d9fe..fb9f7399a 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -1813,6 +1813,7 @@ a: { x.y -> a.b: { style.animated: true + target-arrowhead.shape: cf-many } `, }, diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json index 93aba66a4..08265e940 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json @@ -152,7 +152,7 @@ "srcArrow": "none", "srcLabel": "", "dst": "a", - "dstArrow": "triangle", + "dstArrow": "cf-many", "dstLabel": "", "opacity": 1, "strokeDash": 0, diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg index 4c942441c..12c3e8317 100644 --- a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg @@ -56,7 +56,7 @@ width="280" height="464" viewBox="-102 -118 280 464"> + + + + +ab00112233445566778899 <->-- arrowtriangle diamond diamond filled cf-many cf-many-required cf-one cf-one-required + + + + + + + + + + + + \ No newline at end of file From af2a032a9e981ab5455c9954308fcd25912973f1 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Thu, 12 Jan 2023 12:01:49 -0800 Subject: [PATCH 18/37] render sketch arrowheads separately --- d2renderers/d2svg/d2svg.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index b57b483e8..5ed641c44 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -10,6 +10,7 @@ import ( "hash/fnv" "html" "io" + "regexp" "sort" "strings" @@ -60,6 +61,8 @@ var sketchStyleCSS string //go:embed github-markdown.css var mdCSS string +var strokeWidthRE = regexp.MustCompile(`(.*stroke-width):(.+?);(.*)`) + type RenderOpts struct { Pad int Sketch bool @@ -449,24 +452,32 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co } path := pathData(connection, idToShape) - attrs := fmt.Sprintf(`%s%smask="url(#%s)"`, - markerStart, - markerEnd, - labelMaskID, - ) + mask := fmt.Sprintf(`mask="url(#%s)"`, labelMaskID) if sketchRunner != nil { - out, err := d2sketch.Connection(sketchRunner, connection, path, attrs) + out, err := d2sketch.Connection(sketchRunner, connection, path, mask) if err != nil { return "", err } - fmt.Fprintf(writer, out) + fmt.Fprint(writer, out) + + // render sketch arrowheads separately + // TODO add sketch specific arrowheads + if markerStart != "" || markerEnd != "" { + // set stroke width to 0 + style := strokeWidthRE.ReplaceAllString(connection.CSSStyle(), `$1:0;$3`) + fmt.Fprintf(writer, ``, + path, style, + markerStart, + markerEnd, + ) + } } else { animatedClass := "" if connection.Animated { animatedClass = " animated-connection" } - fmt.Fprintf(writer, ``, - path, animatedClass, connection.CSSStyle(), attrs) + fmt.Fprintf(writer, ``, + path, animatedClass, connection.CSSStyle(), markerStart, markerEnd, mask) } if connection.Label != "" { From 62d153f79887fdb2d3b43c926594ca24d4e758eb Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Thu, 12 Jan 2023 12:05:05 -0800 Subject: [PATCH 19/37] update tests --- d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/animated/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/basic/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/child_to_child/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/connection_label/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/sql_tables/sketch.exp.svg | 2 +- d2renderers/d2sketch/testdata/twitter/sketch.exp.svg | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg index efb2c8aba..fd826c475 100644 --- a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg +++ b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg @@ -51,7 +51,7 @@ width="1597" height="835" viewBox="-102 -102 1597 835"> + +# 2 leading, 2 trailing +def hello(): + +  print "world" + + + +# 2 leading +def hello(): + +  print "world"# 2 trailing +def hello(): + +  print "world" + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json new file mode 100644 index 000000000..3e0bd62e5 --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json @@ -0,0 +1,124 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hello world", + "type": "code", + "pos": { + "x": 12, + "y": 12 + }, + "width": 239, + "height": 86, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading, 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 239, + "labelHeight": 86, + "zIndex": 0, + "level": 1 + }, + { + "id": "no trailing", + "type": "code", + "pos": { + "x": 271, + "y": 12 + }, + "width": 160, + "height": 86, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading\ndef hello():\n\n print \"world\"", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 86, + "zIndex": 0, + "level": 1 + }, + { + "id": "no leading", + "type": "code", + "pos": { + "x": 451, + "y": 12 + }, + "width": 160, + "height": 86, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "# 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 86, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg new file mode 100644 index 000000000..b3352ede2 --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg @@ -0,0 +1,69 @@ + + + +# 2 leading, 2 trailing +def hello(): + +  print "world" + + + +# 2 leading +def hello(): + +  print "world"# 2 trailing +def hello(): + +  print "world" + + + + + \ No newline at end of file From 7f13be1524c2ea53cd1867138398b5a9c0e9f61c Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 13 Jan 2023 20:03:39 -0800 Subject: [PATCH 32/37] account for leading/trailing newlines when measuring code shapes --- d2graph/d2graph.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 21361304a..28ea03ef9 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -1027,6 +1027,27 @@ func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2 var h int if t.Language != "" { w, h = ruler.Measure(d2fonts.SourceCodePro.Font(t.FontSize, d2fonts.FONT_STYLE_REGULAR), t.Text) + + // count empty leading and trailing lines since ruler will not be able to measure it + lines := strings.Split(t.Text, "\n") + leadingLines := 0 + for _, line := range lines { + if strings.TrimSpace(line) == "" { + leadingLines++ + } else { + break + } + } + trailingLines := 0 + for i := len(lines) - 1; i >= 0; i-- { + if strings.TrimSpace(lines[i]) == "" { + trailingLines++ + } else { + break + } + } + h += t.FontSize * (leadingLines + trailingLines) + // padding w += 12 h += 12 From 1bf92b4c3c26142b0a9613daa1ec445ec409f75b Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 13 Jan 2023 20:05:04 -0800 Subject: [PATCH 33/37] update test --- .../dagre/board.exp.json | 16 ++++++++-------- .../dagre/sketch.exp.svg | 12 ++++++------ .../elk/board.exp.json | 16 ++++++++-------- .../elk/sketch.exp.svg | 12 ++++++------ 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json index 161541e69..6096ee9c0 100644 --- a/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/board.exp.json @@ -10,7 +10,7 @@ "y": 0 }, "width": 239, - "height": 86, + "height": 150, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -37,7 +37,7 @@ "bold": true, "underline": false, "labelWidth": 239, - "labelHeight": 86, + "labelHeight": 150, "zIndex": 0, "level": 1 }, @@ -46,10 +46,10 @@ "type": "code", "pos": { "x": 299, - "y": 0 + "y": 16 }, "width": 160, - "height": 86, + "height": 118, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -76,7 +76,7 @@ "bold": true, "underline": false, "labelWidth": 160, - "labelHeight": 86, + "labelHeight": 118, "zIndex": 0, "level": 1 }, @@ -85,10 +85,10 @@ "type": "code", "pos": { "x": 519, - "y": 0 + "y": 16 }, "width": 160, - "height": 86, + "height": 118, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -115,7 +115,7 @@ "bold": true, "underline": false, "labelWidth": 160, - "labelHeight": 86, + "labelHeight": 118, "zIndex": 0, "level": 1 } diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg index 18b87b5d0..b35570020 100644 --- a/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/dagre/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="883" height="290" viewBox="-102 -102 883 290">