diff --git a/d2layouts/d2cycle/layout.go b/d2layouts/d2cycle/layout.go index fcf7b968b..d7306ff1a 100644 --- a/d2layouts/d2cycle/layout.go +++ b/d2layouts/d2cycle/layout.go @@ -1,3 +1,198 @@ +// package d2cycle + +// import ( +// "context" +// "math" + +// "oss.terrastruct.com/d2/d2graph" +// "oss.terrastruct.com/d2/lib/geo" +// "oss.terrastruct.com/d2/lib/label" +// "oss.terrastruct.com/util-go/go2" +// ) + +// const ( +// MIN_RADIUS = 200 +// PADDING = 20 +// MIN_SEGMENT_LEN = 10 +// ARC_STEPS = 30 +// ) + +// func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) error { +// objects := g.Root.ChildrenArray +// if len(objects) == 0 { +// return nil +// } + +// for _, obj := range g.Objects { +// positionLabelsIcons(obj) +// } + +// radius := calculateRadius(objects) +// positionObjects(objects, radius) + +// for _, edge := range g.Edges { +// createCircularArc(edge) +// } + +// return nil +// } + +// func calculateRadius(objects []*d2graph.Object) float64 { +// numObjects := float64(len(objects)) +// maxSize := 0.0 +// for _, obj := range objects { +// size := math.Max(obj.Box.Width, obj.Box.Height) +// maxSize = math.Max(maxSize, size) +// } +// minRadius := (maxSize/2.0 + PADDING) / math.Sin(math.Pi/numObjects) +// return math.Max(minRadius, MIN_RADIUS) +// } + +// func positionObjects(objects []*d2graph.Object, radius float64) { +// numObjects := float64(len(objects)) +// angleOffset := -math.Pi / 2 + +// for i, obj := range objects { +// angle := angleOffset + (2*math.Pi*float64(i)/numObjects) +// x := radius * math.Cos(angle) +// y := radius * math.Sin(angle) + +// obj.TopLeft = geo.NewPoint( +// x-obj.Box.Width/2, +// y-obj.Box.Height/2, +// ) +// } +// } + +// func createCircularArc(edge *d2graph.Edge) { +// if edge.Src == nil || edge.Dst == nil { +// return +// } + +// srcCenter := edge.Src.Center() +// dstCenter := edge.Dst.Center() + +// srcAngle := math.Atan2(srcCenter.Y, srcCenter.X) +// dstAngle := math.Atan2(dstCenter.Y, dstCenter.X) +// if dstAngle < srcAngle { +// dstAngle += 2 * math.Pi +// } + +// arcRadius := math.Hypot(srcCenter.X, srcCenter.Y) + +// path := make([]*geo.Point, 0, ARC_STEPS+1) +// for i := 0; i <= ARC_STEPS; i++ { +// t := float64(i) / float64(ARC_STEPS) +// angle := srcAngle + t*(dstAngle-srcAngle) +// x := arcRadius * math.Cos(angle) +// y := arcRadius * math.Sin(angle) +// path = append(path, geo.NewPoint(x, y)) +// } +// path[0] = srcCenter +// path[len(path)-1] = dstCenter + +// startIndex, newSrc := clampPointOutsideBox(edge.Src.Box, path, 0) +// endIndex, newDst := clampPointOutsideBoxReverse(edge.Dst.Box, path, len(path)-1) + +// path[0] = newSrc +// path[len(path)-1] = newDst + +// edge.Route = path[startIndex : endIndex+1] +// edge.IsCurve = true +// } + +// func clampPointOutsideBox(box *geo.Box, path []*geo.Point, startIdx int) (int, *geo.Point) { +// if startIdx >= len(path)-1 { +// return startIdx, path[startIdx] +// } +// if !boxContains(box, path[startIdx]) { +// return startIdx, path[startIdx] +// } + +// for i := startIdx + 1; i < len(path); i++ { +// if boxContains(box, path[i]) { +// continue +// } +// seg := geo.NewSegment(path[i-1], path[i]) +// inters := boxIntersections(box, *seg) +// if len(inters) > 0 { +// return i, inters[0] +// } +// return i, path[i] +// } +// last := len(path) - 1 +// return last, path[last] +// } + +// func clampPointOutsideBoxReverse(box *geo.Box, path []*geo.Point, endIdx int) (int, *geo.Point) { +// if endIdx <= 0 { +// return endIdx, path[endIdx] +// } +// if !boxContains(box, path[endIdx]) { +// return endIdx, path[endIdx] +// } + +// for j := endIdx - 1; j >= 0; j-- { +// if boxContains(box, path[j]) { +// continue +// } +// seg := geo.NewSegment(path[j], path[j+1]) +// inters := boxIntersections(box, *seg) +// if len(inters) > 0 { +// return j, inters[0] +// } +// return j, path[j] +// } +// return 0, path[0] +// } + +// func boxContains(b *geo.Box, p *geo.Point) bool { +// return p.X >= b.TopLeft.X && +// p.X <= b.TopLeft.X+b.Width && +// p.Y >= b.TopLeft.Y && +// p.Y <= b.TopLeft.Y+b.Height +// } + +// func boxIntersections(b *geo.Box, seg geo.Segment) []*geo.Point { +// return b.Intersections(seg) +// } + +// func positionLabelsIcons(obj *d2graph.Object) { +// if obj.Icon != nil && obj.IconPosition == nil { +// if len(obj.ChildrenArray) > 0 { +// obj.IconPosition = go2.Pointer(label.OutsideTopLeft.String()) +// if obj.LabelPosition == nil { +// obj.LabelPosition = go2.Pointer(label.OutsideTopRight.String()) +// return +// } +// } else if obj.SQLTable != nil || obj.Class != nil || obj.Language != "" { +// obj.IconPosition = go2.Pointer(label.OutsideTopLeft.String()) +// } else { +// obj.IconPosition = go2.Pointer(label.InsideMiddleCenter.String()) +// } +// } + +// if obj.HasLabel() && obj.LabelPosition == nil { +// if len(obj.ChildrenArray) > 0 { +// obj.LabelPosition = go2.Pointer(label.OutsideTopCenter.String()) +// } else if obj.HasOutsideBottomLabel() { +// obj.LabelPosition = go2.Pointer(label.OutsideBottomCenter.String()) +// } else if obj.Icon != nil { +// obj.LabelPosition = go2.Pointer(label.InsideTopCenter.String()) +// } else { +// obj.LabelPosition = go2.Pointer(label.InsideMiddleCenter.String()) +// } + +// if float64(obj.LabelDimensions.Width) > obj.Width || +// float64(obj.LabelDimensions.Height) > obj.Height { +// if len(obj.ChildrenArray) > 0 { +// obj.LabelPosition = go2.Pointer(label.OutsideTopCenter.String()) +// } else { +// obj.LabelPosition = go2.Pointer(label.OutsideBottomCenter.String()) +// } +// } +// } +// } package d2cycle import ( @@ -64,6 +259,9 @@ func positionObjects(objects []*d2graph.Object, radius float64) { } } +// createCircularArc computes an arc along a circle from the source to destination, +// then computes the exact intersection points between a ray from the object's center +// and its bounding box. This ensures that the arrow precisely touches the boundary. func createCircularArc(edge *d2graph.Edge) { if edge.Src == nil || edge.Dst == nil { return @@ -78,9 +276,10 @@ func createCircularArc(edge *d2graph.Edge) { dstAngle += 2 * math.Pi } - // Use the source center's distance for the arc radius. + // Here we use the source center's distance as the arc radius. arcRadius := math.Hypot(srcCenter.X, srcCenter.Y) + // Sample points along the circular arc. path := make([]*geo.Point, 0, ARC_STEPS+1) for i := 0; i <= ARC_STEPS; i++ { t := float64(i) / float64(ARC_STEPS) @@ -89,80 +288,51 @@ func createCircularArc(edge *d2graph.Edge) { y := arcRadius * math.Sin(angle) path = append(path, geo.NewPoint(x, y)) } - path[0] = srcCenter - path[len(path)-1] = dstCenter - - startIndex, newSrc := clampPointOutsideBox(edge.Src.Box, path, 0) - endIndex, newDst := clampPointOutsideBoxReverse(edge.Dst.Box, path, len(path)-1) + // Instead of relying on iterative clamping, we compute exact intersection points. + // For the source, the ray is from the center toward the second sample point. + newSrc := rayRectangleIntersection(srcCenter, edge.Src.Box, path[1].X-srcCenter.X, path[1].Y-srcCenter.Y) + // For the destination, the ray is from the center in the direction opposite to the second-to-last sample. + newDst := rayRectangleIntersection(dstCenter, edge.Dst.Box, dstCenter.X-path[len(path)-2].X, dstCenter.Y-path[len(path)-2].Y) path[0] = newSrc path[len(path)-1] = newDst - edge.Route = path[startIndex : endIndex+1] + edge.Route = path edge.IsCurve = true } -func clampPointOutsideBox(box *geo.Box, path []*geo.Point, startIdx int) (int, *geo.Point) { - if startIdx >= len(path)-1 { - return startIdx, path[startIdx] - } - if !boxContains(box, path[startIdx]) { - return startIdx, path[startIdx] +// rayRectangleIntersection computes the exact intersection point of a ray starting at 'center' +// with direction (dx, dy) and the boundary of an axis-aligned rectangle 'box'. +// The rectangle is defined by its TopLeft corner, width, and height. +func rayRectangleIntersection(center *geo.Point, box *geo.Box, dx, dy float64) *geo.Point { + L := box.TopLeft.X + R := box.TopLeft.X + box.Width + T := box.TopLeft.Y + B := box.TopLeft.Y + box.Height + + var tX, tY float64 + if dx > 0 { + tX = (R - center.X) / dx + } else if dx < 0 { + tX = (L - center.X) / dx + } else { + tX = math.Inf(1) } - for i := startIdx + 1; i < len(path); i++ { - if boxContains(box, path[i]) { - continue - } - // Refine the intersection between the last inside and the first outside point. - refined := refineIntersection(box, path[i-1], path[i]) - return i, refined - } - return len(path) - 1, path[len(path)-1] -} - -func clampPointOutsideBoxReverse(box *geo.Box, path []*geo.Point, endIdx int) (int, *geo.Point) { - if endIdx <= 0 { - return endIdx, path[endIdx] - } - if !boxContains(box, path[endIdx]) { - return endIdx, path[endIdx] + if dy > 0 { + tY = (B - center.Y) / dy + } else if dy < 0 { + tY = (T - center.Y) / dy + } else { + tY = math.Inf(1) } - for j := endIdx - 1; j >= 0; j-- { - if boxContains(box, path[j]) { - continue - } - refined := refineIntersection(box, path[j], path[j+1]) - return j, refined + t := tX + if tY < t { + t = tY } - return 0, path[0] -} -func refineIntersection(box *geo.Box, pInside, pOutside *geo.Point) *geo.Point { - const epsilon = 1e-6 - a := pInside - b := pOutside - for math.Hypot(b.X-a.X, b.Y-a.Y) > epsilon { - mid := geo.NewPoint((a.X+b.X)/2, (a.Y+b.Y)/2) - if boxContains(box, mid) { - a = mid - } else { - b = mid - } - } - return geo.NewPoint((a.X+b.X)/2, (a.Y+b.Y)/2) -} - -func boxContains(b *geo.Box, p *geo.Point) bool { - return p.X >= b.TopLeft.X && - p.X <= b.TopLeft.X+b.Width && - p.Y >= b.TopLeft.Y && - p.Y <= b.TopLeft.Y+b.Height -} - -func boxIntersections(b *geo.Box, seg geo.Segment) []*geo.Point { - return b.Intersections(seg) + return geo.NewPoint(center.X+dx*t, center.Y+dy*t) } func positionLabelsIcons(obj *d2graph.Object) { diff --git a/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json b/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json index 104df56cc..f2104c95c 100644 --- a/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json +++ b/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json @@ -539,6 +539,18 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 26.5, + "y": -199.30599975585938 + }, + { + "x": 10.467000007629395, + "y": -199.72500610351562 + }, + { + "x": 20.905000686645508, + "y": -198.9040069580078 + }, { "x": 31.285999298095703, "y": -197.53700256347656 @@ -634,6 +646,22 @@ { "x": 195.62899780273438, "y": -41.582000732421875 + }, + { + "x": 197.53700256347656, + "y": -31.285999298095703 + }, + { + "x": 198.9040069580078, + "y": -20.905000686645508 + }, + { + "x": 199.72500610351562, + "y": -10.467000007629395 + }, + { + "x": 200.86399841308594, + "y": 33 } ], "isCurve": true, @@ -667,6 +695,22 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 199.13499450683594, + "y": 33 + }, + { + "x": 199.72500610351562, + "y": 10.467000007629395 + }, + { + "x": 198.9040069580078, + "y": 20.905000686645508 + }, + { + "x": 197.53700256347656, + "y": 31.285999298095703 + }, { "x": 195.62899780273438, "y": 41.582000732421875 @@ -762,6 +806,18 @@ { "x": 31.285999298095703, "y": 197.53700256347656 + }, + { + "x": 20.905000686645508, + "y": 198.9040069580078 + }, + { + "x": 10.467000007629395, + "y": 199.72500610351562 + }, + { + "x": -26.499000549316406, + "y": 200.6929931640625 } ], "isCurve": true, @@ -795,6 +851,18 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": -26.499000549316406, + "y": 199.30599975585938 + }, + { + "x": -10.467000007629395, + "y": 199.72500610351562 + }, + { + "x": -20.905000686645508, + "y": 198.9040069580078 + }, { "x": -31.285999298095703, "y": 197.53700256347656 @@ -890,6 +958,22 @@ { "x": -195.62899780273438, "y": 41.582000732421875 + }, + { + "x": -197.53700256347656, + "y": 31.285999298095703 + }, + { + "x": -198.9040069580078, + "y": 20.905000686645508 + }, + { + "x": -199.72500610351562, + "y": 10.467000007629395 + }, + { + "x": -200.86399841308594, + "y": -32.999000549316406 } ], "isCurve": true, @@ -923,6 +1007,14 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 539.5, + "y": -149.07400512695312 + }, + { + "x": 526.9509887695312, + "y": -149.51199340820312 + }, { "x": 540.833984375, "y": -148.05299377441406 @@ -1026,6 +1118,18 @@ { "x": 703.2109985351562, "y": 111.8030014038086 + }, + { + "x": 698.4359741210938, + "y": 124.9209976196289 + }, + { + "x": 692.7579956054688, + "y": 137.6739959716797 + }, + { + "x": 668.6580200195312, + "y": 182.99899291992188 } ], "isCurve": true, @@ -1059,6 +1163,18 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 665.583984375, + "y": 182.99899291992188 + }, + { + "x": 678.8070068359375, + "y": 161.83799743652344 + }, + { + "x": 670.6019897460938, + "y": 173.1320037841797 + }, { "x": 661.6279907226562, "y": 183.8260040283203 @@ -1158,6 +1274,18 @@ { "x": 364.3710021972656, "y": 183.8260040283203 + }, + { + "x": 355.3970031738281, + "y": 173.1320037841797 + }, + { + "x": 347.1919860839844, + "y": 161.83799743652344 + }, + { + "x": 319.17401123046875, + "y": 117 } ], "isCurve": true, @@ -1191,6 +1319,14 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 998.5, + "y": -198.61099243164062 + }, + { + "x": 992.905029296875, + "y": -198.9040069580078 + }, { "x": 1013.5819702148438, "y": -195.62899780273438 @@ -1298,6 +1434,14 @@ { "x": 1013.5819702148438, "y": 195.62899780273438 + }, + { + "x": 992.905029296875, + "y": 198.9040069580078 + }, + { + "x": 945.5, + "y": 201.38800048828125 } ], "isCurve": true, diff --git a/e2etests/testdata/txtar/cycle-diagram/dagre/sketch.exp.svg b/e2etests/testdata/txtar/cycle-diagram/dagre/sketch.exp.svg index ecc912981..9d9c1e229 100644 --- a/e2etests/testdata/txtar/cycle-diagram/dagre/sketch.exp.svg +++ b/e2etests/testdata/txtar/cycle-diagram/dagre/sketch.exp.svg @@ -1,9 +1,9 @@ -abcdabcab + .d2-3910026144 .fill-N1{fill:#0A0F25;} + .d2-3910026144 .fill-N2{fill:#676C7E;} + .d2-3910026144 .fill-N3{fill:#9499AB;} + .d2-3910026144 .fill-N4{fill:#CFD2DD;} + .d2-3910026144 .fill-N5{fill:#DEE1EB;} + .d2-3910026144 .fill-N6{fill:#EEF1F8;} + .d2-3910026144 .fill-N7{fill:#FFFFFF;} + .d2-3910026144 .fill-B1{fill:#0D32B2;} + .d2-3910026144 .fill-B2{fill:#0D32B2;} + .d2-3910026144 .fill-B3{fill:#E3E9FD;} + .d2-3910026144 .fill-B4{fill:#E3E9FD;} + .d2-3910026144 .fill-B5{fill:#EDF0FD;} + .d2-3910026144 .fill-B6{fill:#F7F8FE;} + .d2-3910026144 .fill-AA2{fill:#4A6FF3;} + .d2-3910026144 .fill-AA4{fill:#EDF0FD;} + .d2-3910026144 .fill-AA5{fill:#F7F8FE;} + .d2-3910026144 .fill-AB4{fill:#EDF0FD;} + .d2-3910026144 .fill-AB5{fill:#F7F8FE;} + .d2-3910026144 .stroke-N1{stroke:#0A0F25;} + .d2-3910026144 .stroke-N2{stroke:#676C7E;} + .d2-3910026144 .stroke-N3{stroke:#9499AB;} + .d2-3910026144 .stroke-N4{stroke:#CFD2DD;} + .d2-3910026144 .stroke-N5{stroke:#DEE1EB;} + .d2-3910026144 .stroke-N6{stroke:#EEF1F8;} + .d2-3910026144 .stroke-N7{stroke:#FFFFFF;} + .d2-3910026144 .stroke-B1{stroke:#0D32B2;} + .d2-3910026144 .stroke-B2{stroke:#0D32B2;} + .d2-3910026144 .stroke-B3{stroke:#E3E9FD;} + .d2-3910026144 .stroke-B4{stroke:#E3E9FD;} + .d2-3910026144 .stroke-B5{stroke:#EDF0FD;} + .d2-3910026144 .stroke-B6{stroke:#F7F8FE;} + .d2-3910026144 .stroke-AA2{stroke:#4A6FF3;} + .d2-3910026144 .stroke-AA4{stroke:#EDF0FD;} + .d2-3910026144 .stroke-AA5{stroke:#F7F8FE;} + .d2-3910026144 .stroke-AB4{stroke:#EDF0FD;} + .d2-3910026144 .stroke-AB5{stroke:#F7F8FE;} + .d2-3910026144 .background-color-N1{background-color:#0A0F25;} + .d2-3910026144 .background-color-N2{background-color:#676C7E;} + .d2-3910026144 .background-color-N3{background-color:#9499AB;} + .d2-3910026144 .background-color-N4{background-color:#CFD2DD;} + .d2-3910026144 .background-color-N5{background-color:#DEE1EB;} + .d2-3910026144 .background-color-N6{background-color:#EEF1F8;} + .d2-3910026144 .background-color-N7{background-color:#FFFFFF;} + .d2-3910026144 .background-color-B1{background-color:#0D32B2;} + .d2-3910026144 .background-color-B2{background-color:#0D32B2;} + .d2-3910026144 .background-color-B3{background-color:#E3E9FD;} + .d2-3910026144 .background-color-B4{background-color:#E3E9FD;} + .d2-3910026144 .background-color-B5{background-color:#EDF0FD;} + .d2-3910026144 .background-color-B6{background-color:#F7F8FE;} + .d2-3910026144 .background-color-AA2{background-color:#4A6FF3;} + .d2-3910026144 .background-color-AA4{background-color:#EDF0FD;} + .d2-3910026144 .background-color-AA5{background-color:#F7F8FE;} + .d2-3910026144 .background-color-AB4{background-color:#EDF0FD;} + .d2-3910026144 .background-color-AB5{background-color:#F7F8FE;} + .d2-3910026144 .color-N1{color:#0A0F25;} + .d2-3910026144 .color-N2{color:#676C7E;} + .d2-3910026144 .color-N3{color:#9499AB;} + .d2-3910026144 .color-N4{color:#CFD2DD;} + .d2-3910026144 .color-N5{color:#DEE1EB;} + .d2-3910026144 .color-N6{color:#EEF1F8;} + .d2-3910026144 .color-N7{color:#FFFFFF;} + .d2-3910026144 .color-B1{color:#0D32B2;} + .d2-3910026144 .color-B2{color:#0D32B2;} + .d2-3910026144 .color-B3{color:#E3E9FD;} + .d2-3910026144 .color-B4{color:#E3E9FD;} + .d2-3910026144 .color-B5{color:#EDF0FD;} + .d2-3910026144 .color-B6{color:#F7F8FE;} + .d2-3910026144 .color-AA2{color:#4A6FF3;} + .d2-3910026144 .color-AA4{color:#EDF0FD;} + .d2-3910026144 .color-AA5{color:#F7F8FE;} + .d2-3910026144 .color-AB4{color:#EDF0FD;} + .d2-3910026144 .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-d2-3910026144);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-3910026144);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-3910026144);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-3910026144);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-3910026144);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-3910026144);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-3910026144);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-3910026144);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>abcdabcab diff --git a/e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json b/e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json index ad3f518e0..37e4ae23c 100644 --- a/e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json +++ b/e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json @@ -539,6 +539,18 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 38.5, + "y": -187.30599975585938 + }, + { + "x": 22.466999053955078, + "y": -187.72500610351562 + }, + { + "x": 32.904998779296875, + "y": -186.9040069580078 + }, { "x": 43.2859992980957, "y": -185.53700256347656 @@ -634,6 +646,22 @@ { "x": 207.62899780273438, "y": -29.582000732421875 + }, + { + "x": 209.53700256347656, + "y": -19.285999298095703 + }, + { + "x": 210.9040069580078, + "y": -8.904999732971191 + }, + { + "x": 211.72500610351562, + "y": 1.531999945640564 + }, + { + "x": 212.86399841308594, + "y": 45 } ], "isCurve": true, @@ -667,6 +695,22 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 211.13499450683594, + "y": 45 + }, + { + "x": 211.72500610351562, + "y": 22.466999053955078 + }, + { + "x": 210.9040069580078, + "y": 32.904998779296875 + }, + { + "x": 209.53700256347656, + "y": 43.2859992980957 + }, { "x": 207.62899780273438, "y": 53.582000732421875 @@ -762,6 +806,18 @@ { "x": 43.2859992980957, "y": 209.53700256347656 + }, + { + "x": 32.904998779296875, + "y": 210.9040069580078 + }, + { + "x": 22.466999053955078, + "y": 211.72500610351562 + }, + { + "x": -14.49899959564209, + "y": 212.6929931640625 } ], "isCurve": true, @@ -795,6 +851,18 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": -14.49899959564209, + "y": 211.30599975585938 + }, + { + "x": 1.531999945640564, + "y": 211.72500610351562 + }, + { + "x": -8.904999732971191, + "y": 210.9040069580078 + }, { "x": -19.285999298095703, "y": 209.53700256347656 @@ -890,6 +958,22 @@ { "x": -183.62899780273438, "y": 53.582000732421875 + }, + { + "x": -185.53700256347656, + "y": 43.2859992980957 + }, + { + "x": -186.9040069580078, + "y": 32.904998779296875 + }, + { + "x": -187.72500610351562, + "y": 22.466999053955078 + }, + { + "x": -188.86399841308594, + "y": -20.999000549316406 } ], "isCurve": true, @@ -923,6 +1007,14 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 512, + "y": -137.07400512695312 + }, + { + "x": 499.45098876953125, + "y": -137.51199340820312 + }, { "x": 513.333984375, "y": -136.05299377441406 @@ -1026,6 +1118,18 @@ { "x": 675.7109985351562, "y": 123.8030014038086 + }, + { + "x": 670.9359741210938, + "y": 136.92100524902344 + }, + { + "x": 665.2579956054688, + "y": 149.6739959716797 + }, + { + "x": 641.1580200195312, + "y": 194.99899291992188 } ], "isCurve": true, @@ -1059,6 +1163,18 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 638.083984375, + "y": 194.99899291992188 + }, + { + "x": 651.3070068359375, + "y": 173.83799743652344 + }, + { + "x": 643.1019897460938, + "y": 185.1320037841797 + }, { "x": 634.1279907226562, "y": 195.8260040283203 @@ -1158,6 +1274,18 @@ { "x": 336.8710021972656, "y": 195.8260040283203 + }, + { + "x": 327.8970031738281, + "y": 185.1320037841797 + }, + { + "x": 319.6919860839844, + "y": 173.83799743652344 + }, + { + "x": 291.67401123046875, + "y": 129 } ], "isCurve": true, @@ -1191,6 +1319,14 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 931.4099731445312, + "y": -186.61099243164062 + }, + { + "x": 925.8150024414062, + "y": -186.9040069580078 + }, { "x": 946.4920043945312, "y": -183.62899780273438 @@ -1298,6 +1434,14 @@ { "x": 946.4920043945312, "y": 207.62899780273438 + }, + { + "x": 925.8150024414062, + "y": 210.9040069580078 + }, + { + "x": 878.4099731445312, + "y": 213.38800048828125 } ], "isCurve": true, diff --git a/e2etests/testdata/txtar/cycle-diagram/elk/sketch.exp.svg b/e2etests/testdata/txtar/cycle-diagram/elk/sketch.exp.svg index f5afaee6a..44b8e6cf7 100644 --- a/e2etests/testdata/txtar/cycle-diagram/elk/sketch.exp.svg +++ b/e2etests/testdata/txtar/cycle-diagram/elk/sketch.exp.svg @@ -1,9 +1,9 @@ -abcdabcab + .d2-451256407 .fill-N1{fill:#0A0F25;} + .d2-451256407 .fill-N2{fill:#676C7E;} + .d2-451256407 .fill-N3{fill:#9499AB;} + .d2-451256407 .fill-N4{fill:#CFD2DD;} + .d2-451256407 .fill-N5{fill:#DEE1EB;} + .d2-451256407 .fill-N6{fill:#EEF1F8;} + .d2-451256407 .fill-N7{fill:#FFFFFF;} + .d2-451256407 .fill-B1{fill:#0D32B2;} + .d2-451256407 .fill-B2{fill:#0D32B2;} + .d2-451256407 .fill-B3{fill:#E3E9FD;} + .d2-451256407 .fill-B4{fill:#E3E9FD;} + .d2-451256407 .fill-B5{fill:#EDF0FD;} + .d2-451256407 .fill-B6{fill:#F7F8FE;} + .d2-451256407 .fill-AA2{fill:#4A6FF3;} + .d2-451256407 .fill-AA4{fill:#EDF0FD;} + .d2-451256407 .fill-AA5{fill:#F7F8FE;} + .d2-451256407 .fill-AB4{fill:#EDF0FD;} + .d2-451256407 .fill-AB5{fill:#F7F8FE;} + .d2-451256407 .stroke-N1{stroke:#0A0F25;} + .d2-451256407 .stroke-N2{stroke:#676C7E;} + .d2-451256407 .stroke-N3{stroke:#9499AB;} + .d2-451256407 .stroke-N4{stroke:#CFD2DD;} + .d2-451256407 .stroke-N5{stroke:#DEE1EB;} + .d2-451256407 .stroke-N6{stroke:#EEF1F8;} + .d2-451256407 .stroke-N7{stroke:#FFFFFF;} + .d2-451256407 .stroke-B1{stroke:#0D32B2;} + .d2-451256407 .stroke-B2{stroke:#0D32B2;} + .d2-451256407 .stroke-B3{stroke:#E3E9FD;} + .d2-451256407 .stroke-B4{stroke:#E3E9FD;} + .d2-451256407 .stroke-B5{stroke:#EDF0FD;} + .d2-451256407 .stroke-B6{stroke:#F7F8FE;} + .d2-451256407 .stroke-AA2{stroke:#4A6FF3;} + .d2-451256407 .stroke-AA4{stroke:#EDF0FD;} + .d2-451256407 .stroke-AA5{stroke:#F7F8FE;} + .d2-451256407 .stroke-AB4{stroke:#EDF0FD;} + .d2-451256407 .stroke-AB5{stroke:#F7F8FE;} + .d2-451256407 .background-color-N1{background-color:#0A0F25;} + .d2-451256407 .background-color-N2{background-color:#676C7E;} + .d2-451256407 .background-color-N3{background-color:#9499AB;} + .d2-451256407 .background-color-N4{background-color:#CFD2DD;} + .d2-451256407 .background-color-N5{background-color:#DEE1EB;} + .d2-451256407 .background-color-N6{background-color:#EEF1F8;} + .d2-451256407 .background-color-N7{background-color:#FFFFFF;} + .d2-451256407 .background-color-B1{background-color:#0D32B2;} + .d2-451256407 .background-color-B2{background-color:#0D32B2;} + .d2-451256407 .background-color-B3{background-color:#E3E9FD;} + .d2-451256407 .background-color-B4{background-color:#E3E9FD;} + .d2-451256407 .background-color-B5{background-color:#EDF0FD;} + .d2-451256407 .background-color-B6{background-color:#F7F8FE;} + .d2-451256407 .background-color-AA2{background-color:#4A6FF3;} + .d2-451256407 .background-color-AA4{background-color:#EDF0FD;} + .d2-451256407 .background-color-AA5{background-color:#F7F8FE;} + .d2-451256407 .background-color-AB4{background-color:#EDF0FD;} + .d2-451256407 .background-color-AB5{background-color:#F7F8FE;} + .d2-451256407 .color-N1{color:#0A0F25;} + .d2-451256407 .color-N2{color:#676C7E;} + .d2-451256407 .color-N3{color:#9499AB;} + .d2-451256407 .color-N4{color:#CFD2DD;} + .d2-451256407 .color-N5{color:#DEE1EB;} + .d2-451256407 .color-N6{color:#EEF1F8;} + .d2-451256407 .color-N7{color:#FFFFFF;} + .d2-451256407 .color-B1{color:#0D32B2;} + .d2-451256407 .color-B2{color:#0D32B2;} + .d2-451256407 .color-B3{color:#E3E9FD;} + .d2-451256407 .color-B4{color:#E3E9FD;} + .d2-451256407 .color-B5{color:#EDF0FD;} + .d2-451256407 .color-B6{color:#F7F8FE;} + .d2-451256407 .color-AA2{color:#4A6FF3;} + .d2-451256407 .color-AA4{color:#EDF0FD;} + .d2-451256407 .color-AA5{color:#F7F8FE;} + .d2-451256407 .color-AB4{color:#EDF0FD;} + .d2-451256407 .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-d2-451256407);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-451256407);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-451256407);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-451256407);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-451256407);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-451256407);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-451256407);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-451256407);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>abcdabcab