diff --git a/README.md b/README.md index bf91097cd..5f615e6ce 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ https://user-images.githubusercontent.com/3120367/206125010-bd1fea8e-248a-43e7-8 - Community plugins - Misc - FAQ +- Open-source projects documenting with D2 ## What does D2 look like? @@ -218,6 +219,7 @@ let us know and we'll be happy to include it here! - **D2 org-mode support**: [https://github.com/xcapaldi/ob-d2](https://github.com/xcapaldi/ob-d2) - **Python D2 diagram builder**: [https://github.com/MrBlenny/py-d2](https://github.com/MrBlenny/py-d2) - **Clojure D2 transpiler**: [https://github.com/judepayne/dictim](https://github.com/judepayne/dictim) +- **JavaScript D2 diagram builder**: [https://github.com/Kreshnik/d2lang-js](https://github.com/Kreshnik/d2lang-js) ### Misc @@ -240,3 +242,21 @@ let us know and we'll be happy to include it here! - Please open up a Github Issue. - I have a private inquiry. - Please reach out at [hi@d2lang.com](hi@d2lang.com). + +## Open-source projects documenting with D2 + +Do you have or see an open-source project with `.d2` files? Please submit a PR adding to +this list (ordered by star count, desc). + +- [Block Protocol](https://github.com/blockprotocol/blockprotocol) - The Block Protocol is + an open standard for building and using data-driven blocks. +- [Ivy Wallet](https://github.com/Ivy-Apps/ivy-wallet) - Ivy Wallet is an open-source + money manager app for Android. +- [Learn EVM Attacks](https://github.com/coinspect/learn-evm-attacks) - Learn & Contribute + on previously exploited vulnerabilities across several EVM projects. +- [BYCEPS](https://github.com/byceps/byceps) - BYCEPS is a self-hosted web platform to run + LAN parties. +- [Re:Earth](https://github.com/reearth/reearth-web) - A free, open and highly extensible + WebGIS platform. +- [Terraform OCI VSCode Server](https://github.com/timoa/terraform-oci-vscode-server) - + Terraform project that deploys VSCode Server on Oracle Cloud Infrastructure. diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index cfdebd299..2fa59fa9a 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -1,5 +1,26 @@ +![animated connection example](https://user-images.githubusercontent.com/3120367/213055161-e6f1918b-150c-4beb-b61c-3ea05cc29f00.svg) + + #### Features ๐Ÿš€ + - Circle arrowheads are now supported. [#634](https://github.com/terrastruct/d2/pull/634) + +- `animated` keyword implemented for connections. [#652](https://github.com/terrastruct/d2/pull/652) + #### Improvements ๐Ÿงน +- ELK layouts tuned to have better defaults. [#627](https://github.com/terrastruct/d2/pull/627) +- Code snippets of unrecognized languages will render (just without syntax highlighting). [#650](https://github.com/terrastruct/d2/pull/650) +- Adds sketched versions of arrowheads. [#656](https://github.com/terrastruct/d2/pull/656) + #### Bugfixes โ›‘๏ธ + +- Fixes arrowheads sometimes appearing broken in dagre layouts. [#649](https://github.com/terrastruct/d2/pull/649) +- Fixes attributes being ignored for `sql_table` to `sql_table` connections. [#658](https://github.com/terrastruct/d2/pull/658) +- Fixes tooltip/link attributes being ignored for `sql_table` and `class`. [#658](https://github.com/terrastruct/d2/pull/658) +- Fixes arrowheads sometimes appearing broken with sketch on. [#656](https://github.com/terrastruct/d2/pull/656) +- Fixes code snippets not being tall enough with leading newlines. [#664](https://github.com/terrastruct/d2/pull/664) +- Opacity was not being applied to labels of shapes (and other edge cases). [#677](https://github.com/terrastruct/d2/pull/677) +- Icon URLs that needed escaping (e.g. with ampersands) are handled correctly by CLI. [#666](https://github.com/terrastruct/d2/pull/666) +- Fixes markdown shapes being slightly too short for their text in some cases. [#665](https://github.com/terrastruct/d2/pull/665) +- Fixes self-connections inside layouts when using ELK. [#676](https://github.com/terrastruct/d2/pull/676) diff --git a/ci/sub b/ci/sub index 9a29d9ea6..23984e4d7 160000 --- a/ci/sub +++ b/ci/sub @@ -1 +1 @@ -Subproject commit 9a29d9ea640834905c4010c0b3d14b7301ebb6d8 +Subproject commit 23984e4d743dd9977b513c0fd850a4996c9198a5 diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 48498a767..c89a4853e 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -757,13 +757,15 @@ func flattenContainer(g *d2graph.Graph, obj *d2graph.Object) { // TODO more attributes if e.SrcTableColumnIndex != nil { newEdge.SrcTableColumnIndex = new(int) + newEdge.SrcArrowhead = e.SrcArrowhead *newEdge.SrcTableColumnIndex = *e.SrcTableColumnIndex } if e.DstTableColumnIndex != nil { newEdge.DstTableColumnIndex = new(int) + newEdge.DstArrowhead = e.DstArrowhead *newEdge.DstTableColumnIndex = *e.DstTableColumnIndex } - newEdge.Attributes.Label = e.Attributes.Label + newEdge.Attributes = e.Attributes newEdge.References = e.References } updatedEdges := []*d2graph.Edge{} diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 81db413f2..a432f078e 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1597,6 +1597,25 @@ b`, g.Objects[0].Attributes.Label.Value) } }, }, + { + name: "table_connection_attr", + + text: `x: { + shape: sql_table + y +} +a: { + shape: sql_table + b +} +x.y -> a.b: { + style.animated: true +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "true", g.Edges[0].Attributes.Style.Animated.Value) + }, + }, { name: "class_paren", diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 21361304a..28ea03ef9 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -1027,6 +1027,27 @@ func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2 var h int if t.Language != "" { w, h = ruler.Measure(d2fonts.SourceCodePro.Font(t.FontSize, d2fonts.FONT_STYLE_REGULAR), t.Text) + + // count empty leading and trailing lines since ruler will not be able to measure it + lines := strings.Split(t.Text, "\n") + leadingLines := 0 + for _, line := range lines { + if strings.TrimSpace(line) == "" { + leadingLines++ + } else { + break + } + } + trailingLines := 0 + for i := len(lines) - 1; i >= 0; i-- { + if strings.TrimSpace(lines[i]) == "" { + trailingLines++ + } else { + break + } + } + h += t.FontSize * (leadingLines + trailingLines) + // padding w += 12 h += 12 diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 0d5c5d569..7ac2a44e4 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -30,6 +30,8 @@ var setupJS string //go:embed dagre.js var dagreJS string +const MIN_SEGMENT_LEN = 10 + type ConfigurableOpts struct { NodeSep int `json:"nodesep"` EdgeSep int `json:"edgesep"` @@ -247,6 +249,47 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err } } + // arrowheads can appear broken if segments are very short from dagre routing a point just outside the shape + // to fix this, we try extending the previous segment into the shape instead of having a very short segment + if !start.Equals(points[0]) && startIndex+2 < len(points) { + newStartingSegment := *geo.NewSegment(start, points[startIndex+1]) + if newStartingSegment.Length() < MIN_SEGMENT_LEN { + // we don't want a very short segment right next to the source because it will mess up the arrowhead + // instead we want to extend the next segment into the shape border if possible + nextStart := points[startIndex+1] + nextEnd := points[startIndex+2] + + // Note: in other direction to extend towards source + nextSegment := *geo.NewSegment(nextStart, nextEnd) + v := nextSegment.ToVector() + extendedStart := nextEnd.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint() + extended := *geo.NewSegment(nextEnd, extendedStart) + + if intersections := edge.Src.Box.Intersections(extended); len(intersections) > 0 { + start = intersections[0] + startIndex += 1 + } + } + } + if !end.Equals(points[len(points)-1]) && endIndex-2 >= 0 { + newEndingSegment := *geo.NewSegment(end, points[endIndex-1]) + if newEndingSegment.Length() < MIN_SEGMENT_LEN { + // extend the prev segment into the shape border if possible + prevStart := points[endIndex-2] + prevEnd := points[endIndex-1] + + prevSegment := *geo.NewSegment(prevStart, prevEnd) + v := prevSegment.ToVector() + extendedEnd := prevStart.ToVector().Add(v.AddLength(MIN_SEGMENT_LEN)).ToPoint() + extended := *geo.NewSegment(prevStart, extendedEnd) + + if intersections := edge.Dst.Box.Intersections(extended); len(intersections) > 0 { + end = intersections[0] + endIndex -= 1 + } + } + } + srcShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Src.Attributes.Shape.Value)], edge.Src.Box) dstShape := shape.NewShape(d2target.DSL_SHAPE_TO_SHAPE_TYPE[strings.ToLower(edge.Dst.Attributes.Shape.Value)], edge.Dst.Box) @@ -263,18 +306,20 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err path := make([]*geo.Point, 0) path = append(path, points[0]) - path = append(path, points[0].AddVector(vectors[0].Multiply(.8))) - for i := 1; i < len(vectors)-2; i++ { - p := points[i] - v := vectors[i] - path = append(path, p.AddVector(v.Multiply(.2))) - path = append(path, p.AddVector(v.Multiply(.5))) - path = append(path, p.AddVector(v.Multiply(.8))) + if len(vectors) > 1 { + path = append(path, points[0].AddVector(vectors[0].Multiply(.8))) + for i := 1; i < len(vectors)-2; i++ { + p := points[i] + v := vectors[i] + path = append(path, p.AddVector(v.Multiply(.2))) + path = append(path, p.AddVector(v.Multiply(.5))) + path = append(path, p.AddVector(v.Multiply(.8))) + } + path = append(path, points[len(points)-2].AddVector(vectors[len(vectors)-1].Multiply(.2))) + edge.IsCurve = true } - path = append(path, points[len(points)-2].AddVector(vectors[len(vectors)-1].Multiply(.2))) path = append(path, points[len(points)-1]) - edge.IsCurve = true edge.Route = path // compile needs to assign edge label positions if edge.Attributes.Label.Value != "" { diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index d9b333385..909a7eab1 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -94,11 +94,13 @@ var DefaultOpts = ConfigurableOpts{ } type elkOpts struct { - Direction string `json:"elk.direction"` - HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` - InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"` - ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"` - ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"` + Thoroughness int `json:"elk.layered.thoroughness,omitempty"` + EdgeEdgeBetweenLayersSpacing int `json:"elk.layered.spacing.edgeEdgeBetweenLayers,omitempty"` + Direction string `json:"elk.direction"` + HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` + InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"` + ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"` + ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"` ConfigurableOpts } @@ -130,8 +132,10 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err elkGraph := &ELKGraph{ ID: "root", LayoutOptions: &elkOpts{ - HierarchyHandling: "INCLUDE_CHILDREN", - ConsiderModelOrder: "NODES_AND_EDGES", + Thoroughness: 20, + EdgeEdgeBetweenLayersSpacing: 50, + HierarchyHandling: "INCLUDE_CHILDREN", + ConsiderModelOrder: "NODES_AND_EDGES", ConfigurableOpts: ConfigurableOpts{ Algorithm: opts.Algorithm, NodeSpacing: opts.NodeSpacing, @@ -183,9 +187,16 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err if len(obj.ChildrenArray) > 0 { n.LayoutOptions = &elkOpts{ - ForceNodeModelOrder: true, + ForceNodeModelOrder: true, + Thoroughness: 20, + EdgeEdgeBetweenLayersSpacing: 50, + HierarchyHandling: "INCLUDE_CHILDREN", + ConsiderModelOrder: "NODES_AND_EDGES", ConfigurableOpts: ConfigurableOpts{ - Padding: opts.Padding, + NodeSpacing: opts.NodeSpacing, + EdgeNodeSpacing: opts.EdgeNodeSpacing, + SelfLoopSpacing: opts.SelfLoopSpacing, + Padding: opts.Padding, }, } } diff --git a/d2renderers/d2sketch/sketch.go b/d2renderers/d2sketch/sketch.go index 4c4913a2b..16697c0b1 100644 --- a/d2renderers/d2sketch/sketch.go +++ b/d2renderers/d2sketch/sketch.go @@ -3,6 +3,7 @@ package d2sketch import ( "encoding/json" "fmt" + "regexp" "strings" _ "embed" @@ -33,6 +34,8 @@ fillStyle: "solid", bowing: 2, seed: 1,` +var floatRE = regexp.MustCompile(`(\d+)\.(\d+)`) + func (r *Runner) run(js string) (goja.Value, error) { vm := (*goja.Runtime)(r) return vm.RunString(js) @@ -63,26 +66,6 @@ func DefineFillPattern() string { `, fillPattern) } -func shapeStyle(shape d2target.Shape) string { - out := "" - - if shape.Type == d2target.ShapeSQLTable || shape.Type == d2target.ShapeClass { - out += fmt.Sprintf(`fill:%s;`, shape.Stroke) - out += fmt.Sprintf(`stroke:%s;`, shape.Fill) - } else { - out += fmt.Sprintf(`fill:%s;`, shape.Fill) - out += fmt.Sprintf(`stroke:%s;`, shape.Stroke) - } - out += fmt.Sprintf(`opacity:%f;`, shape.Opacity) - out += fmt.Sprintf(`stroke-width:%d;`, shape.StrokeWidth) - if shape.StrokeDash != 0 { - dashSize, gapSize := svg.GetStrokeDashAttributes(float64(shape.StrokeWidth), shape.StrokeDash) - out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize) - } - - return out -} - func Rect(r *Runner, shape d2target.Shape) (string, error) { js := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, { fill: "%s", @@ -90,7 +73,7 @@ func Rect(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } @@ -98,7 +81,7 @@ func Rect(r *Runner, shape d2target.Shape) (string, error) { for _, p := range paths { output += fmt.Sprintf( ``, - shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape), + shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(), ) } output += fmt.Sprintf( @@ -115,7 +98,7 @@ func Oval(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width/2, shape.Height/2, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } @@ -123,7 +106,7 @@ func Oval(r *Runner, shape d2target.Shape) (string, error) { for _, p := range paths { output += fmt.Sprintf( ``, - shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape), + shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(), ) } output += fmt.Sprintf( @@ -143,14 +126,14 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) { strokeWidth: %d, %s });`, path, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps) - sketchPaths, err := computeRoughPaths(r, js) + sketchPaths, err := computeRoughPathData(r, js) if err != nil { return "", err } for _, p := range sketchPaths { output += fmt.Sprintf( ``, - p, shapeStyle(shape), + p, shape.CSSStyle(), ) } for _, p := range sketchPaths { @@ -163,32 +146,22 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) { return output, nil } -func connectionStyle(connection d2target.Connection) string { - out := "" - - out += fmt.Sprintf(`stroke:%s;`, connection.Stroke) - out += fmt.Sprintf(`opacity:%f;`, connection.Opacity) - out += fmt.Sprintf(`stroke-width:%d;`, connection.StrokeWidth) - if connection.StrokeDash != 0 { - dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), connection.StrokeDash) - out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize) - } - - return out -} - func Connection(r *Runner, connection d2target.Connection, path, attrs string) (string, error) { roughness := 1.0 js := fmt.Sprintf(`node = rc.path("%s", {roughness: %f, seed: 1});`, path, roughness) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } output := "" + animatedClass := "" + if connection.Animated { + animatedClass = " animated-connection" + } for _, p := range paths { output += fmt.Sprintf( - ``, - p, connectionStyle(connection), attrs, + ``, + animatedClass, p, connection.CSSStyle(), attrs, ) } return output, nil @@ -203,14 +176,14 @@ func Table(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } for _, p := range paths { output += fmt.Sprintf( ``, - shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape), + shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(), ) } @@ -226,7 +199,7 @@ func Table(r *Runner, shape d2target.Shape) (string, error) { fill: "%s", %s });`, shape.Width, rowHeight, shape.Fill, baseRoughProps) - paths, err = computeRoughPaths(r, js) + paths, err = computeRoughPathData(r, js) if err != nil { return "", err } @@ -305,7 +278,7 @@ func Table(r *Runner, shape d2target.Shape) (string, error) { js = fmt.Sprintf(`node = rc.line(%f, %f, %f, %f, { %s });`, rowBox.TopLeft.X, rowBox.TopLeft.Y, rowBox.TopLeft.X+rowBox.Width, rowBox.TopLeft.Y, baseRoughProps) - paths, err = computeRoughPaths(r, js) + paths, err = computeRoughPathData(r, js) if err != nil { return "", err } @@ -331,14 +304,14 @@ func Class(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } for _, p := range paths { output += fmt.Sprintf( ``, - shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape), + shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(), ) } @@ -355,7 +328,7 @@ func Class(r *Runner, shape d2target.Shape) (string, error) { fill: "%s", %s });`, shape.Width, headerBox.Height, shape.Fill, baseRoughProps) - paths, err = computeRoughPaths(r, js) + paths, err = computeRoughPathData(r, js) if err != nil { return "", err } @@ -402,7 +375,7 @@ func Class(r *Runner, shape d2target.Shape) (string, error) { js = fmt.Sprintf(`node = rc.line(%f, %f, %f, %f, { %s });`, rowBox.TopLeft.X, rowBox.TopLeft.Y, rowBox.TopLeft.X+rowBox.Width, rowBox.TopLeft.Y, baseRoughProps) - paths, err = computeRoughPaths(r, js) + paths, err = computeRoughPathData(r, js) if err != nil { return "", err } @@ -461,38 +434,242 @@ func classRow(shape d2target.Shape, box *geo.Box, prefix, nameText, typeText str return output } -func computeRoughPaths(r *Runner, js string) ([]string, error) { +func computeRoughPathData(r *Runner, js string) ([]string, error) { if _, err := r.run(js); err != nil { return nil, err } - return extractPaths(r) + roughPaths, err := extractRoughPaths(r) + if err != nil { + return nil, err + } + return extractPathData(roughPaths) +} + +func computeRoughPaths(r *Runner, js string) ([]roughPath, error) { + if _, err := r.run(js); err != nil { + return nil, err + } + return extractRoughPaths(r) } type attrs struct { D string `json:"d"` } -type node struct { - Attrs attrs `json:"attrs"` +type style struct { + Stroke string `json:"stroke,omitempty"` + StrokeWidth string `json:"strokeWidth,omitempty"` + Fill string `json:"fill,omitempty"` } -func extractPaths(r *Runner) ([]string, error) { - val, err := r.run("JSON.stringify(node.children)") +type roughPath struct { + Attrs attrs `json:"attrs"` + Style style `json:"style"` +} + +func (rp roughPath) StyleCSS() string { + style := "" + if rp.Style.Fill != "" { + style += fmt.Sprintf("fill:%s;", rp.Style.Fill) + } + if rp.Style.Stroke != "" { + style += fmt.Sprintf("stroke:%s;", rp.Style.Stroke) + } + if rp.Style.StrokeWidth != "" { + style += fmt.Sprintf("stroke-width:%s;", rp.Style.StrokeWidth) + } + return style +} + +func extractRoughPaths(r *Runner) ([]roughPath, error) { + val, err := r.run("JSON.stringify(node.children, null, ' ')") if err != nil { return nil, err } - var nodes []node - - err = json.Unmarshal([]byte(val.String()), &nodes) + var roughPaths []roughPath + err = json.Unmarshal([]byte(val.String()), &roughPaths) if err != nil { return nil, err } + // we want to have a fixed precision to the decimals in the path data + for i := range roughPaths { + // truncate all floats in path to only use up to 6 decimal places + roughPaths[i].Attrs.D = floatRE.ReplaceAllStringFunc(roughPaths[i].Attrs.D, func(floatStr string) string { + i := strings.Index(floatStr, ".") + decimalLen := len(floatStr) - i - 1 + end := i + go2.Min(decimalLen, 6) + return floatStr[:end+1] + }) + } + + return roughPaths, nil +} + +func extractPathData(roughPaths []roughPath) ([]string, error) { var paths []string - for _, n := range nodes { - paths = append(paths, n.Attrs.D) + for _, rp := range roughPaths { + paths = append(paths, rp.Attrs.D) } - return paths, nil } + +func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeWidth int) (arrowJS, extraJS string) { + // Note: selected each seed that looks the good for consistent renders + switch arrowhead { + case d2target.ArrowArrowhead: + arrowJS = fmt.Sprintf( + `node = rc.linearPath(%s, { strokeWidth: %d, stroke: "%s", seed: 3 })`, + `[[-10, -4], [0, 0], [-10, 4]]`, + strokeWidth, + stroke, + ) + case d2target.TriangleArrowhead: + arrowJS = fmt.Sprintf( + `node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", seed: 2 })`, + `[[-10, -4], [0, 0], [-10, 4]]`, + strokeWidth, + stroke, + stroke, + ) + case d2target.DiamondArrowhead: + arrowJS = fmt.Sprintf( + `node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "white", fillStyle: "solid", seed: 1 })`, + `[[-20, 0], [-10, 5], [0, 0], [-10, -5], [-20, 0]]`, + strokeWidth, + stroke, + ) + case d2target.FilledDiamondArrowhead: + arrowJS = fmt.Sprintf( + `node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "zigzag", fillWeight: 4, seed: 1 })`, + `[[-20, 0], [-10, 5], [0, 0], [-10, -5], [-20, 0]]`, + strokeWidth, + stroke, + stroke, + ) + case d2target.CfManyRequired: + arrowJS = fmt.Sprintf( + // TODO why does fillStyle: "zigzag" error with path + `node = rc.path(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 4, seed: 2 })`, + `"M-15,-10 -15,10 M0,10 -15,0 M0,-10 -15,0"`, + strokeWidth, + stroke, + stroke, + ) + case d2target.CfMany: + arrowJS = fmt.Sprintf( + `node = rc.path(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 4, seed: 8 })`, + `"M0,10 -15,0 M0,-10 -15,0"`, + strokeWidth, + stroke, + stroke, + ) + extraJS = fmt.Sprintf( + `node = rc.circle(-20, 0, 8, { strokeWidth: %d, stroke: "%s", fill: "white", fillStyle: "solid", fillWeight: 1, seed: 4 })`, + strokeWidth, + stroke, + ) + case d2target.CfOneRequired: + arrowJS = fmt.Sprintf( + `node = rc.path(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 4, seed: 2 })`, + `"M-15,-10 -15,10 M-10,-10 -10,10"`, + strokeWidth, + stroke, + stroke, + ) + case d2target.CfOne: + arrowJS = fmt.Sprintf( + `node = rc.path(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 4, seed: 3 })`, + `"M-10,-10 -10,10"`, + strokeWidth, + stroke, + stroke, + ) + extraJS = fmt.Sprintf( + `node = rc.circle(-20, 0, 8, { strokeWidth: %d, stroke: "%s", fill: "white", fillStyle: "solid", fillWeight: 1, seed: 5 })`, + strokeWidth, + stroke, + ) + } + return +} + +func Arrowheads(r *Runner, connection d2target.Connection, srcAdj, dstAdj *geo.Point) (string, error) { + arrowPaths := []string{} + + if connection.SrcArrow != d2target.NoArrowhead { + arrowJS, extraJS := ArrowheadJS(r, connection.SrcArrow, connection.Stroke, connection.StrokeWidth) + if arrowJS == "" { + return "", nil + } + + startingSegment := geo.NewSegment(connection.Route[0], connection.Route[1]) + startingVector := startingSegment.ToVector().Reverse() + angle := startingVector.Degrees() + + transform := fmt.Sprintf(`transform="translate(%f %f) rotate(%v)"`, + startingSegment.Start.X+srcAdj.X, startingSegment.Start.Y+srcAdj.Y, angle, + ) + + roughPaths, err := computeRoughPaths(r, arrowJS) + if err != nil { + return "", err + } + if extraJS != "" { + extraPaths, err := computeRoughPaths(r, extraJS) + if err != nil { + return "", err + } + roughPaths = append(roughPaths, extraPaths...) + } + + for _, rp := range roughPaths { + pathStr := fmt.Sprintf(``, + rp.Attrs.D, + rp.StyleCSS(), + transform, + ) + arrowPaths = append(arrowPaths, pathStr) + } + } + + if connection.DstArrow != d2target.NoArrowhead { + arrowJS, extraJS := ArrowheadJS(r, connection.DstArrow, connection.Stroke, connection.StrokeWidth) + if arrowJS == "" { + return "", nil + } + + length := len(connection.Route) + endingSegment := geo.NewSegment(connection.Route[length-2], connection.Route[length-1]) + endingVector := endingSegment.ToVector() + angle := endingVector.Degrees() + + transform := fmt.Sprintf(`transform="translate(%f %f) rotate(%v)"`, + endingSegment.End.X+dstAdj.X, endingSegment.End.Y+dstAdj.Y, angle, + ) + + roughPaths, err := computeRoughPaths(r, arrowJS) + if err != nil { + return "", err + } + if extraJS != "" { + extraPaths, err := computeRoughPaths(r, extraJS) + if err != nil { + return "", err + } + roughPaths = append(roughPaths, extraPaths...) + } + + for _, rp := range roughPaths { + pathStr := fmt.Sprintf(``, + rp.Attrs.D, + rp.StyleCSS(), + transform, + ) + arrowPaths = append(arrowPaths, pathStr) + } + } + + return strings.Join(arrowPaths, " "), nil +} diff --git a/d2renderers/d2sketch/sketch_test.go b/d2renderers/d2sketch/sketch_test.go index c2b8dadea..f431a62a2 100644 --- a/d2renderers/d2sketch/sketch_test.go +++ b/d2renderers/d2sketch/sketch_test.go @@ -39,6 +39,11 @@ func TestSketch(t *testing.T) { script: `winter.snow -> summer.sun `, }, + { + name: "animated", + script: `winter.snow -> summer.sun -> trees -> winter.snow: { style.animated: true } + `, + }, { name: "connection label", script: `a -> b: hello @@ -275,6 +280,71 @@ shipments.order_id <-> orders.id`, +getJobs(): "Job[]" +setTimeout(seconds int) } +`, + }, + { + name: "arrowheads", + script: ` +a: "" +b: "" +a.1 -- b.1: none +a.2 <-> b.2: arrow { + source-arrowhead.shape: arrow + target-arrowhead.shape: arrow +} +a.3 <-> b.3: triangle { + source-arrowhead.shape: triangle + target-arrowhead.shape: triangle +} +a.4 <-> b.4: diamond { + source-arrowhead.shape: diamond + target-arrowhead.shape: diamond +} +a.5 <-> b.5: diamond filled { + source-arrowhead: { + shape: diamond + style.filled: true + } + target-arrowhead: { + shape: diamond + style.filled: true + } +} +a.6 <-> b.6: cf-many { + source-arrowhead.shape: cf-many + target-arrowhead.shape: cf-many +} +a.7 <-> b.7: cf-many-required { + source-arrowhead.shape: cf-many-required + target-arrowhead.shape: cf-many-required +} +a.8 <-> b.8: cf-one { + source-arrowhead.shape: cf-one + target-arrowhead.shape: cf-one +} +a.9 <-> b.9: cf-one-required { + source-arrowhead.shape: cf-one-required + target-arrowhead.shape: cf-one-required +} +`, + }, + { + name: "opacity", + script: `x.style.opacity: 0.4 +y: |md + linux: because a PC is a terrible thing to waste +| { + style.opacity: 0.4 +} +x -> a: { + label: You don't have to know how the computer works,\njust how to work the computer. + style.opacity: 0.4 +} +users: { + shape: sql_table + last_login: datetime + style.opacity: 0.4 +} `, }, } diff --git a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg index efb2c8aba..07980441b 100644 --- a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg +++ b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg @@ -51,7 +51,7 @@ width="1597" height="835" viewBox="-102 -102 1597 835"> + + + + +wintersummertreessnowsun + + + \ No newline at end of file diff --git a/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg b/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg new file mode 100644 index 000000000..086197e48 --- /dev/null +++ b/d2renderers/d2sketch/testdata/arrowheads/sketch.exp.svg @@ -0,0 +1,79 @@ + + + + + + +112233445566778899none arrow triangle diamond diamond filled cf-many cf-many-required cf-one cf-one-required + + + + + + + + + + + \ No newline at end of file diff --git a/d2renderers/d2sketch/testdata/basic/sketch.exp.svg b/d2renderers/d2sketch/testdata/basic/sketch.exp.svg index fa9cb40e1..04920a63f 100644 --- a/d2renderers/d2sketch/testdata/basic/sketch.exp.svg +++ b/d2renderers/d2sketch/testdata/basic/sketch.exp.svg @@ -51,7 +51,7 @@ width="319" height="556" viewBox="-102 -102 319 556"> + + + + +x

linux: because a PC is a terrible thing to waste

+
userslast_login +datetime +a You don't have to know how the computer works,just how to work the computer. + + + \ No newline at end of file diff --git a/d2renderers/d2sketch/testdata/sql_tables/sketch.exp.svg b/d2renderers/d2sketch/testdata/sql_tables/sketch.exp.svg index faf736cb5..a73606a4b 100644 --- a/d2renderers/d2sketch/testdata/sql_tables/sketch.exp.svg +++ b/d2renderers/d2sketch/testdata/sql_tables/sketch.exp.svg @@ -51,39 +51,39 @@ width="1029" height="664" viewBox="-102 -102 1029 664"> + +# 2 leading, 2 trailing +def hello(): + +  print "world" + + + +# 2 leading +def hello(): + +  print "world"# 2 trailing +def hello(): + +  print "world" + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json new file mode 100644 index 000000000..da4f01ab5 --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/board.exp.json @@ -0,0 +1,124 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hello world", + "type": "code", + "pos": { + "x": 12, + "y": 12 + }, + "width": 239, + "height": 150, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading, 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 239, + "labelHeight": 150, + "zIndex": 0, + "level": 1 + }, + { + "id": "no trailing", + "type": "code", + "pos": { + "x": 271, + "y": 28 + }, + "width": 160, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n\n# 2 leading\ndef hello():\n\n print \"world\"", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 118, + "zIndex": 0, + "level": 1 + }, + { + "id": "no leading", + "type": "code", + "pos": { + "x": 451, + "y": 28 + }, + "width": 160, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "# 2 trailing\ndef hello():\n\n print \"world\"\n\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "python", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 160, + "labelHeight": 118, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg new file mode 100644 index 000000000..430902c7d --- /dev/null +++ b/e2etests/testdata/regression/code_leading_trailing_newlines/elk/sketch.exp.svg @@ -0,0 +1,69 @@ + + + +# 2 leading, 2 trailing +def hello(): + +  print "world" + + + +# 2 leading +def hello(): + +  print "world"# 2 trailing +def hello(): + +  print "world" + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json new file mode 100644 index 000000000..5a05fac5f --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json @@ -0,0 +1,392 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 571, + "height": 648, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 17, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "a.c", + "type": "", + "pos": { + "x": 40, + "y": 359 + }, + "width": 478, + "height": 235, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "white", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.c.d", + "type": "", + "pos": { + "x": 236, + "y": 413 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "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", + "zIndex": 0, + "level": 3 + }, + { + "id": "a.b", + "type": "", + "pos": { + "x": 64, + "y": 55 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.1", + "type": "", + "pos": { + "x": 237, + "y": 55 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.2", + "type": "", + "pos": { + "x": 409, + "y": 55 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "2", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "a.(b -> c)[0]", + "src": "a.b", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "red", + "label": "line 1\nline 2\nline 3\nline 4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "red", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 36, + "labelHeight": 69, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 120, + "y": 181.5 + }, + { + "x": 120, + "y": 251.9 + }, + { + "x": 120, + "y": 287.5 + }, + { + "x": 120, + "y": 359.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(1 -> c)[0]", + "src": "a.1", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.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": 292.5, + "y": 181.5 + }, + { + "x": 292.5, + "y": 251.9 + }, + { + "x": 292.5, + "y": 287.5 + }, + { + "x": 292.5, + "y": 359.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(2 <-> c)[0]", + "src": "a.2", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "a.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": 465, + "y": 181.5 + }, + { + "x": 465, + "y": 251.9 + }, + { + "x": 465, + "y": 287.5 + }, + { + "x": 465, + "y": 359.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg new file mode 100644 index 000000000..6a3c69130 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg @@ -0,0 +1,66 @@ + +acb12d line 1line 2line 3line 4 + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json new file mode 100644 index 000000000..7c00e2724 --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/board.exp.json @@ -0,0 +1,381 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 490, + "height": 878, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 17, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "a.c", + "type": "", + "pos": { + "x": 106, + "y": 539 + }, + "width": 264, + "height": 276, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "white", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "c", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.c.d", + "type": "", + "pos": { + "x": 181, + "y": 614 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "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", + "zIndex": 0, + "level": 3 + }, + { + "id": "a.b", + "type": "", + "pos": { + "x": 87, + "y": 87 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.1", + "type": "", + "pos": { + "x": 182, + "y": 313 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "1", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "a.2", + "type": "", + "pos": { + "x": 314, + "y": 313 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "2", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "a.(b -> c)[0]", + "src": "a.b", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.c", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "red", + "label": "line 1\nline 2\nline 3\nline 4", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "red", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 36, + "labelHeight": 69, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 143.5, + "y": 213 + }, + { + "x": 143.5, + "y": 489 + }, + { + "x": 172.5, + "y": 489 + }, + { + "x": 172.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(1 -> c)[0]", + "src": "a.1", + "srcArrow": "none", + "srcLabel": "", + "dst": "a.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": 238.5, + "y": 439 + }, + { + "x": 238.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "a.(2 <-> c)[0]", + "src": "a.2", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "a.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": 371, + "y": 439 + }, + { + "x": 371, + "y": 489 + }, + { + "x": 304.5, + "y": 489 + }, + { + "x": 304.5, + "y": 539 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg new file mode 100644 index 000000000..ae203e0aa --- /dev/null +++ b/e2etests/testdata/regression/dagre_broken_arrowhead/elk/sketch.exp.svg @@ -0,0 +1,66 @@ + +acb12d line 1line 2line 3line 4 + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg index 1e7b73085..5a6d741b6 100644 --- a/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="2832" height="441" viewBox="-102 -102 2832 441"> \ No newline at end of file diff --git a/e2etests/testdata/regression/elk_img_empty_label_panic/elk/sketch.exp.svg b/e2etests/testdata/regression/elk_img_empty_label_panic/elk/sketch.exp.svg index 2ca3fb21b..6f53328fa 100644 --- a/e2etests/testdata/regression/elk_img_empty_label_panic/elk/sketch.exp.svg +++ b/e2etests/testdata/regression/elk_img_empty_label_panic/elk/sketch.exp.svg @@ -39,7 +39,7 @@ width="452" height="332" viewBox="-90 -90 452 332"> \ No newline at end of file diff --git a/e2etests/testdata/regression/elk_loop_panic/dagre/board.exp.json b/e2etests/testdata/regression/elk_loop_panic/dagre/board.exp.json new file mode 100644 index 000000000..ca5d11974 --- /dev/null +++ b/e2etests/testdata/regression/elk_loop_panic/dagre/board.exp.json @@ -0,0 +1,212 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 426, + "height": 226, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 18, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x.a", + "type": "", + "pos": { + "x": 50, + "y": 50 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "x.b", + "type": "", + "pos": { + "x": 263, + "y": 50 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "x.(a -> a)[0]", + "src": "x.a", + "srcArrow": "none", + "srcLabel": "", + "dst": "x.a", + "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": 163, + "y": 73.37662337662337 + }, + { + "x": 189.66666666666669, + "y": 54.675324675324674 + }, + { + "x": 198, + "y": 50 + }, + { + "x": 200.5, + "y": 50 + }, + { + "x": 203, + "y": 50 + }, + { + "x": 206.33333333333331, + "y": 62.6 + }, + { + "x": 208.83333333333331, + "y": 81.5 + }, + { + "x": 211.33333333333334, + "y": 100.4 + }, + { + "x": 211.33333333333334, + "y": 125.6 + }, + { + "x": 208.83333333333331, + "y": 144.5 + }, + { + "x": 206.33333333333331, + "y": 163.4 + }, + { + "x": 189.66666666666669, + "y": 171.32467532467533 + }, + { + "x": 163, + "y": 152.62337662337663 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/elk_loop_panic/dagre/sketch.exp.svg b/e2etests/testdata/regression/elk_loop_panic/dagre/sketch.exp.svg new file mode 100644 index 000000000..48ca96d52 --- /dev/null +++ b/e2etests/testdata/regression/elk_loop_panic/dagre/sketch.exp.svg @@ -0,0 +1,59 @@ + +xab + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/elk_loop_panic/elk/board.exp.json b/e2etests/testdata/regression/elk_loop_panic/elk/board.exp.json new file mode 100644 index 000000000..58c402aea --- /dev/null +++ b/e2etests/testdata/regression/elk_loop_panic/elk/board.exp.json @@ -0,0 +1,175 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 446, + "height": 276, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 18, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "x.a", + "type": "", + "pos": { + "x": 137, + "y": 87 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "x.b", + "type": "", + "pos": { + "x": 270, + "y": 87 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 2 + } + ], + "connections": [ + { + "id": "x.(a -> a)[0]", + "src": "x.a", + "srcArrow": "none", + "srcLabel": "", + "dst": "x.a", + "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": 137, + "y": 129 + }, + { + "x": 87, + "y": 129 + }, + { + "x": 87, + "y": 171 + }, + { + "x": 137, + "y": 171 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/elk_loop_panic/elk/sketch.exp.svg b/e2etests/testdata/regression/elk_loop_panic/elk/sketch.exp.svg new file mode 100644 index 000000000..9f81bb30e --- /dev/null +++ b/e2etests/testdata/regression/elk_loop_panic/elk/sketch.exp.svg @@ -0,0 +1,59 @@ + +xab + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/elk_order/dagre/sketch.exp.svg b/e2etests/testdata/regression/elk_order/dagre/sketch.exp.svg index 373f07923..57268f464 100644 --- a/e2etests/testdata/regression/elk_order/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/elk_order/dagre/sketch.exp.svg @@ -796,12 +796,12 @@ width="1540" height="578" viewBox="-102 -102 1540 578">

Oldest message

+

Oldest message

Offset

Last message

Next message will be
inserted here

-
M0M1M2M3M4M5M6 +
M0M1M2M3M4M5M6

Oldest message

+

Oldest message

Offset

Last message

Next message will be
inserted here

-
M0M1M2M3M4M5M6 +
M0M1M2M3M4M5M6

hey

+
    +
  • they +
      +
    1. they
    2. +
    +
  • +
+
ab + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json b/e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json new file mode 100644 index 000000000..52486aa53 --- /dev/null +++ b/e2etests/testdata/regression/md_h1_li_li/elk/board.exp.json @@ -0,0 +1,205 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "md", + "type": "text", + "pos": { + "x": 21, + "y": 238 + }, + "width": 95, + "height": 115, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "\n# hey\n- they\n\t1. they\n", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 95, + "labelHeight": 115, + "zIndex": 0, + "level": 1 + }, + { + "id": "a", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "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", + "zIndex": 0, + "level": 1 + }, + { + "id": "b", + "type": "", + "pos": { + "x": 12, + "y": 453 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "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", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(a -> md)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "", + "dst": "md", + "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": 68.5, + "y": 138 + }, + { + "x": 68.5, + "y": 238 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(md -> b)[0]", + "src": "md", + "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": 68.5, + "y": 353 + }, + { + "x": 68.5, + "y": 453 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg b/e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg new file mode 100644 index 000000000..a84a33d83 --- /dev/null +++ b/e2etests/testdata/regression/md_h1_li_li/elk/sketch.exp.svg @@ -0,0 +1,824 @@ + +

hey

+
    +
  • they +
      +
    1. they
    2. +
    +
  • +
+
ab + + +
\ No newline at end of file diff --git a/e2etests/testdata/regression/no-lexer/dagre/board.exp.json b/e2etests/testdata/regression/no-lexer/dagre/board.exp.json new file mode 100644 index 000000000..8b025b727 --- /dev/null +++ b/e2etests/testdata/regression/no-lexer/dagre/board.exp.json @@ -0,0 +1,46 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "code", + "pos": { + "x": 0, + "y": 0 + }, + "width": 73, + "height": 38, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x -> y", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "d2", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 73, + "labelHeight": 38, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/regression/no-lexer/dagre/sketch.exp.svg b/e2etests/testdata/regression/no-lexer/dagre/sketch.exp.svg new file mode 100644 index 000000000..c1aa6317e --- /dev/null +++ b/e2etests/testdata/regression/no-lexer/dagre/sketch.exp.svg @@ -0,0 +1,52 @@ + +x -> y + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/no-lexer/elk/board.exp.json b/e2etests/testdata/regression/no-lexer/elk/board.exp.json new file mode 100644 index 000000000..25c474e9c --- /dev/null +++ b/e2etests/testdata/regression/no-lexer/elk/board.exp.json @@ -0,0 +1,46 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "code", + "pos": { + "x": 12, + "y": 12 + }, + "width": 73, + "height": 38, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x -> y", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "d2", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 73, + "labelHeight": 38, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/regression/no-lexer/elk/sketch.exp.svg b/e2etests/testdata/regression/no-lexer/elk/sketch.exp.svg new file mode 100644 index 000000000..4956b6370 --- /dev/null +++ b/e2etests/testdata/regression/no-lexer/elk/sketch.exp.svg @@ -0,0 +1,52 @@ + +x -> y + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg b/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg index df46d764c..42aab1de0 100644 --- a/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg @@ -39,9 +39,9 @@ width="1286" height="548" viewBox="-102 -102 1286 548">x

linux: because a PC is a terrible thing to waste

+
a You don't have to know how the computer works,just how to work the computer. + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/opacity-on-label/elk/board.exp.json b/e2etests/testdata/regression/opacity-on-label/elk/board.exp.json new file mode 100644 index 000000000..3ae7ceeba --- /dev/null +++ b/e2etests/testdata/regression/opacity-on-label/elk/board.exp.json @@ -0,0 +1,166 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "", + "pos": { + "x": 116, + "y": 12 + }, + "width": 113, + "height": 126, + "opacity": 0.4, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "y", + "type": "text", + "pos": { + "x": 249, + "y": 63 + }, + "width": 304, + "height": 24, + "opacity": 0.4, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "#0A0F25", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "linux: because a PC is a terrible thing to waste", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 304, + "labelHeight": 24, + "zIndex": 0, + "level": 1 + }, + { + "id": "a", + "type": "", + "pos": { + "x": 116, + "y": 375 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "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", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(x -> a)[0]", + "src": "x", + "srcArrow": "none", + "srcLabel": "", + "dst": "a", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 0.4, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "You don't have to know how the computer works,\njust how to work the computer.", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 322, + "labelHeight": 37, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 173, + "y": 138 + }, + { + "x": 173, + "y": 375 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/regression/opacity-on-label/elk/sketch.exp.svg b/e2etests/testdata/regression/opacity-on-label/elk/sketch.exp.svg new file mode 100644 index 000000000..28aa950fe --- /dev/null +++ b/e2etests/testdata/regression/opacity-on-label/elk/sketch.exp.svg @@ -0,0 +1,824 @@ + +x

linux: because a PC is a terrible thing to waste

+
a You don't have to know how the computer works,just how to work the computer. + + +
\ No newline at end of file diff --git a/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg b/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg index 5a0f1cfad..281102988 100644 --- a/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg +++ b/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="1825" height="777" viewBox="-102 -102 1825 777">your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/animated/elk/board.exp.json b/e2etests/testdata/stable/animated/elk/board.exp.json new file mode 100644 index 000000000..92badcbf0 --- /dev/null +++ b/e2etests/testdata/stable/animated/elk/board.exp.json @@ -0,0 +1,864 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "your love life will be", + "type": "", + "pos": { + "x": 111, + "y": 12 + }, + "width": 247, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "your love life will be", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 147, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "happy", + "type": "", + "pos": { + "x": 12, + "y": 238 + }, + "width": 149, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "happy", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 49, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "harmonious", + "type": "", + "pos": { + "x": 181, + "y": 238 + }, + "width": 190, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "harmonious", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 90, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "boredom", + "type": "", + "pos": { + "x": 402, + "y": 12 + }, + "width": 168, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "boredom", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 68, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "immortality", + "type": "", + "pos": { + "x": 391, + "y": 238 + }, + "width": 191, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "immortality", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 91, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Friday", + "type": "", + "pos": { + "x": 607, + "y": 12 + }, + "width": 150, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Friday", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 50, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Monday", + "type": "", + "pos": { + "x": 602, + "y": 238 + }, + "width": 161, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Monday", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 61, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Insomnia", + "type": "", + "pos": { + "x": 935, + "y": 12 + }, + "width": 170, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Insomnia", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 70, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Sleep", + "type": "", + "pos": { + "x": 783, + "y": 238 + }, + "width": 145, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Sleep", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 45, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Wake", + "type": "", + "pos": { + "x": 948, + "y": 238 + }, + "width": 144, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Wake", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 44, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Dream", + "type": "", + "pos": { + "x": 1112, + "y": 238 + }, + "width": 151, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Dream", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 51, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Listen", + "type": "", + "pos": { + "x": 1225, + "y": 12 + }, + "width": 148, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Listen", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 48, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "Talk", + "type": "", + "pos": { + "x": 1231, + "y": 464 + }, + "width": 136, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "Talk", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 36, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(your love life will be -> happy)[0]", + "src": "your love life will be", + "srcArrow": "none", + "srcLabel": "", + "dst": "happy", + "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": 193.66666666666652, + "y": 138 + }, + { + "x": 193.66666666666652, + "y": 188 + }, + { + "x": 86.5, + "y": 188 + }, + { + "x": 86.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(your love life will be -> harmonious)[0]", + "src": "your love life will be", + "srcArrow": "none", + "srcLabel": "", + "dst": "harmonious", + "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": 275.9999999999999, + "y": 138 + }, + { + "x": 276, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(boredom <- immortality)[0]", + "src": "boredom", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "immortality", + "dstArrow": "none", + "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": 486.5, + "y": 138 + }, + { + "x": 486.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Friday <-> Monday)[0]", + "src": "Friday", + "srcArrow": "triangle", + "srcLabel": "", + "dst": "Monday", + "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": 682.5, + "y": 138 + }, + { + "x": 682.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Insomnia -- Sleep)[0]", + "src": "Insomnia", + "srcArrow": "none", + "srcLabel": "", + "dst": "Sleep", + "dstArrow": "none", + "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": 977.5, + "y": 138 + }, + { + "x": 977.5, + "y": 188 + }, + { + "x": 855.5, + "y": 188 + }, + { + "x": 855.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Insomnia -- Wake)[0]", + "src": "Insomnia", + "srcArrow": "none", + "srcLabel": "", + "dst": "Wake", + "dstArrow": "none", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1020, + "y": 138 + }, + { + "x": 1020, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Insomnia -- Dream)[0]", + "src": "Insomnia", + "srcArrow": "none", + "srcLabel": "", + "dst": "Dream", + "dstArrow": "none", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 8, + "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": 1062.5, + "y": 138 + }, + { + "x": 1062.5, + "y": 188 + }, + { + "x": 1187.5, + "y": 188 + }, + { + "x": 1187.5, + "y": 238 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(Listen <-> Talk)[0]", + "src": "Listen", + "srcArrow": "cf-one", + "srcLabel": "", + "dst": "Talk", + "dstArrow": "diamond", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "hear", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 32, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1299, + "y": 138 + }, + { + "x": 1299, + "y": 464 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/animated/elk/sketch.exp.svg b/e2etests/testdata/stable/animated/elk/sketch.exp.svg new file mode 100644 index 000000000..f3c7a07da --- /dev/null +++ b/e2etests/testdata/stable/animated/elk/sketch.exp.svg @@ -0,0 +1,65 @@ + +your love life will behappyharmoniousboredomimmortalityFridayMondayInsomniaSleepWakeDreamListenTalk hear + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg index 90796e221..3eb3587e4 100644 --- a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="494" height="793" viewBox="-108 -107 494 793">aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 +aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 diff --git a/e2etests/testdata/stable/chaos2/elk/board.exp.json b/e2etests/testdata/stable/chaos2/elk/board.exp.json index 88ff7eaf6..4c3490841 100644 --- a/e2etests/testdata/stable/chaos2/elk/board.exp.json +++ b/e2etests/testdata/stable/chaos2/elk/board.exp.json @@ -9,8 +9,8 @@ "x": 12, "y": 12 }, - "width": 892, - "height": 1704, + "width": 1071, + "height": 2534, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -46,11 +46,11 @@ "id": "aa.bb", "type": "", "pos": { - "x": 107, - "y": 465 + "x": 87, + "y": 815 }, - "width": 722, - "height": 1151, + "width": 875, + "height": 1551, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -86,11 +86,11 @@ "id": "aa.bb.cc", "type": "", "pos": { - "x": 281, - "y": 841 + "x": 423, + "y": 1271 }, - "width": 473, - "height": 700, + "width": 464, + "height": 1020, "opacity": 1, "strokeDash": 0, "strokeWidth": 2, @@ -126,8 +126,8 @@ "id": "aa.bb.cc.dd", "type": "rectangle", "pos": { - "x": 356, - "y": 916 + "x": 498, + "y": 1346 }, "width": 303, "height": 276, @@ -166,8 +166,8 @@ "id": "aa.bb.cc.dd.ee", "type": "text", "pos": { - "x": 431, - "y": 1096 + "x": 573, + "y": 1526 }, "width": 16, "height": 21, @@ -205,8 +205,8 @@ "id": "aa.bb.cc.dd.ff", "type": "", "pos": { - "x": 467, - "y": 991 + "x": 609, + "y": 1421 }, "width": 117, "height": 126, @@ -245,8 +245,8 @@ "id": "aa.bb.cc.gg", "type": "text", "pos": { - "x": 433, - "y": 1258 + "x": 575, + "y": 1848 }, "width": 17, "height": 21, @@ -284,8 +284,8 @@ "id": "aa.bb.cc.hh", "type": "", "pos": { - "x": 380, - "y": 1340 + "x": 522, + "y": 2090 }, "width": 123, "height": 126, @@ -324,8 +324,8 @@ "id": "aa.bb.ii", "type": "package", "pos": { - "x": 181, - "y": 540 + "x": 162, + "y": 890 }, "width": 265, "height": 276, @@ -364,8 +364,8 @@ "id": "aa.bb.ii.jj", "type": "diamond", "pos": { - "x": 256, - "y": 615 + "x": 237, + "y": 965 }, "width": 115, "height": 126, @@ -404,8 +404,8 @@ "id": "aa.bb.kk", "type": "oval", "pos": { - "x": 533, - "y": 615 + "x": 447, + "y": 965 }, "width": 126, "height": 126, @@ -444,8 +444,8 @@ "id": "aa.ll", "type": "", "pos": { - "x": 343, - "y": 243 + "x": 612, + "y": 363 }, "width": 114, "height": 126, @@ -484,7 +484,7 @@ "id": "aa.mm", "type": "cylinder", "pos": { - "x": 348, + "x": 502, "y": 87 }, "width": 131, @@ -524,7 +524,7 @@ "id": "aa.nn", "type": "text", "pos": { - "x": 499, + "x": 653, "y": 139 }, "width": 16, @@ -563,7 +563,7 @@ "id": "aa.oo", "type": "", "pos": { - "x": 535, + "x": 689, "y": 87 }, "width": 123, @@ -627,12 +627,12 @@ "labelPercentage": 0, "route": [ { - "x": 439.33333333333326, - "y": 1117 + "x": 581, + "y": 1547 }, { - "x": 439.3333333333332, - "y": 1258 + "x": 581, + "y": 1848 } ], "animated": false, @@ -666,12 +666,12 @@ "labelPercentage": 0, "route": [ { - "x": 442.1666666666666, - "y": 1279 + "x": 583.8333333333333, + "y": 1869 }, { - "x": 442.16666666666663, - "y": 1340 + "x": 583.8333333333334, + "y": 2090 } ], "animated": false, @@ -705,20 +705,20 @@ "labelPercentage": 0, "route": [ { - "x": 359, - "y": 816 + "x": 339, + "y": 1166 }, { - "x": 358.66666666666663, - "y": 826 + "x": 338.66666666666663, + "y": 1216 }, { - "x": 431.33333333333326, - "y": 826 + "x": 573, + "y": 1216 }, { - "x": 431.33333333333326, - "y": 916 + "x": 573, + "y": 1346 } ], "animated": false, @@ -752,20 +752,20 @@ "labelPercentage": 0, "route": [ { - "x": 411.9, - "y": 369 + "x": 634.8, + "y": 489 }, { - "x": 411.9, - "y": 389 + "x": 634.8, + "y": 710 }, { - "x": 659.3333333333333, - "y": 389 + "x": 593, + "y": 710 }, { - "x": 659.3333333333333, - "y": 465 + "x": 593, + "y": 815 } ], "animated": false, @@ -799,36 +799,20 @@ "labelPercentage": 0, "route": [ { - "x": 453, - "y": 209 + "x": 581, + "y": 213 }, { - "x": 452.9, - "y": 223 + "x": 581.4, + "y": 313 }, { - "x": 716.8333333333333, - "y": 223 + "x": 583, + "y": 313 }, { - "x": 716.8333333333333, - "y": 450 - }, - { - "x": 689.3333333333333, - "y": 450 - }, - { - "x": 689.3333333333333, - "y": 826 - }, - { - "x": 679.3333333333333, - "y": 826 - }, - { - "x": 679.3333333333333, - "y": 841 + "x": 583, + "y": 1271 } ], "animated": false, @@ -862,12 +846,20 @@ "labelPercentage": 0, "route": [ { - "x": 400, - "y": 213 + "x": 608, + "y": 209 }, { - "x": 400.49999999999994, - "y": 243 + "x": 607.6, + "y": 263 + }, + { + "x": 669, + "y": 263 + }, + { + "x": 669, + "y": 363 } ], "animated": false, @@ -901,28 +893,28 @@ "labelPercentage": 0, "route": [ { - "x": 427, + "x": 555, "y": 213 }, { - "x": 426.69999999999993, - "y": 233 + "x": 555.2, + "y": 263 }, { - "x": 689.8333333333333, - "y": 233 + "x": 556, + "y": 263 }, { - "x": 689.8333333333333, - "y": 440 + "x": 556, + "y": 760 }, { - "x": 679.3333333333333, - "y": 440 + "x": 304.5, + "y": 760 }, { - "x": 679.3333333333333, - "y": 465 + "x": 304.5, + "y": 815 } ], "animated": false, @@ -956,36 +948,28 @@ "labelPercentage": 0, "route": [ { - "x": 434.69999999999993, - "y": 369 + "x": 657.6, + "y": 489 }, { - "x": 434.69999999999993, - "y": 379 + "x": 657.6, + "y": 710 }, { - "x": 678.8333333333333, - "y": 379 + "x": 811, + "y": 710 }, { - "x": 678.8333333333333, - "y": 430 + "x": 811, + "y": 1798 }, { - "x": 669.3333333333333, - "y": 430 + "x": 586.6666666666666, + "y": 1798 }, { - "x": 669.3333333333333, - "y": 1248 - }, - { - "x": 445, - "y": 1248 - }, - { - "x": 445, - "y": 1258 + "x": 586.6666666666666, + "y": 1848 } ], "animated": false, @@ -1019,20 +1003,20 @@ "labelPercentage": 0, "route": [ { - "x": 374, + "x": 529, "y": 209 }, { - "x": 374.29999999999995, - "y": 223 + "x": 529, + "y": 710 }, { - "x": 314.49999999999994, - "y": 223 + "x": 294.5, + "y": 710 }, { - "x": 314, - "y": 540 + "x": 295, + "y": 890 } ], "animated": false, @@ -1066,36 +1050,28 @@ "labelPercentage": 0, "route": [ { - "x": 356.33333333333326, - "y": 1541 + "x": 498, + "y": 2291 }, { - "x": 356.33333333333326, - "y": 1641 + "x": 498, + "y": 2421 }, { - "x": 87, - "y": 1641 + "x": 972, + "y": 2421 }, { - "x": 87, - "y": 430 + "x": 972, + "y": 589 }, { - "x": 333.49999999999994, - "y": 430 + "x": 680.4, + "y": 589 }, { - "x": 333.49999999999994, - "y": 379 - }, - { - "x": 366.29999999999995, - "y": 379 - }, - { - "x": 366.29999999999995, - "y": 369 + "x": 680.4, + "y": 489 } ], "animated": false, @@ -1129,28 +1105,28 @@ "labelPercentage": 0, "route": [ { - "x": 270, - "y": 816 + "x": 250, + "y": 1166 }, { - "x": 270.33333333333326, - "y": 1631 + "x": 250.33333333333331, + "y": 2471 }, { - "x": 97, - "y": 1631 + "x": 999, + "y": 2471 }, { - "x": 97, - "y": 440 + "x": 999, + "y": 539 }, { - "x": 389.09999999999997, - "y": 440 + "x": 703.2, + "y": 539 }, { - "x": 389.09999999999997, - "y": 369 + "x": 703.2, + "y": 489 } ], "animated": false, diff --git a/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg b/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg index e616b37b0..e1498a328 100644 --- a/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg @@ -3,7 +3,7 @@ id="d2-svg" style="background: white;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" -width="1096" height="1908" viewBox="-90 -90 1096 1908">aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 - - - - - - - - - +aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 + + + + + + + + + xyThe top of the mountainJoeDonald

Cats, no less liquid than their shadows, offer no angles to the wind.

+xyThe top of the mountainJoeDonald

Cats, no less liquid than their shadows, offer no angles to the wind.

If we can't fix it, it ain't broke.

Dieters live life in the fasting lane.

-
i am top lefti am top righti am bottom lefti am bottom right - +
i am top lefti am top righti am bottom lefti am bottom right + xyThe top of the mountainJoeDonald

Cats, no less liquid than their shadows, offer no angles to the wind.

+xyThe top of the mountainJoeDonald

Cats, no less liquid than their shadows, offer no angles to the wind.

If we can't fix it, it ain't broke.

Dieters live life in the fasting lane.

-
i am top lefti am top righti am bottom lefti am bottom right - +
i am top lefti am top righti am bottom lefti am bottom right + poll the peopleresultsunfavorablefavorablewill of the people

A winning strategy

-
- +poll the peopleresultsunfavorablefavorablewill of the people

A winning strategy

+
+ poll the peopleresultsunfavorablefavorablewill of the people

A winning strategy

-
- +poll the peopleresultsunfavorablefavorablewill of the people

A winning strategy

+
+

Markdown: Syntax

+

Markdown: Syntax

  • Overview
      @@ -1053,8 +1053,8 @@ title for the link, surrounded in quotes. For example:

      Code

      Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

      -
ab - +
ab +

Markdown: Syntax

+

Markdown: Syntax

  • Overview
      @@ -1053,8 +1053,8 @@ title for the link, surrounded in quotes. For example:

      Code

      Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

      -
ab - +
ab +

Note: This document is itself written using Markdown; you +

Note: This document is itself written using Markdown; you can see the source for it by adding '.text' to the URL.


Overview

-
ab - +
ab +

Note: This document is itself written using Markdown; you +

Note: This document is itself written using Markdown; you can see the source for it by adding '.text' to the URL.


Overview

-
ab - +
ab + mixed togethersugarsolution we get +mixed togethersugarsolution we get mixed togethersugarsolution we get +mixed togethersugarsolution we get

Markdown: Syntax

-
ab - +

Markdown: Syntax

+
ab +

Markdown: Syntax

-
ab - +

Markdown: Syntax

+
ab +

Every frustum longs to be a cone

+

Every frustum longs to be a cone

  • A continuing flow of paper is sufficient to continue the flow of paper
  • Please remain calm, it's no use both of us being hysterical at the same time
  • Visits always give pleasure: if not on arrival, then on the departure

Festivity Level 1: Your guests are chatting amiably with each other.

-
xy - +
xy +

Every frustum longs to be a cone

+

Every frustum longs to be a cone

  • A continuing flow of paper is sufficient to continue the flow of paper
  • Please remain calm, it's no use both of us being hysterical at the same time
  • Visits always give pleasure: if not on arrival, then on the departure

Festivity Level 1: Your guests are chatting amiably with each other.

-
xy - +
xy + container

they did it in style

-

a header

+container

they did it in style

+

a header

a line of text and an

{
 	indented: "block",
@@ -805,8 +805,8 @@ width="516" height="685" viewBox="-102 -102 516 685">container

they did it in style

-

a header

+container

they did it in style

+

a header

a line of text and an

{
 	indented: "block",
@@ -805,8 +805,8 @@ width="566" height="735" viewBox="-90 -90 566 735">markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

diff --git a/e2etests/testdata/stable/md_2space_newline/elk/sketch.exp.svg b/e2etests/testdata/stable/md_2space_newline/elk/sketch.exp.svg index 556034da3..20588b494 100644 --- a/e2etests/testdata/stable/md_2space_newline/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/md_2space_newline/elk/sketch.exp.svg @@ -796,7 +796,7 @@ width="813" height="402" viewBox="-90 -90 813 402">markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

diff --git a/e2etests/testdata/stable/md_backslash_newline/dagre/sketch.exp.svg b/e2etests/testdata/stable/md_backslash_newline/dagre/sketch.exp.svg index 02882dac2..c8ae1c67d 100644 --- a/e2etests/testdata/stable/md_backslash_newline/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/md_backslash_newline/dagre/sketch.exp.svg @@ -796,7 +796,7 @@ width="763" height="352" viewBox="-102 -102 763 352">markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

diff --git a/e2etests/testdata/stable/md_backslash_newline/elk/sketch.exp.svg b/e2etests/testdata/stable/md_backslash_newline/elk/sketch.exp.svg index 36b39bde1..675ff5992 100644 --- a/e2etests/testdata/stable/md_backslash_newline/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/md_backslash_newline/elk/sketch.exp.svg @@ -796,7 +796,7 @@ width="813" height="402" viewBox="-90 -90 813 402">markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+markdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

diff --git a/e2etests/testdata/stable/md_code_block_fenced/dagre/sketch.exp.svg b/e2etests/testdata/stable/md_code_block_fenced/dagre/sketch.exp.svg index e6e3efc9b..f56147b8e 100644 --- a/e2etests/testdata/stable/md_code_block_fenced/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/md_code_block_fenced/dagre/sketch.exp.svg @@ -801,7 +801,7 @@ width="400" height="767" viewBox="-102 -102 400 767">

code

-
ab +
ab

code

-
ab +
ab xy + + + + + + + + + + + + + + +I like turtlesab + + + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json new file mode 100644 index 000000000..e869a4914 --- /dev/null +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json @@ -0,0 +1,189 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "sql_table", + "pos": { + "x": 12, + "y": 12 + }, + "width": 60, + "height": 72, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "I like turtles", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "y", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 10, + "labelHeight": 26 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "a.b" + } + ], + "label": "x", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 17, + "labelHeight": 36, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" + }, + { + "id": "a", + "type": "sql_table", + "pos": { + "x": 12, + "y": 184 + }, + "width": 60, + "height": 72, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "b", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 10, + "labelHeight": 26 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "" + } + ], + "label": "a", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 16, + "labelHeight": 36, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" + } + ], + "connections": [ + { + "id": "(x -> a)[0]", + "src": "x", + "srcArrow": "none", + "srcLabel": "", + "dst": "a", + "dstArrow": "cf-many", + "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": 42, + "y": 84 + }, + { + "x": 42, + "y": 184 + } + ], + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg new file mode 100644 index 000000000..f7d9f5b56 --- /dev/null +++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg @@ -0,0 +1,78 @@ + +xy + + + + + + + + + + + + + + +I like turtlesab + + + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg index 025bd88a8..a20a91845 100644 --- a/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="1000" height="664" viewBox="-102 -102 1000 664">bearmama bearpapa bear +bearmama bearpapa bear bearmama bearpapa bear +bearmama bearpapa bear