diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index eb48251c4..9a94f1e60 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -2,6 +2,9 @@ - Latex is now supported. See [docs](https://d2lang.com/tour/text) for more. [#229](https://github.com/terrastruct/d2/pull/229) +- `direction` keyword is now supported to specify `up`, `down`, `right`, `left` layouts. See + [docs](https://d2lang.com/tour/layouts) for more. + [#251](https://github.com/terrastruct/d2/pull/251) - Arrowhead labels are now supported. [#182](https://github.com/terrastruct/d2/pull/182) - `stroke-dash` on shapes is now supported. [#188](https://github.com/terrastruct/d2/issues/188) - `font-color` is now supported on shapes and connections. [#215](https://github.com/terrastruct/d2/pull/215) @@ -11,6 +14,8 @@ #### Improvements 🔧 +- ELK layout engine now defaults to top-down to be consistent with dagre. + [#251](https://github.com/terrastruct/d2/pull/251) - [install.sh](./install.sh) prints the dry run message more visibly. [#266](https://github.com/terrastruct/d2/pull/266) diff --git a/d2compiler/compile.go b/d2compiler/compile.go index f865bfb9b..b5de7915b 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -13,6 +13,7 @@ import ( "oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2parser" "oss.terrastruct.com/d2/d2target" + "oss.terrastruct.com/d2/lib/go2" ) // TODO: should Parse even be exported? guess not. IR should contain list of files and @@ -356,6 +357,14 @@ func (c *compiler) applyScalar(attrs *d2graph.Attributes, reserved string, box d case "link": attrs.Link = scalar.ScalarString() return + case "direction": + dirs := []string{"up", "down", "right", "left"} + if !go2.Contains(dirs, scalar.ScalarString()) { + c.errorf(scalar.GetRange().Start, scalar.GetRange().End, `direction must be one of %v, got %q`, strings.Join(dirs, ", "), scalar.ScalarString()) + return + } + attrs.Direction.Value = scalar.ScalarString() + return } if _, ok := d2graph.StyleKeywords[reserved]; ok { diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index dbcc86071..07dee8f17 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1521,6 +1521,41 @@ dst.id <-> src.dst_id diff.AssertStringEq(t, "sequence_diagram", g.Root.Attributes.Shape.Value) }, }, + { + name: "root_direction", + + text: `direction: right`, + assertions: func(t *testing.T, g *d2graph.Graph) { + diff.AssertStringEq(t, "right", g.Root.Attributes.Direction.Value) + }, + }, + { + name: "default_direction", + + text: `x`, + assertions: func(t *testing.T, g *d2graph.Graph) { + diff.AssertStringEq(t, "down", g.Objects[0].Attributes.Direction.Value) + }, + }, + { + name: "set_direction", + + text: `x: { + direction: left +}`, + assertions: func(t *testing.T, g *d2graph.Graph) { + diff.AssertStringEq(t, "left", g.Objects[0].Attributes.Direction.Value) + }, + }, + { + name: "invalid_direction", + + text: `x: { + direction: diagonal +}`, + expErr: `d2/testdata/d2compiler/TestCompile/invalid_direction.d2:2:14: direction must be one of up, down, right, left, got "diagonal" +`, + }, } for _, tc := range testCases { diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 1fe88fba4..69d8d918d 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -39,6 +39,7 @@ func NewGraph(ast *d2ast.Map) *Graph { Parent: nil, Children: make(map[string]*Object), } + d.Root.Attributes.Direction.Value = "down" return d } @@ -97,6 +98,8 @@ type Attributes struct { Language string `json:"language,omitempty"` // TODO: default to ShapeRectangle instead of empty string Shape Scalar `json:"shape"` + + Direction Scalar `json:"direction"` } // TODO references at the root scope should have their Scope set to root graph AST @@ -442,6 +445,9 @@ func (obj *Object) newObject(id string) *Object { Label: Scalar{ Value: idval, }, + Direction: Scalar{ + Value: "down", + }, }, Graph: obj.Graph, @@ -1057,6 +1063,7 @@ var ReservedKeywords = map[string]struct{}{ "near": {}, "width": {}, "height": {}, + "direction": {}, } // ReservedKeywordHolders are reserved keywords that are meaningless on its own and exist solely to hold a set of reserved keywords diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 51f30bf09..9fa88ccc3 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -60,12 +60,22 @@ func Layout(ctx context.Context, d2graph *d2graph.Graph) (err error) { return err } - configJS := setGraphAttrs(dagreGraphAttrs{ + rootAttrs := dagreGraphAttrs{ ranksep: 100, edgesep: 40, nodesep: 60, - rankdir: "tb", - }) + } + switch d2graph.Root.Attributes.Direction.Value { + case "down": + rootAttrs.rankdir = "TB" + case "right": + rootAttrs.rankdir = "LR" + case "left": + rootAttrs.rankdir = "RL" + case "up": + rootAttrs.rankdir = "BT" + } + configJS := setGraphAttrs(rootAttrs) if _, err := v8ctx.RunScript(configJS, "config.js"); err != nil { return err } diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index 47904d6cc..9365949b7 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -68,10 +68,10 @@ type ELKEdge struct { } type ELKGraph struct { - ID string `json:"id"` - LayoutOptions ELKLayoutOptions `json:"layoutOptions"` - Children []*ELKNode `json:"children,omitempty"` - Edges []*ELKEdge `json:"edges,omitempty"` + ID string `json:"id"` + LayoutOptions *ELKLayoutOptions `json:"layoutOptions"` + Children []*ELKNode `json:"children,omitempty"` + Edges []*ELKEdge `json:"edges,omitempty"` } type ELKLayoutOptions struct { @@ -80,6 +80,7 @@ type ELKLayoutOptions struct { NodeSpacing float64 `json:"spacing.nodeNodeBetweenLayers,omitempty"` Padding string `json:"elk.padding,omitempty"` EdgeNodeSpacing float64 `json:"spacing.edgeNodeBetweenLayers,omitempty"` + Direction string `json:"elk.direction"` } func Layout(ctx context.Context, g *d2graph.Graph) (err error) { @@ -114,13 +115,23 @@ func Layout(ctx context.Context, g *d2graph.Graph) (err error) { elkGraph := &ELKGraph{ ID: "root", - LayoutOptions: ELKLayoutOptions{ + LayoutOptions: &ELKLayoutOptions{ Algorithm: "layered", HierarchyHandling: "INCLUDE_CHILDREN", NodeSpacing: 100.0, EdgeNodeSpacing: 50.0, }, } + switch g.Root.Attributes.Direction.Value { + case "down": + elkGraph.LayoutOptions.Direction = "DOWN" + case "up": + elkGraph.LayoutOptions.Direction = "UP" + case "right": + elkGraph.LayoutOptions.Direction = "RIGHT" + case "left": + elkGraph.LayoutOptions.Direction = "LEFT" + } elkNodes := make(map[*d2graph.Object]*ELKNode) elkEdges := make(map[*d2graph.Edge]*ELKEdge) diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index 17cfa561e..02b66f0a3 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -986,6 +986,20 @@ sugar -> c c: mixed together c -> solution: we get +`, + }, + { + name: "direction", + script: `a -> b -> c -> d -> e +b: { + direction: right + 1 -> 2 -> 3 -> 4 -> 5 + + 2: { + direction: up + a -> b -> c -> d -> e + } +} `, }, { 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 c1d27b8de..6c709942a 100644 --- a/e2etests/testdata/sanity/1_to_2/elk/board.exp.json +++ b/e2etests/testdata/sanity/1_to_2/elk/board.exp.json @@ -5,8 +5,8 @@ "id": "a", "type": "", "pos": { - "x": 12, - "y": 33 + "x": 31, + "y": 12 }, "width": 113, "height": 126, @@ -43,8 +43,8 @@ "id": "b", "type": "", "pos": { - "x": 225, - "y": 12 + "x": 12, + "y": 238 }, "width": 113, "height": 126, @@ -81,8 +81,8 @@ "id": "c", "type": "", "pos": { - "x": 225, - "y": 158 + "x": 145, + "y": 238 }, "width": 113, "height": 126, @@ -143,12 +143,12 @@ "labelPercentage": 0, "route": [ { - "x": 125, - "y": 75 + "x": 68.5, + "y": 138 }, { - "x": 225, - "y": 75 + "x": 68.5, + "y": 238 } ], "animated": false, @@ -181,20 +181,20 @@ "labelPercentage": 0, "route": [ { - "x": 125, - "y": 117 + "x": 106.16666666666667, + "y": 138 }, { - "x": 175, - "y": 117 + "x": 106.16666666666667, + "y": 188 }, { - "x": 175, - "y": 221 + "x": 201.5, + "y": 188 }, { - "x": 225, - "y": 221 + "x": 201.5, + "y": 238 } ], "animated": false, 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 76640f7f2..c6a7e3671 100644 --- a/e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg +++ b/e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg @@ -2,7 +2,7 @@ // RegisterHash registers a function that returns a new instance of the given // hash function. This is intended to be called from the init function in // packages that implement hash functions. func RegisterHash(h Hash, f func() hash.Hash) { @@ -22,7 +22,7 @@ width="1382" height="366" viewBox="-88 -88 1382 366">        panic("crypto: RegisterHash of unknown hash function")     }     hashes[h] = f -}xy acfbdhg agdfbhec abcdefghijklmnopq finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot bacde21345abcde \ No newline at end of file diff --git a/e2etests/testdata/stable/direction/elk/board.exp.json b/e2etests/testdata/stable/direction/elk/board.exp.json new file mode 100644 index 000000000..37051403b --- /dev/null +++ b/e2etests/testdata/stable/direction/elk/board.exp.json @@ -0,0 +1,1033 @@ +{ + "name": "", + "shapes": [ + { + "id": "b", + "type": "", + "pos": { + "x": 12, + "y": 238 + }, + "width": 414, + "height": 1594, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 18, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER" + }, + { + "id": "b.2", + "type": "", + "pos": { + "x": 87, + "y": 459 + }, + "width": 264, + "height": 860, + "level": 2, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "2", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 16, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER" + }, + { + "id": "a", + "type": "", + "pos": { + "x": 163, + "y": 12 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "c", + "type": "", + "pos": { + "x": 163, + "y": 1932 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "d", + "type": "", + "pos": { + "x": 162, + "y": 2158 + }, + "width": 114, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "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" + }, + { + "id": "e", + "type": "", + "pos": { + "x": 163, + "y": 2384 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b.1", + "type": "", + "pos": { + "x": 163, + "y": 313 + }, + "width": 112, + "height": 126, + "level": 2, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "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" + }, + { + "id": "b.3", + "type": "", + "pos": { + "x": 163, + "y": 1339 + }, + "width": 113, + "height": 126, + "level": 2, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "3", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b.4", + "type": "", + "pos": { + "x": 162, + "y": 1485 + }, + "width": 114, + "height": 126, + "level": 2, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b.5", + "type": "", + "pos": { + "x": 163, + "y": 1631 + }, + "width": 113, + "height": 126, + "level": 2, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "5", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b.2.a", + "type": "", + "pos": { + "x": 163, + "y": 534 + }, + "width": 113, + "height": 126, + "level": 3, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b.2.b", + "type": "", + "pos": { + "x": 163, + "y": 680 + }, + "width": 113, + "height": 126, + "level": 3, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "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" + }, + { + "id": "b.2.c", + "type": "", + "pos": { + "x": 163, + "y": 826 + }, + "width": 113, + "height": 126, + "level": 3, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b.2.d", + "type": "", + "pos": { + "x": 162, + "y": 972 + }, + "width": 114, + "height": 126, + "level": 3, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "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" + }, + { + "id": "b.2.e", + "type": "", + "pos": { + "x": 163, + "y": 1118 + }, + "width": 113, + "height": 126, + "level": 3, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "e", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "b", + "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": 219, + "y": 138 + }, + { + "x": 219, + "y": 238 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(b -> c)[0]", + "src": "b", + "srcArrow": "none", + "srcLabel": "", + "dst": "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": 219, + "y": 1832 + }, + { + "x": 219, + "y": 1932 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(c -> d)[0]", + "src": "c", + "srcArrow": "none", + "srcLabel": "", + "dst": "d", + "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": 219, + "y": 2058 + }, + { + "x": 219, + "y": 2158 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(d -> e)[0]", + "src": "d", + "srcArrow": "none", + "srcLabel": "", + "dst": "e", + "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": 219, + "y": 2284 + }, + { + "x": 219, + "y": 2384 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.(1 -> 2)[0]", + "src": "b.1", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.2", + "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": 219, + "y": 439 + }, + { + "x": 219, + "y": 459 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.(2 -> 3)[0]", + "src": "b.2", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.3", + "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": 219, + "y": 1319 + }, + { + "x": 219, + "y": 1339 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.(3 -> 4)[0]", + "src": "b.3", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.4", + "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": 219, + "y": 1465 + }, + { + "x": 219, + "y": 1485 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.(4 -> 5)[0]", + "src": "b.4", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.5", + "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": 219, + "y": 1611 + }, + { + "x": 219, + "y": 1631 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.2.(a -> b)[0]", + "src": "b.2.a", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.2.b", + "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": 219, + "y": 660 + }, + { + "x": 219, + "y": 680 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.2.(b -> c)[0]", + "src": "b.2.b", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.2.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": 219, + "y": 806 + }, + { + "x": 219, + "y": 826 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.2.(c -> d)[0]", + "src": "b.2.c", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.2.d", + "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": 219, + "y": 952 + }, + { + "x": 219, + "y": 972 + } + ], + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "b.2.(d -> e)[0]", + "src": "b.2.d", + "srcArrow": "none", + "srcLabel": "", + "dst": "b.2.e", + "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": 219, + "y": 1098 + }, + { + "x": 219, + "y": 1118 + } + ], + "animated": false, + "tooltip": "", + "icon": null + } + ] +} diff --git a/e2etests/testdata/stable/direction/elk/sketch.exp.svg b/e2etests/testdata/stable/direction/elk/sketch.exp.svg new file mode 100644 index 000000000..1733e1ad8 --- /dev/null +++ b/e2etests/testdata/stable/direction/elk/sketch.exp.svg @@ -0,0 +1,24 @@ + +bacde21345abcde \ No newline at end of file diff --git a/e2etests/testdata/stable/font_colors/elk/board.exp.json b/e2etests/testdata/stable/font_colors/elk/board.exp.json index 0c8ebea65..41a5119ca 100644 --- a/e2etests/testdata/stable/font_colors/elk/board.exp.json +++ b/e2etests/testdata/stable/font_colors/elk/board.exp.json @@ -43,8 +43,8 @@ "id": "beta", "type": "", "pos": { - "x": 409, - "y": 12 + "x": 17, + "y": 359 }, "width": 136, "height": 126, @@ -105,12 +105,12 @@ "labelPercentage": 0, "route": [ { - "x": 157, - "y": 75 + "x": 84.5, + "y": 138 }, { - "x": 409, - "y": 75 + "x": 84.5, + "y": 359 } ], "animated": false, diff --git a/e2etests/testdata/stable/font_colors/elk/sketch.exp.svg b/e2etests/testdata/stable/font_colors/elk/sketch.exp.svg index a69bb2a09..d851b1a03 100644 --- a/e2etests/testdata/stable/font_colors/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/font_colors/elk/sketch.exp.svg @@ -2,7 +2,7 @@ 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 -tracking_number -string -status +order_id +int +tracking_number string - - -rectangle - -square acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDcontainerfirstsecond - - -1->2 - - -c->2