From f6580b69df9269986766d45aa1df11523a4b7dc5 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 2 Jun 2023 11:05:02 -0700 Subject: [PATCH 1/5] add multiple_box_selection test --- e2etests/stable_test.go | 1 + .../testdata/files/multiple_box_selection.d2 | 11 + .../dagre/board.exp.json | 437 ++++++++++++++++++ .../dagre/sketch.exp.svg | 102 ++++ .../multiple_box_selection/elk/board.exp.json | 371 +++++++++++++++ .../multiple_box_selection/elk/sketch.exp.svg | 102 ++++ 6 files changed, 1024 insertions(+) create mode 100644 e2etests/testdata/files/multiple_box_selection.d2 create mode 100644 e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json create mode 100644 e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg create mode 100644 e2etests/testdata/stable/multiple_box_selection/elk/board.exp.json create mode 100644 e2etests/testdata/stable/multiple_box_selection/elk/sketch.exp.svg diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index ff25dfd6d..7adfa8072 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -2726,6 +2726,7 @@ scenarios: { loadFromFile(t, "grid_icon"), loadFromFile(t, "multiple_offset"), loadFromFile(t, "multiple_offset_left"), + loadFromFile(t, "multiple_box_selection"), } runa(t, tcs) diff --git a/e2etests/testdata/files/multiple_box_selection.d2 b/e2etests/testdata/files/multiple_box_selection.d2 new file mode 100644 index 000000000..a4301aa80 --- /dev/null +++ b/e2etests/testdata/files/multiple_box_selection.d2 @@ -0,0 +1,11 @@ +outer: { + vg: volume group { + vd: volume definition { + style.multiple: true + + volume.style.multiple: true + volume.style.stroke-dash: 3 + } + } +} +start -> outer.vg.vd.volume -> end diff --git a/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json b/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json new file mode 100644 index 000000000..edc87a5af --- /dev/null +++ b/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json @@ -0,0 +1,437 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "outer", + "type": "rectangle", + "pos": { + "x": 0, + "y": 207 + }, + "width": 268, + "height": 335, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "outer", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 63, + "labelHeight": 36, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "outer.vg", + "type": "rectangle", + "pos": { + "x": 20, + "y": 272 + }, + "width": 228, + "height": 240, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "volume group", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 140, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "outer.vg.vd", + "type": "rectangle", + "pos": { + "x": 40, + "y": 345 + }, + "width": 188, + "height": 145, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "volume definition", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 147, + "labelHeight": 26, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "outer.vg.vd.volume", + "type": "rectangle", + "pos": { + "x": 80, + "y": 390 + }, + "width": 98, + "height": 66, + "opacity": 1, + "strokeDash": 3, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N7", + "stroke": "B2", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "volume", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 53, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 4 + }, + { + "id": "start", + "type": "rectangle", + "pos": { + "x": 94, + "y": 0 + }, + "width": 80, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "start", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "end", + "type": "rectangle", + "pos": { + "x": 98, + "y": 642 + }, + "width": 72, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "end", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 27, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(start -> outer.vg.vd.volume)[0]", + "src": "start", + "srcArrow": "none", + "dst": "outer.vg.vd.volume", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 134, + "y": 66 + }, + { + "x": 134, + "y": 106 + }, + { + "x": 134, + "y": 126 + }, + { + "x": 134, + "y": 141 + }, + { + "x": 134, + "y": 156 + }, + { + "x": 134, + "y": 176 + }, + { + "x": 134, + "y": 191 + }, + { + "x": 134, + "y": 206 + }, + { + "x": 134, + "y": 288.79998779296875 + }, + { + "x": 134, + "y": 380 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(outer.vg.vd.volume -> end)[0]", + "src": "outer.vg.vd.volume", + "srcArrow": "none", + "dst": "end", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 134, + "y": 456 + }, + { + "x": 134, + "y": 444.79998779296875 + }, + { + "x": 134, + "y": 452 + }, + { + "x": 134, + "y": 467 + }, + { + "x": 134, + "y": 482 + }, + { + "x": 134, + "y": 502 + }, + { + "x": 134, + "y": 517 + }, + { + "x": 134, + "y": 532 + }, + { + "x": 134, + "y": 602 + }, + { + "x": 134, + "y": 642 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg b/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg new file mode 100644 index 000000000..07623dea1 --- /dev/null +++ b/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg @@ -0,0 +1,102 @@ +outerstartendvolume groupvolume definitionvolume + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/multiple_box_selection/elk/board.exp.json b/e2etests/testdata/stable/multiple_box_selection/elk/board.exp.json new file mode 100644 index 000000000..f9f1eb196 --- /dev/null +++ b/e2etests/testdata/stable/multiple_box_selection/elk/board.exp.json @@ -0,0 +1,371 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "outer", + "type": "rectangle", + "pos": { + "x": 12, + "y": 153 + }, + "width": 408, + "height": 396, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "outer", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 63, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "outer.vg", + "type": "rectangle", + "pos": { + "x": 62, + "y": 208 + }, + "width": 308, + "height": 286, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "volume group", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 140, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "outer.vg.vd", + "type": "rectangle", + "pos": { + "x": 112, + "y": 273 + }, + "width": 208, + "height": 176, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "volume definition", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 147, + "labelHeight": 26, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "outer.vg.vd.volume", + "type": "rectangle", + "pos": { + "x": 162, + "y": 333 + }, + "width": 98, + "height": 66, + "opacity": 1, + "strokeDash": 3, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N7", + "stroke": "B2", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "volume", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 53, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 4 + }, + { + "id": "start", + "type": "rectangle", + "pos": { + "x": 176, + "y": 12 + }, + "width": 80, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "start", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "end", + "type": "rectangle", + "pos": { + "x": 180, + "y": 624 + }, + "width": 72, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "end", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 27, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(start -> outer.vg.vd.volume)[0]", + "src": "start", + "srcArrow": "none", + "dst": "outer.vg.vd.volume", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 216, + "y": 78 + }, + { + "x": 216, + "y": 323 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(outer.vg.vd.volume -> end)[0]", + "src": "outer.vg.vd.volume", + "srcArrow": "none", + "dst": "end", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 216, + "y": 399 + }, + { + "x": 216, + "y": 624 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/stable/multiple_box_selection/elk/sketch.exp.svg b/e2etests/testdata/stable/multiple_box_selection/elk/sketch.exp.svg new file mode 100644 index 000000000..6ac271a10 --- /dev/null +++ b/e2etests/testdata/stable/multiple_box_selection/elk/sketch.exp.svg @@ -0,0 +1,102 @@ +outerstartendvolume groupvolume definitionvolume + + + \ No newline at end of file From 4015a486643107ef4092e7f5adc38f64f120c349 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 2 Jun 2023 14:15:49 -0700 Subject: [PATCH 2/5] fix dagre shifting connection start past 2nd point --- d2graph/layout.go | 112 ++++++++++++++++++++++++++++++ d2layouts/d2dagrelayout/layout.go | 4 +- lib/geo/point.go | 19 +++++ 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/d2graph/layout.go b/d2graph/layout.go index 43342daa1..25b66795b 100644 --- a/d2graph/layout.go +++ b/d2graph/layout.go @@ -141,6 +141,118 @@ func (obj *Object) ShiftDescendants(dx, dy float64) { }) } +// ShiftStart moves the starting point of the route by delta either horizontally or vertically +// if subsequent points are in line with the movement, they will be removed (unless it is the last point) +// start end +// . ├────┼────┼───┼────┼───┤ before +// . ├──dx──► +// . ├──┼───┼────┼───┤ after +func (edge *Edge) ShiftStart(delta float64, isHorizontal bool) { + position := func(p *geo.Point) float64 { + if isHorizontal { + return p.X + } + return p.Y + } + + start := edge.Route[0] + next := edge.Route[1] + isIncreasing := position(start) < position(next) + if isHorizontal { + start.X += delta + } else { + start.Y += delta + } + + if isIncreasing == (delta < 0) { + // nothing more to do when moving away from the next point + return + } + + isAligned := func(p *geo.Point) bool { + if isHorizontal { + return p.Y == start.Y + } + return p.X == start.X + } + isPastStart := func(p *geo.Point) bool { + if delta > 0 { + return position(p) < position(start) + } else { + return position(p) > position(start) + } + } + + needsRemoval := false + toRemove := make([]bool, len(edge.Route)) + for i := 1; i < len(edge.Route)-1; i++ { + if !isAligned(edge.Route[i]) { + break + } + if isPastStart(edge.Route[i]) { + toRemove[i] = true + needsRemoval = true + } + } + if needsRemoval { + edge.Route = geo.RemovePoints(edge.Route, toRemove) + } +} + +// ShiftEnd moves the ending point of the route by delta either horizontally or vertically +// if prior points are in line with the movement, they will be removed (unless it is the first point) +func (edge *Edge) ShiftEnd(delta float64, isHorizontal bool) { + position := func(p *geo.Point) float64 { + if isHorizontal { + return p.X + } + return p.Y + } + + end := edge.Route[len(edge.Route)-1] + prev := edge.Route[len(edge.Route)-2] + isIncreasing := position(prev) < position(end) + if isHorizontal { + end.X += delta + } else { + end.Y += delta + } + + if isIncreasing == (delta > 0) { + // nothing more to do when moving away from the next point + return + } + + isAligned := func(p *geo.Point) bool { + if isHorizontal { + return p.Y == end.Y + } + return p.X == end.X + } + isPastEnd := func(p *geo.Point) bool { + if delta > 0 { + return position(p) < position(end) + } else { + return position(p) > position(end) + } + } + + needsRemoval := false + toRemove := make([]bool, len(edge.Route)) + for i := len(edge.Route) - 2; i > 0; i-- { + if !isAligned(edge.Route[i]) { + break + } + if isPastEnd(edge.Route[i]) { + toRemove[i] = true + needsRemoval = true + } + } + if needsRemoval { + edge.Route = geo.RemovePoints(edge.Route, toRemove) + } +} + // GetModifierElementAdjustments returns width/height adjustments to account for shapes with 3d or multiple func (obj *Object) GetModifierElementAdjustments() (dx, dy float64) { if obj.Is3D() { diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index e033c61e7..97734237d 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -384,7 +384,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err if isHorizontal && e.Src.Parent != g.Root && e.Dst.Parent != g.Root { moveWholeEdge = true } else { - e.Route[0].Y += stepSize + e.ShiftStart(stepSize, false) } } } @@ -393,7 +393,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err if isHorizontal && e.Dst.Parent != g.Root && e.Src.Parent != g.Root { moveWholeEdge = true } else { - e.Route[len(e.Route)-1].Y += stepSize + e.ShiftEnd(stepSize, false) } } } diff --git a/lib/geo/point.go b/lib/geo/point.go index 0b0a4ff51..ab8e034a0 100644 --- a/lib/geo/point.go +++ b/lib/geo/point.go @@ -305,3 +305,22 @@ func (p *Point) TruncateDecimals() { p.X = TruncateDecimals(p.X) p.Y = TruncateDecimals(p.Y) } + +// RemovePoints returns a new Points slice without the points in toRemove +func RemovePoints(points Points, toRemove []bool) Points { + newLen := len(points) + for _, should := range toRemove { + if should { + newLen-- + } + } + + without := make([]*Point, 0, newLen) + for i := 0; i < len(points); i++ { + if toRemove[i] { + continue + } + without = append(without, points[i]) + } + return without +} From 2c0142abfdb0aba77ea07afe9e5581a107ae58e4 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 2 Jun 2023 15:46:30 -0700 Subject: [PATCH 3/5] update test --- .../dagre/board.exp.json | 14 +- .../dagre/sketch.exp.svg | 158 +++++++++--------- 2 files changed, 80 insertions(+), 92 deletions(-) diff --git a/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json b/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json index edc87a5af..defb282e2 100644 --- a/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json +++ b/e2etests/testdata/stable/multiple_box_selection/dagre/board.exp.json @@ -352,19 +352,7 @@ }, { "x": 134, - "y": 444.79998779296875 - }, - { - "x": 134, - "y": 452 - }, - { - "x": 134, - "y": 467 - }, - { - "x": 134, - "y": 482 + "y": 484.79998779296875 }, { "x": 134, diff --git a/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg b/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg index 07623dea1..cd9d766d3 100644 --- a/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/multiple_box_selection/dagre/sketch.exp.svg @@ -1,16 +1,16 @@ -outerstartendvolume groupvolume definitionvolume + .d2-240483443 .fill-N1{fill:#0A0F25;} + .d2-240483443 .fill-N2{fill:#676C7E;} + .d2-240483443 .fill-N3{fill:#9499AB;} + .d2-240483443 .fill-N4{fill:#CFD2DD;} + .d2-240483443 .fill-N5{fill:#DEE1EB;} + .d2-240483443 .fill-N6{fill:#EEF1F8;} + .d2-240483443 .fill-N7{fill:#FFFFFF;} + .d2-240483443 .fill-B1{fill:#0D32B2;} + .d2-240483443 .fill-B2{fill:#0D32B2;} + .d2-240483443 .fill-B3{fill:#E3E9FD;} + .d2-240483443 .fill-B4{fill:#E3E9FD;} + .d2-240483443 .fill-B5{fill:#EDF0FD;} + .d2-240483443 .fill-B6{fill:#F7F8FE;} + .d2-240483443 .fill-AA2{fill:#4A6FF3;} + .d2-240483443 .fill-AA4{fill:#EDF0FD;} + .d2-240483443 .fill-AA5{fill:#F7F8FE;} + .d2-240483443 .fill-AB4{fill:#EDF0FD;} + .d2-240483443 .fill-AB5{fill:#F7F8FE;} + .d2-240483443 .stroke-N1{stroke:#0A0F25;} + .d2-240483443 .stroke-N2{stroke:#676C7E;} + .d2-240483443 .stroke-N3{stroke:#9499AB;} + .d2-240483443 .stroke-N4{stroke:#CFD2DD;} + .d2-240483443 .stroke-N5{stroke:#DEE1EB;} + .d2-240483443 .stroke-N6{stroke:#EEF1F8;} + .d2-240483443 .stroke-N7{stroke:#FFFFFF;} + .d2-240483443 .stroke-B1{stroke:#0D32B2;} + .d2-240483443 .stroke-B2{stroke:#0D32B2;} + .d2-240483443 .stroke-B3{stroke:#E3E9FD;} + .d2-240483443 .stroke-B4{stroke:#E3E9FD;} + .d2-240483443 .stroke-B5{stroke:#EDF0FD;} + .d2-240483443 .stroke-B6{stroke:#F7F8FE;} + .d2-240483443 .stroke-AA2{stroke:#4A6FF3;} + .d2-240483443 .stroke-AA4{stroke:#EDF0FD;} + .d2-240483443 .stroke-AA5{stroke:#F7F8FE;} + .d2-240483443 .stroke-AB4{stroke:#EDF0FD;} + .d2-240483443 .stroke-AB5{stroke:#F7F8FE;} + .d2-240483443 .background-color-N1{background-color:#0A0F25;} + .d2-240483443 .background-color-N2{background-color:#676C7E;} + .d2-240483443 .background-color-N3{background-color:#9499AB;} + .d2-240483443 .background-color-N4{background-color:#CFD2DD;} + .d2-240483443 .background-color-N5{background-color:#DEE1EB;} + .d2-240483443 .background-color-N6{background-color:#EEF1F8;} + .d2-240483443 .background-color-N7{background-color:#FFFFFF;} + .d2-240483443 .background-color-B1{background-color:#0D32B2;} + .d2-240483443 .background-color-B2{background-color:#0D32B2;} + .d2-240483443 .background-color-B3{background-color:#E3E9FD;} + .d2-240483443 .background-color-B4{background-color:#E3E9FD;} + .d2-240483443 .background-color-B5{background-color:#EDF0FD;} + .d2-240483443 .background-color-B6{background-color:#F7F8FE;} + .d2-240483443 .background-color-AA2{background-color:#4A6FF3;} + .d2-240483443 .background-color-AA4{background-color:#EDF0FD;} + .d2-240483443 .background-color-AA5{background-color:#F7F8FE;} + .d2-240483443 .background-color-AB4{background-color:#EDF0FD;} + .d2-240483443 .background-color-AB5{background-color:#F7F8FE;} + .d2-240483443 .color-N1{color:#0A0F25;} + .d2-240483443 .color-N2{color:#676C7E;} + .d2-240483443 .color-N3{color:#9499AB;} + .d2-240483443 .color-N4{color:#CFD2DD;} + .d2-240483443 .color-N5{color:#DEE1EB;} + .d2-240483443 .color-N6{color:#EEF1F8;} + .d2-240483443 .color-N7{color:#FFFFFF;} + .d2-240483443 .color-B1{color:#0D32B2;} + .d2-240483443 .color-B2{color:#0D32B2;} + .d2-240483443 .color-B3{color:#E3E9FD;} + .d2-240483443 .color-B4{color:#E3E9FD;} + .d2-240483443 .color-B5{color:#EDF0FD;} + .d2-240483443 .color-B6{color:#F7F8FE;} + .d2-240483443 .color-AA2{color:#4A6FF3;} + .d2-240483443 .color-AA4{color:#EDF0FD;} + .d2-240483443 .color-AA5{color:#F7F8FE;} + .d2-240483443 .color-AB4{color:#EDF0FD;} + .d2-240483443 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>outerstartendvolume groupvolume definitionvolume \ No newline at end of file From a2ccb6a3dc093b32eb601aa41c8ae700b7e99e6b Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 2 Jun 2023 15:48:43 -0700 Subject: [PATCH 4/5] also update ShiftDescendants --- d2graph/layout.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/d2graph/layout.go b/d2graph/layout.go index 25b66795b..1bec09adc 100644 --- a/d2graph/layout.go +++ b/d2graph/layout.go @@ -127,11 +127,23 @@ func (obj *Object) ShiftDescendants(dx, dy float64) { p.Y += dy } } else if isSrc { - e.Route[0].X += dx - e.Route[0].Y += dy + if dx == 0 { + e.ShiftStart(dy, false) + } else if dy == 0 { + e.ShiftStart(dx, true) + } else { + e.Route[0].X += dx + e.Route[0].Y += dy + } } else if isDst { - e.Route[len(e.Route)-1].X += dx - e.Route[len(e.Route)-1].Y += dy + if dx == 0 { + e.ShiftEnd(dy, false) + } else if dy == 0 { + e.ShiftEnd(dx, true) + } else { + e.Route[len(e.Route)-1].X += dx + e.Route[len(e.Route)-1].Y += dy + } } if isSrc || isDst { From 171d5357df51994791c4e06056b4544e8934f4cc Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Fri, 2 Jun 2023 15:59:42 -0700 Subject: [PATCH 5/5] changelog --- ci/release/changelogs/next.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 0735e46d5..d38d71c61 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -19,3 +19,4 @@ - When multiple classes are applied changing different attributes of arrowheads, they are all applied instead of only the last one [#1362](https://github.com/terrastruct/d2/pull/1362) - Prevent empty block strings [#1364](https://github.com/terrastruct/d2/pull/1364) +- Fixes dagre mis-aligning a nested shape's connection. [#1370](https://github.com/terrastruct/d2/pull/1370)