diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 489a520f2..c3fb0f722 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -1,8 +1,18 @@ #### Features ๐Ÿš€ +- `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) +- Icon URLs that needed escaping (e.g. with ampersands) are handled correctly by CLI. [#666](https://github.com/terrastruct/d2/pull/666) 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 1dd1791a6..85521f0ac 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/d2renderers/d2sketch/sketch.go b/d2renderers/d2sketch/sketch.go index e5ceab8aa..5c5ce2d3b 100644 --- a/d2renderers/d2sketch/sketch.go +++ b/d2renderers/d2sketch/sketch.go @@ -3,6 +3,8 @@ package d2sketch import ( "encoding/json" "fmt" + "regexp" + "strings" _ "embed" @@ -31,6 +33,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) @@ -74,7 +78,7 @@ func Rect(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } @@ -83,7 +87,7 @@ func Rect(r *Runner, shape d2target.Shape) (string, error) { pathEl.Transform = fmt.Sprintf("translate(%d %d)", shape.Pos.X, shape.Pos.Y) pathEl.Fill, pathEl.Stroke = svg_style.ShapeTheme(shape) pathEl.Class = "shape" - pathEl.Style = svg_style.ShapeStyle(shape) + pathEl.Style = shape.CSSStyle() for _, p := range paths { pathEl.D = p output += pathEl.Render() @@ -109,7 +113,7 @@ func Oval(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width/2, shape.Height/2, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } @@ -118,7 +122,7 @@ func Oval(r *Runner, shape d2target.Shape) (string, error) { pathEl.Transform = fmt.Sprintf("translate(%d %d)", shape.Pos.X, shape.Pos.Y) pathEl.Fill, pathEl.Stroke = svg_style.ShapeTheme(shape) pathEl.Class = "shape" - pathEl.Style = svg_style.ShapeStyle(shape) + pathEl.Style = shape.CSSStyle() for _, p := range paths { pathEl.D = p output += pathEl.Render() @@ -150,14 +154,14 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) { strokeWidth: %d, %s });`, path, shape.StrokeWidth, baseRoughProps) - sketchPaths, err := computeRoughPaths(r, js) + sketchPaths, err := computeRoughPathData(r, js) if err != nil { return "", err } pathEl := svg_style.NewThemableElement("path") pathEl.Fill, pathEl.Stroke = svg_style.ShapeTheme(shape) pathEl.Class = "shape" - pathEl.Style = svg_style.ShapeStyle(shape) + pathEl.Style = shape.CSSStyle() for _, p := range sketchPaths { pathEl.D = p output += pathEl.Render() @@ -182,7 +186,7 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) { 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 } @@ -191,7 +195,7 @@ func Connection(r *Runner, connection d2target.Connection, path, attrs string) ( pathEl.Fill = color.None pathEl.Stroke = svg_style.ConnectionTheme(connection) pathEl.Class = "connection" - pathEl.Style = svg_style.ConnectionStyle(connection) + pathEl.Style = connection.CSSStyle() pathEl.Attributes = attrs for _, p := range paths { pathEl.D = p @@ -209,7 +213,7 @@ func Table(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } @@ -217,7 +221,7 @@ func Table(r *Runner, shape d2target.Shape) (string, error) { pathEl.Transform = fmt.Sprintf("translate(%d %d)", shape.Pos.X, shape.Pos.Y) pathEl.Fill, pathEl.Stroke = svg_style.ShapeTheme(shape) pathEl.Class = "shape" - pathEl.Style = svg_style.ShapeStyle(shape) + pathEl.Style = shape.CSSStyle() for _, p := range paths { pathEl.D = p output += pathEl.Render() @@ -235,7 +239,7 @@ func Table(r *Runner, shape d2target.Shape) (string, error) { fill: "#000", %s });`, shape.Width, rowHeight, baseRoughProps) - paths, err = computeRoughPaths(r, js) + paths, err = computeRoughPathData(r, js) if err != nil { return "", err } @@ -315,7 +319,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 } @@ -348,7 +352,7 @@ func Class(r *Runner, shape d2target.Shape) (string, error) { strokeWidth: %d, %s });`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps) - paths, err := computeRoughPaths(r, js) + paths, err := computeRoughPathData(r, js) if err != nil { return "", err } @@ -356,6 +360,7 @@ func Class(r *Runner, shape d2target.Shape) (string, error) { pathEl.Transform = fmt.Sprintf("translate(%d %d)", shape.Pos.X, shape.Pos.Y) pathEl.Fill, pathEl.Stroke = svg_style.ShapeTheme(shape) pathEl.Class = "shape" + pathEl.Style = shape.CSSStyle() for _, p := range paths { pathEl.D = p output += pathEl.Render() @@ -374,7 +379,7 @@ func Class(r *Runner, shape d2target.Shape) (string, error) { fill: "#000", %s });`, shape.Width, headerBox.Height, baseRoughProps) - paths, err = computeRoughPaths(r, js) + paths, err = computeRoughPathData(r, js) if err != nil { return "", err } @@ -428,7 +433,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 } @@ -487,38 +492,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 af821700a..638d0d320 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,52 @@ 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 +} `, }, { diff --git a/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg b/d2renderers/d2sketch/testdata/all_shapes/sketch.exp.svg index efb2c8aba..8496e2c0f 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..05f0b4575 --- /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..085125e38 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"> + +# 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..5f47f871b --- /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..657dbb9f6 --- /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..1160dee24 --- /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/stable/animated/dagre/board.exp.json b/e2etests/testdata/stable/animated/dagre/board.exp.json new file mode 100644 index 000000000..0acdeb9d5 --- /dev/null +++ b/e2etests/testdata/stable/animated/dagre/board.exp.json @@ -0,0 +1,912 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "your love life will be", + "type": "", + "pos": { + "x": 58, + "y": 0 + }, + "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": 0, + "y": 247 + }, + "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": 209, + "y": 247 + }, + "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": 471, + "y": 247 + }, + "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": 460, + "y": 0 + }, + "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": 711, + "y": 0 + }, + "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": 705, + "y": 247 + }, + "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": 1126, + "y": 0 + }, + "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": 930, + "y": 247 + }, + "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": 1135, + "y": 247 + }, + "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": 1339, + "y": 247 + }, + "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": 1552, + "y": 0 + }, + "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": 1558, + "y": 247 + }, + "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": 126.917004048583, + "y": 126 + }, + { + "x": 84.9834008097166, + "y": 174.4 + }, + { + "x": 74.5, + "y": 198.7 + }, + { + "x": 74.5, + "y": 247.5 + } + ], + "isCurve": true, + "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": 243.98987854251013, + "y": 126 + }, + { + "x": 291.99797570850205, + "y": 174.4 + }, + { + "x": 304, + "y": 198.7 + }, + { + "x": 304, + "y": 247.5 + } + ], + "isCurve": true, + "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": 555.25, + "y": 247 + }, + { + "x": 555.25, + "y": 198.6 + }, + { + "x": 555.25, + "y": 174.3 + }, + { + "x": 555.25, + "y": 125.5 + } + ], + "isCurve": true, + "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": 785.75, + "y": 126 + }, + { + "x": 785.75, + "y": 174.4 + }, + { + "x": 785.75, + "y": 198.7 + }, + { + "x": 785.75, + "y": 247.5 + } + ], + "isCurve": true, + "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": 1126, + "y": 113.2874251497006 + }, + { + "x": 1027, + "y": 171.8574850299401 + }, + { + "x": 1002.25, + "y": 198.7 + }, + { + "x": 1002.25, + "y": 247.5 + } + ], + "isCurve": true, + "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": 1208.831983805668, + "y": 126 + }, + { + "x": 1207.1663967611337, + "y": 174.4 + }, + { + "x": 1206.75, + "y": 198.7 + }, + { + "x": 1206.75, + "y": 247.5 + } + ], + "isCurve": true, + "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": 1296, + "y": 114.64821648216483 + }, + { + "x": 1390.6, + "y": 172.12964329643296 + }, + { + "x": 1414.25, + "y": 198.7 + }, + { + "x": 1414.25, + "y": 247.5 + } + ], + "isCurve": true, + "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": 1625.5, + "y": 126 + }, + { + "x": 1625.5, + "y": 174.4 + }, + { + "x": 1625.5, + "y": 198.7 + }, + { + "x": 1625.5, + "y": 247.5 + } + ], + "isCurve": true, + "animated": true, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/animated/dagre/sketch.exp.svg b/e2etests/testdata/stable/animated/dagre/sketch.exp.svg new file mode 100644 index 000000000..472f2ae90 --- /dev/null +++ b/e2etests/testdata/stable/animated/dagre/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/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..5d3c01de3 --- /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/chaos2/dagre/board.exp.json b/e2etests/testdata/stable/chaos2/dagre/board.exp.json index 12a1513a1..241154fec 100644 --- a/e2etests/testdata/stable/chaos2/dagre/board.exp.json +++ b/e2etests/testdata/stable/chaos2/dagre/board.exp.json @@ -822,20 +822,11 @@ "x": 925, "y": 745.597137014315 }, - { - "x": 847.4, - "y": 758.3971370143149 - }, - { - "x": 905.6, - "y": 748.797137014315 - }, { "x": 828, "y": 761.597137014315 } ], - "isCurve": true, "animated": false, "tooltip": "", "icon": null, @@ -978,20 +969,11 @@ "x": 912, "y": 522 }, - { - "x": 845, - "y": 533.8777110844337 - }, - { - "x": 895.25, - "y": 524.9694277711085 - }, { "x": 828.25, "y": 536.8471388555422 } ], - "isCurve": true, "animated": false, "tooltip": "", "icon": null, diff --git a/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg b/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg index 5631cb34a..e540281c0 100644 --- a/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg @@ -796,7 +796,7 @@ width="1331" height="1939" viewBox="-102 -102 1331 1939">aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 +aabbllmmnnoocciikkddgghhjjeeff1122 334455667788 diff --git a/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json b/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json index d64f023cc..29604db23 100644 --- a/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json +++ b/e2etests/testdata/stable/child_parent_edges/dagre/board.exp.json @@ -361,20 +361,11 @@ "x": 243.66666666666669, "y": 238 }, - { - "x": 243.93333333333334, - "y": 237.99628770301624 - }, - { - "x": 243.73333333333335, - "y": 237.99907192575407 - }, { "x": 244, "y": 237.9953596287703 } ], - "isCurve": true, "animated": false, "tooltip": "", "icon": null, diff --git a/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg b/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg index c157addac..f8a893097 100644 --- a/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/child_parent_edges/dagre/sketch.exp.svg @@ -39,7 +39,7 @@ width="698" height="630" viewBox="-102 -102 698 630">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..ef9d36cc8 --- /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/lib/geo/point.go b/lib/geo/point.go index 13275db79..0acc5021b 100644 --- a/lib/geo/point.go +++ b/lib/geo/point.go @@ -187,12 +187,12 @@ func (p *Point) DistanceToLine(p1, p2 *Point) float64 { // Moves the given point by Vector func (start *Point) AddVector(v Vector) *Point { - return start.toVector().Add(v).ToPoint() + return start.ToVector().Add(v).ToPoint() } // Creates a Vector of the size between start and endpoint, pointing to endpoint func (start *Point) VectorTo(endpoint *Point) Vector { - return endpoint.toVector().Minus(start.toVector()) + return endpoint.ToVector().Minus(start.ToVector()) } func (p *Point) FormattedCoordinates() string { @@ -205,7 +205,7 @@ func (q *Point) OnSegment(p, r *Point) bool { } // Creates a Vector pointing to point -func (endpoint *Point) toVector() Vector { +func (endpoint *Point) ToVector() Vector { return []float64{endpoint.X, endpoint.Y} } diff --git a/lib/geo/point_test.go b/lib/geo/point_test.go index 259975897..343f8bb30 100644 --- a/lib/geo/point_test.go +++ b/lib/geo/point_test.go @@ -29,7 +29,7 @@ func TestAddVector(t *testing.T) { func TestToVector(t *testing.T) { p := &Point{3.5, 6.7} - v := p.toVector() + v := p.ToVector() if v[0] != p.X || v[1] != p.Y { t.Fatalf("Expected Vector (%v) coordinates to match the point (%v)", p, v) diff --git a/lib/geo/segment.go b/lib/geo/segment.go index 473cb12e8..df6f64a5c 100644 --- a/lib/geo/segment.go +++ b/lib/geo/segment.go @@ -114,3 +114,11 @@ func (segment *Segment) GetBounds(segments []*Segment, buffer float64) (float64, } return floor, ceil } + +func (segment Segment) Length() float64 { + return EuclideanDistance(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y) +} + +func (segment Segment) ToVector() Vector { + return NewVector(segment.End.X-segment.Start.X, segment.End.Y-segment.Start.Y) +} diff --git a/lib/geo/vector.go b/lib/geo/vector.go index 199fe73db..db1bb107b 100644 --- a/lib/geo/vector.go +++ b/lib/geo/vector.go @@ -76,3 +76,15 @@ func GetUnitNormalVector(x1, y1, x2, y2 float64) (float64, float64) { length := EuclideanDistance(x1, y1, x2, y2) return normalX / length, normalY / length } + +func (a Vector) Radians() float64 { + return math.Atan2(a[1], a[0]) +} + +func (a Vector) Degrees() float64 { + return a.Radians() * 180 / math.Pi +} + +func (a Vector) Reverse() Vector { + return a.Multiply(-1) +} diff --git a/lib/imgbundler/imgbundler.go b/lib/imgbundler/imgbundler.go index e1b719687..5c6de7038 100644 --- a/lib/imgbundler/imgbundler.go +++ b/lib/imgbundler/imgbundler.go @@ -5,6 +5,7 @@ import ( "context" "encoding/base64" "fmt" + "html" "io/ioutil" "mime" "net/http" @@ -66,7 +67,7 @@ func filterImageElements(imgs [][][]byte, isRemote bool) [][][]byte { continue } - u, err := url.Parse(href) + u, err := url.Parse(html.UnescapeString(href)) isRemoteImg := err == nil && strings.HasPrefix(u.Scheme, "http") if isRemoteImg == isRemote { @@ -147,9 +148,9 @@ func worker(ctx context.Context, href []byte, isRemote bool) ([]byte, error) { var mimeType string var err error if isRemote { - buf, mimeType, err = httpGet(ctx, string(href)) + buf, mimeType, err = httpGet(ctx, html.UnescapeString(string(href))) } else { - buf, err = os.ReadFile(string(href)) + buf, err = os.ReadFile(html.UnescapeString(string(href))) } if err != nil { return nil, err @@ -194,7 +195,7 @@ func httpGet(ctx context.Context, href string) ([]byte, string, error) { func sniffMimeType(href, buf []byte, isRemote bool) string { p := string(href) if isRemote { - u, err := url.Parse(p) + u, err := url.Parse(html.UnescapeString(p)) if err != nil { p = "" } else { diff --git a/testdata/d2compiler/TestCompile/table_connection_attr.exp.json b/testdata/d2compiler/TestCompile/table_connection_attr.exp.json new file mode 100644 index 000000000..2dc6c143d --- /dev/null +++ b/testdata/d2compiler/TestCompile/table_connection_attr.exp.json @@ -0,0 +1,570 @@ +{ + "graph": { + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-11:0:99", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-3:1:29", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:3:3-3:0:28", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:2:7-1:18:23", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:2:7-1:7:12", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:2:7-1:7:12", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,1:9:14-1:18:23", + "value": [ + { + "string": "sql_table", + "raw_string": "sql_table" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,2:2:26-2:3:27", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,2:2:26-2:3:27", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,2:2:26-2:3:27", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-7:1:59", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:3:33-7:0:58", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:2:37-5:18:53", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:2:37-5:7:42", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:2:37-5:7:42", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,5:9:44-5:18:53", + "value": [ + { + "string": "sql_table", + "raw_string": "sql_table" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,6:2:56-6:3:57", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,6:2:56-6:3:57", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,6:2:56-6:3:57", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-10:1:98", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:10:70", + "src": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:4:64", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:1:61", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:2:62-8:3:63", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:6:66-8:10:70", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:7:67-8:8:68", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:9:69-8:10:70", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:12:72-10:0:97", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:2:76-9:22:96", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:2:76-9:16:90", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:2:76-9:7:81", + "value": [ + { + "string": "style", + "raw_string": "style" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:8:82-9:16:90", + "value": [ + { + "string": "animated", + "raw_string": "animated" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "boolean": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,9:18:92-9:22:96", + "value": true + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "attributes": { + "label": { + "value": "" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + }, + "edges": [ + { + "index": 0, + "minWidth": 0, + "minHeight": 0, + "srcTableColumnIndex": 0, + "dstTableColumnIndex": 0, + "label_dimensions": { + "width": 0, + "height": 0 + }, + "isCurve": false, + "src_arrow": false, + "dst_arrow": true, + "references": [ + { + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "" + }, + "style": { + "animated": { + "value": "true" + } + }, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + } + ], + "objects": [ + { + "id": "x", + "id_val": "x", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,0:0:0-0:1:1", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + }, + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:4:64", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:0:60-8:1:61", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:2:62-8:3:63", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "sql_table": { + "columns": [ + { + "name": { + "label": "y", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "a.b" + } + ] + }, + "attributes": { + "label": { + "value": "x" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "sql_table" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + }, + { + "id": "a", + "id_val": "a", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,4:0:30-4:1:31", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + }, + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:6:66-8:10:70", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:7:67-8:8:68", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/table_connection_attr.d2,8:9:69-8:10:70", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "sql_table": { + "columns": [ + { + "name": { + "label": "b", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "type": { + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0 + }, + "constraint": "", + "reference": "" + } + ] + }, + "attributes": { + "label": { + "value": "a" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "sql_table" + }, + "direction": { + "value": "" + } + }, + "zIndex": 0 + } + ] + }, + "err": null +}