From 3c1be1ee2ad8198d4c1db19db4fb82f335280aee Mon Sep 17 00:00:00 2001 From: Mayank Mohapatra <125661248+Mayank77maruti@users.noreply.github.com> Date: Sat, 22 Feb 2025 10:32:46 +0000 Subject: [PATCH] try --- d2layouts/d2cycle/layout.go | 341 ++++++++++-------- .../txtar/cycle-diagram/dagre/board.exp.json | 48 +++ .../txtar/cycle-diagram/dagre/sketch.exp.svg | 152 ++++---- .../txtar/cycle-diagram/elk/board.exp.json | 48 +++ .../txtar/cycle-diagram/elk/sketch.exp.svg | 152 ++++---- 5 files changed, 440 insertions(+), 301 deletions(-) diff --git a/d2layouts/d2cycle/layout.go b/d2layouts/d2cycle/layout.go index 940a2ff09..e8eeeba11 100644 --- a/d2layouts/d2cycle/layout.go +++ b/d2layouts/d2cycle/layout.go @@ -1,195 +1,238 @@ package d2cycle import ( - "context" - "math" + "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" + "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 + MIN_RADIUS = 200 + PADDING = 20 + MIN_SEGMENT_LEN = 10 + ARC_STEPS = 30 + EPSILON = 1e-10 // Small value for floating point comparisons ) func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) error { - objects := g.Root.ChildrenArray - if len(objects) == 0 { - return nil - } + objects := g.Root.ChildrenArray + if len(objects) == 0 { + return nil + } - for _, obj := range g.Objects { - positionLabelsIcons(obj) - } + for _, obj := range g.Objects { + positionLabelsIcons(obj) + } - radius := calculateRadius(objects) - positionObjects(objects, radius) + radius := calculateRadius(objects) + positionObjects(objects, radius) - for _, edge := range g.Edges { - createCircularArc(edge) - } + for _, edge := range g.Edges { + createPreciseCircularArc(edge) + } - return nil + 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) + 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 + 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) + 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, - ) - } + 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 - } +func createPreciseCircularArc(edge *d2graph.Edge) { + if edge.Src == nil || edge.Dst == nil { + return + } - srcCenter := edge.Src.Center() - dstCenter := edge.Dst.Center() + 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 - } + // Calculate angles in the circular layout + 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) + 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 + // Generate initial path points + 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)) + } - startIndex, newSrc := clampPointOutsideBox(edge.Src.Box, path, 0) - endIndex, newDst := clampPointOutsideBoxReverse(edge.Dst.Box, path, len(path)-1) + // Find precise intersection points + srcIntersection := findPreciseBoxIntersection(edge.Src.Box, path[0], path[1]) + dstIntersection := findPreciseBoxIntersection(edge.Dst.Box, path[len(path)-1], path[len(path)-2]) - path[0] = newSrc - path[len(path)-1] = newDst + // Update path endpoints with precise intersections + path[0] = srcIntersection + path[len(path)-1] = dstIntersection - edge.Route = path[startIndex : endIndex+1] - edge.IsCurve = true + // Remove any points that might be inside the boxes + startIdx := 0 + endIdx := len(path) - 1 + + for i := 1; i < len(path)-1; i++ { + if boxContains(edge.Src.Box, path[i]) { + startIdx = i + } + if boxContains(edge.Dst.Box, path[i]) { + endIdx = i + break + } + } + + edge.Route = path[startIdx:endIdx+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] - } +func findPreciseBoxIntersection(box *geo.Box, p1, p2 *geo.Point) *geo.Point { + // Define box edges as line segments + edges := []geo.Segment{ + // Top edge + *geo.NewSegment( + geo.NewPoint(box.TopLeft.X, box.TopLeft.Y), + geo.NewPoint(box.TopLeft.X+box.Width, box.TopLeft.Y), + ), + // Right edge + *geo.NewSegment( + geo.NewPoint(box.TopLeft.X+box.Width, box.TopLeft.Y), + geo.NewPoint(box.TopLeft.X+box.Width, box.TopLeft.Y+box.Height), + ), + // Bottom edge + *geo.NewSegment( + geo.NewPoint(box.TopLeft.X, box.TopLeft.Y+box.Height), + geo.NewPoint(box.TopLeft.X+box.Width, box.TopLeft.Y+box.Height), + ), + // Left edge + *geo.NewSegment( + geo.NewPoint(box.TopLeft.X, box.TopLeft.Y), + geo.NewPoint(box.TopLeft.X, box.TopLeft.Y+box.Height), + ), + } - 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] + // Line segment from p1 to p2 + line := *geo.NewSegment(p1, p2) + + // Find the intersection point closest to p1 + var closestIntersection *geo.Point + minDist := math.MaxFloat64 + + for _, edge := range edges { + if intersection := findSegmentIntersection(line, edge); intersection != nil { + dist := math.Hypot( + intersection.X-p1.X, + intersection.Y-p1.Y, + ) + if dist < minDist { + minDist = dist + closestIntersection = intersection + } + } + } + + if closestIntersection != nil { + return closestIntersection + } + return p1 } -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] - } +func findSegmentIntersection(s1, s2 geo.Segment) *geo.Point { + // Calculate the intersection of two line segments using parametric equations + x1, y1 := s1.Start.X, s1.Start.Y + x2, y2 := s1.End.X, s1.End.Y + x3, y3 := s2.Start.X, s2.Start.Y + x4, y4 := s2.End.X, s2.End.Y - 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] + denominator := (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4) + if math.Abs(denominator) < EPSILON { + return nil + } + + t := ((x1-x3)*(y3-y4) - (y1-y3)*(x3-x4)) / denominator + u := -((x1-x2)*(y1-y3) - (y1-y2)*(x1-x3)) / denominator + + if t >= 0 && t <= 1 && u >= 0 && u <= 1 { + x := x1 + t*(x2-x1) + y := y1 + t*(y2-y1) + return geo.NewPoint(x, y) + } + + return nil } 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 p.X >= b.TopLeft.X-EPSILON && + p.X <= b.TopLeft.X+b.Width+EPSILON && + p.Y >= b.TopLeft.Y-EPSILON && + p.Y <= b.TopLeft.Y+b.Height+EPSILON } 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.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 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()) - } - } - } + 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()) + } + } + } } \ No newline at end of file diff --git a/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json b/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json index 104df56cc..1a8d4250a 100644 --- a/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json +++ b/e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json @@ -539,6 +539,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 20.905000686645508, + "y": -198.9040069580078 + }, { "x": 31.285999298095703, "y": -197.53700256347656 @@ -634,6 +638,10 @@ { "x": 195.62899780273438, "y": -41.582000732421875 + }, + { + "x": 197.53700256347656, + "y": -31.285999298095703 } ], "isCurve": true, @@ -667,6 +675,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 197.53700256347656, + "y": 31.285999298095703 + }, { "x": 195.62899780273438, "y": 41.582000732421875 @@ -762,6 +774,10 @@ { "x": 31.285999298095703, "y": 197.53700256347656 + }, + { + "x": 20.905000686645508, + "y": 198.9040069580078 } ], "isCurve": true, @@ -795,6 +811,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": -20.905000686645508, + "y": 198.9040069580078 + }, { "x": -31.285999298095703, "y": 197.53700256347656 @@ -890,6 +910,10 @@ { "x": -195.62899780273438, "y": 41.582000732421875 + }, + { + "x": -197.53700256347656, + "y": 31.285999298095703 } ], "isCurve": true, @@ -923,6 +947,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 526.9509887695312, + "y": -149.51199340820312 + }, { "x": 540.833984375, "y": -148.05299377441406 @@ -1026,6 +1054,10 @@ { "x": 703.2109985351562, "y": 111.8030014038086 + }, + { + "x": 698.4359741210938, + "y": 124.9209976196289 } ], "isCurve": true, @@ -1059,6 +1091,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 670.6019897460938, + "y": 173.1320037841797 + }, { "x": 661.6279907226562, "y": 183.8260040283203 @@ -1158,6 +1194,10 @@ { "x": 364.3710021972656, "y": 183.8260040283203 + }, + { + "x": 355.3970031738281, + "y": 173.1320037841797 } ], "isCurve": true, @@ -1191,6 +1231,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 992.905029296875, + "y": -198.9040069580078 + }, { "x": 1013.5819702148438, "y": -195.62899780273438 @@ -1298,6 +1342,10 @@ { "x": 1013.5819702148438, "y": 195.62899780273438 + }, + { + "x": 992.905029296875, + "y": 198.9040069580078 } ], "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..18ebdee8a 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-363313595 .fill-N1{fill:#0A0F25;} + .d2-363313595 .fill-N2{fill:#676C7E;} + .d2-363313595 .fill-N3{fill:#9499AB;} + .d2-363313595 .fill-N4{fill:#CFD2DD;} + .d2-363313595 .fill-N5{fill:#DEE1EB;} + .d2-363313595 .fill-N6{fill:#EEF1F8;} + .d2-363313595 .fill-N7{fill:#FFFFFF;} + .d2-363313595 .fill-B1{fill:#0D32B2;} + .d2-363313595 .fill-B2{fill:#0D32B2;} + .d2-363313595 .fill-B3{fill:#E3E9FD;} + .d2-363313595 .fill-B4{fill:#E3E9FD;} + .d2-363313595 .fill-B5{fill:#EDF0FD;} + .d2-363313595 .fill-B6{fill:#F7F8FE;} + .d2-363313595 .fill-AA2{fill:#4A6FF3;} + .d2-363313595 .fill-AA4{fill:#EDF0FD;} + .d2-363313595 .fill-AA5{fill:#F7F8FE;} + .d2-363313595 .fill-AB4{fill:#EDF0FD;} + .d2-363313595 .fill-AB5{fill:#F7F8FE;} + .d2-363313595 .stroke-N1{stroke:#0A0F25;} + .d2-363313595 .stroke-N2{stroke:#676C7E;} + .d2-363313595 .stroke-N3{stroke:#9499AB;} + .d2-363313595 .stroke-N4{stroke:#CFD2DD;} + .d2-363313595 .stroke-N5{stroke:#DEE1EB;} + .d2-363313595 .stroke-N6{stroke:#EEF1F8;} + .d2-363313595 .stroke-N7{stroke:#FFFFFF;} + .d2-363313595 .stroke-B1{stroke:#0D32B2;} + .d2-363313595 .stroke-B2{stroke:#0D32B2;} + .d2-363313595 .stroke-B3{stroke:#E3E9FD;} + .d2-363313595 .stroke-B4{stroke:#E3E9FD;} + .d2-363313595 .stroke-B5{stroke:#EDF0FD;} + .d2-363313595 .stroke-B6{stroke:#F7F8FE;} + .d2-363313595 .stroke-AA2{stroke:#4A6FF3;} + .d2-363313595 .stroke-AA4{stroke:#EDF0FD;} + .d2-363313595 .stroke-AA5{stroke:#F7F8FE;} + .d2-363313595 .stroke-AB4{stroke:#EDF0FD;} + .d2-363313595 .stroke-AB5{stroke:#F7F8FE;} + .d2-363313595 .background-color-N1{background-color:#0A0F25;} + .d2-363313595 .background-color-N2{background-color:#676C7E;} + .d2-363313595 .background-color-N3{background-color:#9499AB;} + .d2-363313595 .background-color-N4{background-color:#CFD2DD;} + .d2-363313595 .background-color-N5{background-color:#DEE1EB;} + .d2-363313595 .background-color-N6{background-color:#EEF1F8;} + .d2-363313595 .background-color-N7{background-color:#FFFFFF;} + .d2-363313595 .background-color-B1{background-color:#0D32B2;} + .d2-363313595 .background-color-B2{background-color:#0D32B2;} + .d2-363313595 .background-color-B3{background-color:#E3E9FD;} + .d2-363313595 .background-color-B4{background-color:#E3E9FD;} + .d2-363313595 .background-color-B5{background-color:#EDF0FD;} + .d2-363313595 .background-color-B6{background-color:#F7F8FE;} + .d2-363313595 .background-color-AA2{background-color:#4A6FF3;} + .d2-363313595 .background-color-AA4{background-color:#EDF0FD;} + .d2-363313595 .background-color-AA5{background-color:#F7F8FE;} + .d2-363313595 .background-color-AB4{background-color:#EDF0FD;} + .d2-363313595 .background-color-AB5{background-color:#F7F8FE;} + .d2-363313595 .color-N1{color:#0A0F25;} + .d2-363313595 .color-N2{color:#676C7E;} + .d2-363313595 .color-N3{color:#9499AB;} + .d2-363313595 .color-N4{color:#CFD2DD;} + .d2-363313595 .color-N5{color:#DEE1EB;} + .d2-363313595 .color-N6{color:#EEF1F8;} + .d2-363313595 .color-N7{color:#FFFFFF;} + .d2-363313595 .color-B1{color:#0D32B2;} + .d2-363313595 .color-B2{color:#0D32B2;} + .d2-363313595 .color-B3{color:#E3E9FD;} + .d2-363313595 .color-B4{color:#E3E9FD;} + .d2-363313595 .color-B5{color:#EDF0FD;} + .d2-363313595 .color-B6{color:#F7F8FE;} + .d2-363313595 .color-AA2{color:#4A6FF3;} + .d2-363313595 .color-AA4{color:#EDF0FD;} + .d2-363313595 .color-AA5{color:#F7F8FE;} + .d2-363313595 .color-AB4{color:#EDF0FD;} + .d2-363313595 .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-363313595);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-363313595);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-363313595);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-363313595);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-363313595);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-363313595);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-363313595);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-363313595);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-363313595);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..ad4e2a99c 100644 --- a/e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json +++ b/e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json @@ -539,6 +539,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 32.904998779296875, + "y": -186.9040069580078 + }, { "x": 43.2859992980957, "y": -185.53700256347656 @@ -634,6 +638,10 @@ { "x": 207.62899780273438, "y": -29.582000732421875 + }, + { + "x": 209.53700256347656, + "y": -19.285999298095703 } ], "isCurve": true, @@ -667,6 +675,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 209.53700256347656, + "y": 43.2859992980957 + }, { "x": 207.62899780273438, "y": 53.582000732421875 @@ -762,6 +774,10 @@ { "x": 43.2859992980957, "y": 209.53700256347656 + }, + { + "x": 32.904998779296875, + "y": 210.9040069580078 } ], "isCurve": true, @@ -795,6 +811,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": -8.904999732971191, + "y": 210.9040069580078 + }, { "x": -19.285999298095703, "y": 209.53700256347656 @@ -890,6 +910,10 @@ { "x": -183.62899780273438, "y": 53.582000732421875 + }, + { + "x": -185.53700256347656, + "y": 43.2859992980957 } ], "isCurve": true, @@ -923,6 +947,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 499.45098876953125, + "y": -137.51199340820312 + }, { "x": 513.333984375, "y": -136.05299377441406 @@ -1026,6 +1054,10 @@ { "x": 675.7109985351562, "y": 123.8030014038086 + }, + { + "x": 670.9359741210938, + "y": 136.92100524902344 } ], "isCurve": true, @@ -1059,6 +1091,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 643.1019897460938, + "y": 185.1320037841797 + }, { "x": 634.1279907226562, "y": 195.8260040283203 @@ -1158,6 +1194,10 @@ { "x": 336.8710021972656, "y": 195.8260040283203 + }, + { + "x": 327.8970031738281, + "y": 185.1320037841797 } ], "isCurve": true, @@ -1191,6 +1231,10 @@ "labelPercentage": 0, "link": "", "route": [ + { + "x": 925.8150024414062, + "y": -186.9040069580078 + }, { "x": 946.4920043945312, "y": -183.62899780273438 @@ -1298,6 +1342,10 @@ { "x": 946.4920043945312, "y": 207.62899780273438 + }, + { + "x": 925.8150024414062, + "y": 210.9040069580078 } ], "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..bcdbbd69f 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-170048528 .fill-N1{fill:#0A0F25;} + .d2-170048528 .fill-N2{fill:#676C7E;} + .d2-170048528 .fill-N3{fill:#9499AB;} + .d2-170048528 .fill-N4{fill:#CFD2DD;} + .d2-170048528 .fill-N5{fill:#DEE1EB;} + .d2-170048528 .fill-N6{fill:#EEF1F8;} + .d2-170048528 .fill-N7{fill:#FFFFFF;} + .d2-170048528 .fill-B1{fill:#0D32B2;} + .d2-170048528 .fill-B2{fill:#0D32B2;} + .d2-170048528 .fill-B3{fill:#E3E9FD;} + .d2-170048528 .fill-B4{fill:#E3E9FD;} + .d2-170048528 .fill-B5{fill:#EDF0FD;} + .d2-170048528 .fill-B6{fill:#F7F8FE;} + .d2-170048528 .fill-AA2{fill:#4A6FF3;} + .d2-170048528 .fill-AA4{fill:#EDF0FD;} + .d2-170048528 .fill-AA5{fill:#F7F8FE;} + .d2-170048528 .fill-AB4{fill:#EDF0FD;} + .d2-170048528 .fill-AB5{fill:#F7F8FE;} + .d2-170048528 .stroke-N1{stroke:#0A0F25;} + .d2-170048528 .stroke-N2{stroke:#676C7E;} + .d2-170048528 .stroke-N3{stroke:#9499AB;} + .d2-170048528 .stroke-N4{stroke:#CFD2DD;} + .d2-170048528 .stroke-N5{stroke:#DEE1EB;} + .d2-170048528 .stroke-N6{stroke:#EEF1F8;} + .d2-170048528 .stroke-N7{stroke:#FFFFFF;} + .d2-170048528 .stroke-B1{stroke:#0D32B2;} + .d2-170048528 .stroke-B2{stroke:#0D32B2;} + .d2-170048528 .stroke-B3{stroke:#E3E9FD;} + .d2-170048528 .stroke-B4{stroke:#E3E9FD;} + .d2-170048528 .stroke-B5{stroke:#EDF0FD;} + .d2-170048528 .stroke-B6{stroke:#F7F8FE;} + .d2-170048528 .stroke-AA2{stroke:#4A6FF3;} + .d2-170048528 .stroke-AA4{stroke:#EDF0FD;} + .d2-170048528 .stroke-AA5{stroke:#F7F8FE;} + .d2-170048528 .stroke-AB4{stroke:#EDF0FD;} + .d2-170048528 .stroke-AB5{stroke:#F7F8FE;} + .d2-170048528 .background-color-N1{background-color:#0A0F25;} + .d2-170048528 .background-color-N2{background-color:#676C7E;} + .d2-170048528 .background-color-N3{background-color:#9499AB;} + .d2-170048528 .background-color-N4{background-color:#CFD2DD;} + .d2-170048528 .background-color-N5{background-color:#DEE1EB;} + .d2-170048528 .background-color-N6{background-color:#EEF1F8;} + .d2-170048528 .background-color-N7{background-color:#FFFFFF;} + .d2-170048528 .background-color-B1{background-color:#0D32B2;} + .d2-170048528 .background-color-B2{background-color:#0D32B2;} + .d2-170048528 .background-color-B3{background-color:#E3E9FD;} + .d2-170048528 .background-color-B4{background-color:#E3E9FD;} + .d2-170048528 .background-color-B5{background-color:#EDF0FD;} + .d2-170048528 .background-color-B6{background-color:#F7F8FE;} + .d2-170048528 .background-color-AA2{background-color:#4A6FF3;} + .d2-170048528 .background-color-AA4{background-color:#EDF0FD;} + .d2-170048528 .background-color-AA5{background-color:#F7F8FE;} + .d2-170048528 .background-color-AB4{background-color:#EDF0FD;} + .d2-170048528 .background-color-AB5{background-color:#F7F8FE;} + .d2-170048528 .color-N1{color:#0A0F25;} + .d2-170048528 .color-N2{color:#676C7E;} + .d2-170048528 .color-N3{color:#9499AB;} + .d2-170048528 .color-N4{color:#CFD2DD;} + .d2-170048528 .color-N5{color:#DEE1EB;} + .d2-170048528 .color-N6{color:#EEF1F8;} + .d2-170048528 .color-N7{color:#FFFFFF;} + .d2-170048528 .color-B1{color:#0D32B2;} + .d2-170048528 .color-B2{color:#0D32B2;} + .d2-170048528 .color-B3{color:#E3E9FD;} + .d2-170048528 .color-B4{color:#E3E9FD;} + .d2-170048528 .color-B5{color:#EDF0FD;} + .d2-170048528 .color-B6{color:#F7F8FE;} + .d2-170048528 .color-AA2{color:#4A6FF3;} + .d2-170048528 .color-AA4{color:#EDF0FD;} + .d2-170048528 .color-AA5{color:#F7F8FE;} + .d2-170048528 .color-AB4{color:#EDF0FD;} + .d2-170048528 .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-170048528);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-170048528);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-170048528);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-170048528);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-170048528);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-170048528);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-170048528);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-170048528);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>abcdabcab