diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 0f99d4538..79c22bf5f 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -9,6 +9,7 @@ - Improved label placements for shapes with images to avoid overlapping container labels. [#474](https://github.com/terrastruct/d2/pull/474) - Sequence diagram edge group labels have more reasonable padding. [#512](https://github.com/terrastruct/d2/pull/512) +- ELK layout engine preserves order of nodes. [#282](https://github.com/terrastruct/d2/issues/282) #### Bugfixes ⛑️ diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index be40c6bff..6dd37f828 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -9,7 +9,6 @@ import ( _ "embed" "encoding/json" "fmt" - "math" "strings" "github.com/dop251/goja" @@ -79,14 +78,16 @@ type ELKGraph struct { } type ELKLayoutOptions struct { - Algorithm string `json:"elk.algorithm,omitempty"` - HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` - NodeSpacing float64 `json:"spacing.nodeNodeBetweenLayers,omitempty"` - Padding string `json:"elk.padding,omitempty"` - EdgeNodeSpacing float64 `json:"spacing.edgeNodeBetweenLayers,omitempty"` - Direction string `json:"elk.direction"` - SelfLoopSpacing float64 `json:"elk.spacing.nodeSelfLoop"` - InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"` + Algorithm string `json:"elk.algorithm,omitempty"` + HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` + NodeSpacing float64 `json:"spacing.nodeNodeBetweenLayers,omitempty"` + Padding string `json:"elk.padding,omitempty"` + EdgeNodeSpacing float64 `json:"spacing.edgeNodeBetweenLayers,omitempty"` + Direction string `json:"elk.direction"` + SelfLoopSpacing float64 `json:"elk.spacing.nodeSelfLoop"` + InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"` + ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"` + ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"` } func Layout(ctx context.Context, g *d2graph.Graph) (err error) { @@ -109,11 +110,12 @@ func Layout(ctx context.Context, g *d2graph.Graph) (err error) { elkGraph := &ELKGraph{ ID: "root", LayoutOptions: &ELKLayoutOptions{ - Algorithm: "layered", - HierarchyHandling: "INCLUDE_CHILDREN", - NodeSpacing: 100.0, - EdgeNodeSpacing: 50.0, - SelfLoopSpacing: 50.0, + Algorithm: "layered", + HierarchyHandling: "INCLUDE_CHILDREN", + NodeSpacing: 100.0, + EdgeNodeSpacing: 50.0, + SelfLoopSpacing: 50.0, + ConsiderModelOrder: "NODES_AND_EDGES", }, } switch g.Root.Attributes.Direction.Value { @@ -157,7 +159,8 @@ func Layout(ctx context.Context, g *d2graph.Graph) (err error) { if len(obj.ChildrenArray) > 0 { n.LayoutOptions = &ELKLayoutOptions{ - Padding: "[top=75,left=75,bottom=75,right=75]", + Padding: "[top=75,left=75,bottom=75,right=75]", + ForceNodeModelOrder: true, } } @@ -253,7 +256,7 @@ func Layout(ctx context.Context, g *d2graph.Graph) (err error) { parentX = parent.TopLeft.X parentY = parent.TopLeft.Y } - obj.TopLeft = geo.NewPoint(math.Round(parentX+n.X), math.Round(parentY+n.Y)) + obj.TopLeft = geo.NewPoint(parentX+n.X, parentY+n.Y) obj.Width = n.Width obj.Height = n.Height diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go index 966e03af2..d3fe777b6 100644 --- a/e2etests/regression_test.go +++ b/e2etests/regression_test.go @@ -178,6 +178,43 @@ build_workflow: lambda-build.yaml { script: `my network: { icon: https://icons.terrastruct.com/infra/019-network.svg?fuga=1&hoge } +`, + }, + { + name: "elk_order", + script: `queue: { + shape: queue + label: '' + + M0 + M1 + M2 + M3 + M4 + M5 + M6 +} + +m0_desc: |md + Oldest message +| +m0_desc -> queue.M0 + +m2_desc: |md + Offset +| +m2_desc -> queue.M2 + +m5_desc: |md + Last message +| +m5_desc -> queue.M5 + +m6_desc: |md + Next message will be\ + inserted here +| +m6_desc -> queue.M6 `, }, } diff --git a/e2etests/testdata/regression/dagre_special_ids/elk/board.exp.json b/e2etests/testdata/regression/dagre_special_ids/elk/board.exp.json index bd21d8cc7..30a954424 100644 --- a/e2etests/testdata/regression/dagre_special_ids/elk/board.exp.json +++ b/e2etests/testdata/regression/dagre_special_ids/elk/board.exp.json @@ -6,7 +6,7 @@ "id": "\"ninety\\nnine\"", "type": "", "pos": { - "x": 714, + "x": 12, "y": 12 }, "width": 151, @@ -46,7 +46,7 @@ "id": "eighty\reight", "type": "", "pos": { - "x": 194, + "x": 183, "y": 20 }, "width": 151, @@ -86,7 +86,7 @@ "id": "\"seventy\r\\nseven\"", "type": "", "pos": { - "x": 12, + "x": 354, "y": 12 }, "width": 162, @@ -126,7 +126,7 @@ "id": "\"a\\\\yode\"", "type": "", "pos": { - "x": 885, + "x": 536, "y": 28 }, "width": 154, @@ -166,7 +166,7 @@ "id": "there", "type": "", "pos": { - "x": 546, + "x": 715, "y": 254 }, "width": 143, @@ -206,7 +206,7 @@ "id": "'a\\\"ode'", "type": "", "pos": { - "x": 540, + "x": 710, "y": 28 }, "width": 154, @@ -246,7 +246,7 @@ "id": "\"a\\\\node\"", "type": "", "pos": { - "x": 365, + "x": 884, "y": 28 }, "width": 155, @@ -310,19 +310,19 @@ "labelPercentage": 0, "route": [ { - "x": 962, + "x": 613, "y": 154 }, { - "x": 962, + "x": 613, "y": 204 }, { - "x": 652.75, + "x": 751.25, "y": 204 }, { - "x": 652.75, + "x": 751.25, "y": 254 } ], @@ -357,11 +357,11 @@ "labelPercentage": 0, "route": [ { - "x": 617, + "x": 787, "y": 154 }, { - "x": 617, + "x": 787, "y": 254 } ], @@ -396,19 +396,19 @@ "labelPercentage": 0, "route": [ { - "x": 442.5, + "x": 961.5, "y": 154 }, { - "x": 442.5, + "x": 961.5, "y": 204 }, { - "x": 581.25, + "x": 822.75, "y": 204 }, { - "x": 581.25, + "x": 822.75, "y": 254 } ], diff --git a/e2etests/testdata/regression/dagre_special_ids/elk/sketch.exp.svg b/e2etests/testdata/regression/dagre_special_ids/elk/sketch.exp.svg index fb14b30ee..3ca808db4 100644 --- a/e2etests/testdata/regression/dagre_special_ids/elk/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_special_ids/elk/sketch.exp.svg @@ -18,7 +18,7 @@ width="1227" height="568" viewBox="-88 -88 1227 568">ninetynineeighty eightseventy sevena\yodetherea\"odea\node +ninetynineeighty eightseventy sevena\yodetherea\"odea\node lambda-build.yamllambda-deploy.yamlapollo-deploy.yamlPush to main branchGitHub ActionsS3TerraformAWSManual TriggerGitHub ActionsAWSApollo RepoGitHub ActionsAWS TriggersBuilds zip and pushes it Pulls zip to deployChanges live lambdasLaunchesBuilds zippushes them to S3. Deploys lambdasusing TerraformTriggered manually/push to master test test test test test test testtest +lambda-build.yamllambda-deploy.yamlapollo-deploy.yamlPush to main branchGitHub ActionsS3TerraformAWSManual TriggerGitHub ActionsAWSApollo RepoGitHub ActionsAWS TriggersBuilds zip and pushes it Pulls zip to deployChanges live lambdasLaunchesBuilds zippushes them to S3. Deploys lambdasusing TerraformTriggered manually/push to master test test test test test test testtest - - - - - - - - + + + + + + + + Oldest message +Offset +Last message +Next message will be +inserted here +M0M1M2M3M4M5M6 + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/elk_order/elk/board.exp.json b/e2etests/testdata/regression/elk_order/elk/board.exp.json new file mode 100644 index 000000000..e17d4ca0f --- /dev/null +++ b/e2etests/testdata/regression/elk_order/elk/board.exp.json @@ -0,0 +1,639 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "queue", + "type": "queue", + "pos": { + "x": 12, + "y": 165 + }, + "width": 1146, + "height": 276, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#DEE1EB", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 1 + }, + { + "id": "queue.M0", + "type": "", + "pos": { + "x": 87, + "y": 240 + }, + "width": 125, + "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": "M0", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 25, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "queue.M1", + "type": "", + "pos": { + "x": 232, + "y": 240 + }, + "width": 125, + "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": "M1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 25, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "queue.M2", + "type": "", + "pos": { + "x": 377, + "y": 240 + }, + "width": 125, + "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": "M2", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 25, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "queue.M3", + "type": "", + "pos": { + "x": 522, + "y": 240 + }, + "width": 125, + "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": "M3", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 25, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "queue.M4", + "type": "", + "pos": { + "x": 667, + "y": 240 + }, + "width": 126, + "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": "M4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 26, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "queue.M5", + "type": "", + "pos": { + "x": 813, + "y": 240 + }, + "width": 125, + "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": "M5", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 25, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "queue.M6", + "type": "", + "pos": { + "x": 958, + "y": 240 + }, + "width": 125, + "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": "M6", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 25, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "m0_desc", + "type": "text", + "pos": { + "x": 96, + "y": 36 + }, + "width": 106, + "height": 24, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Oldest message", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 106, + "labelHeight": 24, + "zIndex": 0, + "level": 1 + }, + { + "id": "m2_desc", + "type": "text", + "pos": { + "x": 419, + "y": 36 + }, + "width": 41, + "height": 24, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Offset", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 41, + "labelHeight": 24, + "zIndex": 0, + "level": 1 + }, + { + "id": "m5_desc", + "type": "text", + "pos": { + "x": 830, + "y": 36 + }, + "width": 90, + "height": 24, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Last message", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 90, + "labelHeight": 24, + "zIndex": 0, + "level": 1 + }, + { + "id": "m6_desc", + "type": "text", + "pos": { + "x": 950, + "y": 12 + }, + "width": 140, + "height": 48, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Next message will be\\\ninserted here", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 140, + "labelHeight": 48, + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(m0_desc -> queue.M0)[0]", + "src": "m0_desc", + "srcArrow": "none", + "srcLabel": "", + "dst": "queue.M0", + "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": 149.5, + "y": 60 + }, + { + "x": 149.5, + "y": 240 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(m2_desc -> queue.M2)[0]", + "src": "m2_desc", + "srcArrow": "none", + "srcLabel": "", + "dst": "queue.M2", + "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": 439.5, + "y": 60 + }, + { + "x": 439.5, + "y": 240 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(m5_desc -> queue.M5)[0]", + "src": "m5_desc", + "srcArrow": "none", + "srcLabel": "", + "dst": "queue.M5", + "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": 875.5, + "y": 60 + }, + { + "x": 875.5, + "y": 240 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(m6_desc -> queue.M6)[0]", + "src": "m6_desc", + "srcArrow": "none", + "srcLabel": "", + "dst": "queue.M6", + "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": 1020.5, + "y": 60 + }, + { + "x": 1020.5, + "y": 240 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/elk_order/elk/sketch.exp.svg b/e2etests/testdata/regression/elk_order/elk/sketch.exp.svg new file mode 100644 index 000000000..1088ee5a3 --- /dev/null +++ b/e2etests/testdata/regression/elk_order/elk/sketch.exp.svg @@ -0,0 +1,799 @@ + +Oldest message +Offset +Last message +Next message will be +inserted here +M0M1M2M3M4M5M6 + + + \ No newline at end of file diff --git a/e2etests/testdata/sanity/1_to_2/elk/board.exp.json b/e2etests/testdata/sanity/1_to_2/elk/board.exp.json index 75ea599ab..764009732 100644 --- a/e2etests/testdata/sanity/1_to_2/elk/board.exp.json +++ b/e2etests/testdata/sanity/1_to_2/elk/board.exp.json @@ -6,7 +6,7 @@ "id": "a", "type": "", "pos": { - "x": 31, + "x": 30, "y": 12 }, "width": 113, diff --git a/e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg b/e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg index 21b5d6286..bbe8b1a19 100644 --- a/e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg +++ b/e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg @@ -18,7 +18,7 @@ width="446" height="552" viewBox="-88 -88 446 552">abc +abc acbd +acbd rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud - +rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud + rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud - +rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud + cba * +cba * abcdefghijklmno +abcdefghijklmno aabbllmmnn -oocciikkddgg -hhjjee -ff1122 334455667788 - - - - - - - - - +aabbllmmnn +oocciikkddgg +hhjjee +ff1122 334455667788 + + + + + + + + + acfbdhg +acfbdhg abcdefghijklmnopq - +abcdefghijklmnopq + finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot - +finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot + bacde21345abcde +bacde21345abcde alphabeta gamma +alphabeta gamma size XSsize Ssize Msize Lsize XLsize XXLsize XXXLcustom 8custom 12custom 18custom 21custom 64 custom 10custom 15custom 48 - - - - +size XSsize Ssize Msize Lsize XLsize XXLsize XXXLcustom 8custom 12custom 18custom 21custom 64 custom 10custom 15custom 48 + + + + aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 123456 - - - - - - - +aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 123456 + + + + + + + abcdefghiqrjmnoszaabbeeffggklptuwxyccddv - +abcdefghiqrjmnoszaabbeeffggklptuwxyccddv + mixed togethersugarsolution we get +mixed togethersugarsolution we get - + Markdown: Syntax -ab +ab code -ab +code +ab abcdefghijklmnopqrstuvw - +abcdefghijklmnopqrstuvw + abcdefghijklmnopqrstu - +abcdefghijklmnopqrstu + Foo Baz12hello - +Foo Baz12hello + acdefgbh +acdefgbh topabcbottomstartend - +topabcbottomstartend + rootcontainerrootleftrightrootinnerrootinnerleftrightleftright to inner leftto inner rightto inner leftto inner rightto left container rootto right container root +rootcontainerrootleftrightrootinnerrootinnerleftrightleftright to inner leftto inner rightto inner leftto inner rightto left container rootto right container root diff --git a/e2etests/testdata/stable/pre/elk/board.exp.json b/e2etests/testdata/stable/pre/elk/board.exp.json index df945bd32..f04cb489d 100644 --- a/e2etests/testdata/stable/pre/elk/board.exp.json +++ b/e2etests/testdata/stable/pre/elk/board.exp.json @@ -45,7 +45,7 @@ "id": "a", "type": "", "pos": { - "x": 257, + "x": 256, "y": 12 }, "width": 113, @@ -85,7 +85,7 @@ "id": "b", "type": "", "pos": { - "x": 257, + "x": 256, "y": 508 }, "width": 113, diff --git a/e2etests/testdata/stable/pre/elk/sketch.exp.svg b/e2etests/testdata/stable/pre/elk/sketch.exp.svg index 440472676..2d38f4dc0 100644 --- a/e2etests/testdata/stable/pre/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/pre/elk/sketch.exp.svg @@ -781,7 +781,7 @@ end tell A code block continues until it reaches a line that is not indented (or the end of the article). -ab +ab xyz hello - - +xyz hello + + a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) +a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/e2etests/testdata/stable/sql_tables/elk/board.exp.json b/e2etests/testdata/stable/sql_tables/elk/board.exp.json index f9f18faf2..7804a2686 100644 --- a/e2etests/testdata/stable/sql_tables/elk/board.exp.json +++ b/e2etests/testdata/stable/sql_tables/elk/board.exp.json @@ -6,7 +6,7 @@ "id": "users", "type": "sql_table", "pos": { - "x": 460, + "x": 12, "y": 12 }, "width": 208, @@ -186,7 +186,7 @@ "id": "products", "type": "sql_table", "pos": { - "x": 276, + "x": 240, "y": 48 }, "width": 164, @@ -338,7 +338,7 @@ "id": "orders", "type": "sql_table", "pos": { - "x": 276, + "x": 240, "y": 328 }, "width": 164, @@ -462,7 +462,7 @@ "id": "shipments", "type": "sql_table", "pos": { - "x": 12, + "x": 424, "y": 48 }, "width": 244, @@ -638,19 +638,19 @@ "labelPercentage": 0, "route": [ { - "x": 564, + "x": 116, "y": 228 }, { - "x": 564, + "x": 116, "y": 278 }, { - "x": 399, + "x": 281, "y": 278 }, { - "x": 399, + "x": 281, "y": 328 } ], @@ -685,11 +685,11 @@ "labelPercentage": 0, "route": [ { - "x": 358, + "x": 322, "y": 228 }, { - "x": 358, + "x": 322, "y": 328 } ], @@ -724,19 +724,19 @@ "labelPercentage": 0, "route": [ { - "x": 134, + "x": 546, "y": 228 }, { - "x": 134, + "x": 546, "y": 278 }, { - "x": 317, + "x": 363, "y": 278 }, { - "x": 317, + "x": 363, "y": 328 } ], diff --git a/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg index 7757ccb0a..fc976e4c8 100644 --- a/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg @@ -18,39 +18,39 @@ width="856" height="660" viewBox="-88 -88 856 660">usersid -int -name -string -email -string -password -string -last_login -datetime -productsid -int -price -decimal -sku -string -name -string -ordersid -int -user_id -int -product_id -int -shipmentsid -int -order_id -int -tracking_number -string -status -string - +usersid +int +name +string +email +string +password +string +last_login +datetime +productsid +int +price +decimal +sku +string +name +string +ordersid +int +user_id +int +product_id +int +shipmentsid +int +order_id +int +tracking_number +string +status +string + -rectangle - -square +rectangle + +square acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc - +acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc + AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTND - +AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTND + eightsixteenthirty twosixty fourninety nine twelvetwenty fourforty eighteighty one +eightsixteenthirty twosixty fourninety nine twelvetwenty fourforty eighteighty one
Oldest message
Offset
Last message
Next message will be +inserted here
nn
gg
ee
code
A code block continues until it reaches a line that is not indented (or the end of the article).