From 3d9c35d2446709adfcaadc1a4e168d6f8aef194e Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 9 Nov 2022 11:10:51 -0800 Subject: [PATCH 1/5] add shadow keyword --- d2renderers/d2svg/d2svg.go | 51 ++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 042ecc48e..6a76331b3 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -444,16 +444,28 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma } } -func renderOval(tl *geo.Point, width, height float64, style string) string { +func renderOval(tl *geo.Point, width, height float64, style, shadowAttr string) string { rx := width / 2 ry := height / 2 cx := tl.X + rx cy := tl.Y + ry - return fmt.Sprintf(``, - cx, cy, rx, ry, style, + return fmt.Sprintf(``, + cx, cy, rx, ry, style, shadowAttr, ) } +func defineShadowFilter(writer io.Writer) { + fmt.Fprint(writer, ` + + + + + + + +`) +} + func drawShape(writer io.Writer, targetShape d2target.Shape) error { tl := geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)) width := float64(targetShape.Width) @@ -468,6 +480,11 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { multipleTL = tl.AddVector(multipleOffset) } + var shadowAttr string + if targetShape.Shadow { + shadowAttr = `filter="url(#shadow-filter)" ` + } + switch targetShape.Type { case d2target.ShapeClass: drawClass(writer, targetShape) @@ -477,34 +494,34 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { return nil case d2target.ShapeOval: if targetShape.Multiple { - fmt.Fprint(writer, renderOval(multipleTL, width, height, style)) + fmt.Fprint(writer, renderOval(multipleTL, width, height, style, shadowAttr)) } - fmt.Fprint(writer, renderOval(tl, width, height, style)) + fmt.Fprint(writer, renderOval(tl, width, height, style, shadowAttr)) case d2target.ShapeImage: - fmt.Fprintf(writer, ``, + fmt.Fprintf(writer, ``, targetShape.Icon.String(), - targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style) + targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style, shadowAttr) case d2target.ShapeText: case d2target.ShapeCode: // TODO should standardize "" to rectangle case d2target.ShapeRectangle, "": if targetShape.Multiple { - fmt.Fprintf(writer, ``, - targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style) + fmt.Fprintf(writer, ``, + targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style, shadowAttr) } - fmt.Fprintf(writer, ``, - targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style) + fmt.Fprintf(writer, ``, + targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style, shadowAttr) default: if targetShape.Multiple { multiplePathData := shape.NewShape(shapeType, geo.NewBox(multipleTL, width, height)).GetSVGPathData() for _, pathData := range multiplePathData { - fmt.Fprintf(writer, ``, pathData, style) + fmt.Fprintf(writer, ``, pathData, style, shadowAttr) } } for _, pathData := range s.GetSVGPathData() { - fmt.Fprintf(writer, ``, pathData, style) + fmt.Fprintf(writer, ``, pathData, style, shadowAttr) } } @@ -796,6 +813,14 @@ func Render(diagram *d2target.Diagram) ([]byte, error) { fmt.Fprintf(buf, ``, mdCSS) } + // only define shadow filter if a shape uses it + for _, s := range diagram.Shapes { + if s.Shadow { + defineShadowFilter(buf) + break + } + } + // SVG has no notion of z-index. The z-index is effectively the order it's drawn. // So draw from the least nested to most nested idToShape := make(map[string]d2target.Shape) From c5f047805f124682b6e57bae965fa7277e8b38e9 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 9 Nov 2022 11:45:26 -0800 Subject: [PATCH 2/5] use a group when a shape has multiple paths --- d2renderers/d2svg/d2svg.go | 12 ++++++++++-- e2etests/testdata/stable/all_shapes/sketch.exp.svg | 2 +- .../stable/all_shapes_multiple/sketch.exp.svg | 2 +- e2etests/testdata/stable/chaos1/sketch.exp.svg | 2 +- e2etests/testdata/stable/chaos2/sketch.exp.svg | 2 +- e2etests/testdata/stable/investigate/sketch.exp.svg | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 6a76331b3..7120d318d 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -520,8 +520,16 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { fmt.Fprintf(writer, ``, pathData, style, shadowAttr) } } - for _, pathData := range s.GetSVGPathData() { - fmt.Fprintf(writer, ``, pathData, style, shadowAttr) + + paths := s.GetSVGPathData() + if len(paths) == 1 { + fmt.Fprintf(writer, ``, paths[0], style, shadowAttr) + } else { + fmt.Fprintf(writer, ``, style, shadowAttr) + for _, pathData := range paths { + fmt.Fprintf(writer, ``, pathData) + } + fmt.Fprintf(writer, ``) } } diff --git a/e2etests/testdata/stable/all_shapes/sketch.exp.svg b/e2etests/testdata/stable/all_shapes/sketch.exp.svg index 3c83a55c5..34e7ec310 100644 --- a/e2etests/testdata/stable/all_shapes/sketch.exp.svg +++ b/e2etests/testdata/stable/all_shapes/sketch.exp.svg @@ -12,7 +12,7 @@ width="1539" height="824" viewBox="-100 -100 1539 824">rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud aaadddeeebbbccc +aaadddeeebbbccc 111 diff --git a/e2etests/testdata/stable/chaos2/sketch.exp.svg b/e2etests/testdata/stable/chaos2/sketch.exp.svg index 195c0f5f6..049910b68 100644 --- a/e2etests/testdata/stable/chaos2/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/sketch.exp.svg @@ -788,7 +788,7 @@ width="1317" height="1854" viewBox="-100 -100 1317 1854">aabbllmm

nn

+aabbllmm

nn

oocciikkdd

gg

hhjj

ee

ff diff --git a/e2etests/testdata/stable/investigate/sketch.exp.svg b/e2etests/testdata/stable/investigate/sketch.exp.svg index 36993ddab..5acd68c1f 100644 --- a/e2etests/testdata/stable/investigate/sketch.exp.svg +++ b/e2etests/testdata/stable/investigate/sketch.exp.svg @@ -12,7 +12,7 @@ width="1011" height="4426" viewBox="-100 -100 1011 4426">aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac +aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 1 From 9dfdc0a9eeae420780332a2ff471bab0c9f28557 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 9 Nov 2022 11:14:31 -0800 Subject: [PATCH 3/5] add all_shapes_shadow test --- d2renderers/d2svg/d2svg.go | 8 +- e2etests/stable_test.go | 47 + .../stable/all_shapes_shadow/board.exp.json | 1170 +++++++++++++++++ .../stable/all_shapes_shadow/sketch.exp.svg | 30 + 4 files changed, 1251 insertions(+), 4 deletions(-) create mode 100644 e2etests/testdata/stable/all_shapes_shadow/board.exp.json create mode 100644 e2etests/testdata/stable/all_shapes_shadow/sketch.exp.svg diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 7120d318d..9f979b182 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -458,10 +458,10 @@ func defineShadowFilter(writer io.Writer) { fmt.Fprint(writer, ` - - - - + + + + `) } diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index c77d3bf1b..2367fe7cc 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -95,6 +95,53 @@ oval.multiple: true circle.multiple: true hexagon.multiple: true cloud.multiple: true +`, + }, + { + name: "all_shapes_shadow", + script: ` +rectangle: {shape: "rectangle"} +square: {shape: "square"} +page: {shape: "page"} +parallelogram: {shape: "parallelogram"} +document: {shape: "document"} +cylinder: {shape: "cylinder"} +queue: {shape: "queue"} +package: {shape: "package"} +step: {shape: "step"} +callout: {shape: "callout"} +stored_data: {shape: "stored_data"} +person: {shape: "person"} +diamond: {shape: "diamond"} +oval: {shape: "oval"} +circle: {shape: "circle"} +hexagon: {shape: "hexagon"} +cloud: {shape: "cloud"} + +rectangle -> square -> page +parallelogram -> document -> cylinder +queue -> package -> step +callout -> stored_data -> person +diamond -> oval -> circle +hexagon -> cloud + +rectangle.shadow: true +square.shadow: true +page.shadow: true +parallelogram.shadow: true +document.shadow: true +cylinder.shadow: true +queue.shadow: true +package.shadow: true +step.shadow: true +callout.shadow: true +stored_data.shadow: true +person.shadow: true +diamond.shadow: true +oval.shadow: true +circle.shadow: true +hexagon.shadow: true +cloud.shadow: true `, }, { diff --git a/e2etests/testdata/stable/all_shapes_shadow/board.exp.json b/e2etests/testdata/stable/all_shapes_shadow/board.exp.json new file mode 100644 index 000000000..b751096e7 --- /dev/null +++ b/e2etests/testdata/stable/all_shapes_shadow/board.exp.json @@ -0,0 +1,1170 @@ +{ + "name": "", + "shapes": [ + { + "id": "rectangle", + "type": "rectangle", + "pos": { + "x": 0, + "y": 0 + }, + "width": 171, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "rectangle", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 71, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "square", + "type": "rectangle", + "pos": { + "x": 9, + "y": 226 + }, + "width": 154, + "height": 154, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "square", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 54, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "page", + "type": "page", + "pos": { + "x": 16, + "y": 489 + }, + "width": 139, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "page", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 39, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "parallelogram", + "type": "parallelogram", + "pos": { + "x": 231, + "y": 0 + }, + "width": 204, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F0F3F9", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "parallelogram", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 104, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "document", + "type": "document", + "pos": { + "x": 245, + "y": 240 + }, + "width": 177, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "document", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 77, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "cylinder", + "type": "cylinder", + "pos": { + "x": 251, + "y": 489 + }, + "width": 164, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "cylinder", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 64, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "queue", + "type": "queue", + "pos": { + "x": 495, + "y": 0 + }, + "width": 149, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F0F3F9", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "queue", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 49, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "package", + "type": "package", + "pos": { + "x": 488, + "y": 240 + }, + "width": 163, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "package", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 63, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "step", + "type": "step", + "pos": { + "x": 502, + "y": 489 + }, + "width": 136, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "step", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 36, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "callout", + "type": "callout", + "pos": { + "x": 729, + "y": 0 + }, + "width": 155, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "callout", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 55, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "stored_data", + "type": "stored_data", + "pos": { + "x": 711, + "y": 240 + }, + "width": 191, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#EDF0FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "stored_data", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 91, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "person", + "type": "person", + "pos": { + "x": 730, + "y": 489 + }, + "width": 153, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "person", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 53, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "diamond", + "type": "diamond", + "pos": { + "x": 946, + "y": 0 + }, + "width": 168, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#CFD2DD", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "diamond", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 68, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "oval", + "type": "oval", + "pos": { + "x": 962, + "y": 240 + }, + "width": 136, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "oval", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 36, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "circle", + "type": "oval", + "pos": { + "x": 958, + "y": 480 + }, + "width": 144, + "height": 144, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "circle", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 44, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 1174, + "y": 0 + }, + "width": 165, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F0F3F9", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 65, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "cloud", + "type": "cloud", + "pos": { + "x": 1184, + "y": 240 + }, + "width": 145, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#FFFFFF", + "stroke": "#0D32B2", + "shadow": true, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "cloud", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 45, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + } + ], + "connections": [ + { + "id": "(rectangle -> square)[0]", + "src": "rectangle", + "srcArrow": "none", + "srcLabel": "", + "dst": "square", + "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": 85.5, + "y": 126 + }, + { + "x": 85.5, + "y": 166 + }, + { + "x": 85.5, + "y": 186 + }, + { + "x": 85.5, + "y": 226 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(square -> page)[0]", + "src": "square", + "srcArrow": "none", + "srcLabel": "", + "dst": "page", + "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": 85.5, + "y": 380 + }, + { + "x": 85.5, + "y": 420 + }, + { + "x": 85.4, + "y": 441.8 + }, + { + "x": 85, + "y": 489 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(parallelogram -> document)[0]", + "src": "parallelogram", + "srcArrow": "none", + "srcLabel": "", + "dst": "document", + "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": 333, + "y": 126 + }, + { + "x": 333, + "y": 166 + }, + { + "x": 333, + "y": 188.8 + }, + { + "x": 333, + "y": 240 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(document -> cylinder)[0]", + "src": "document", + "srcArrow": "none", + "srcLabel": "", + "dst": "cylinder", + "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": 333, + "y": 349 + }, + { + "x": 333, + "y": 413.8 + }, + { + "x": 333, + "y": 441.8 + }, + { + "x": 333, + "y": 489 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(queue -> package)[0]", + "src": "queue", + "srcArrow": "none", + "srcLabel": "", + "dst": "package", + "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": 569, + "y": 126 + }, + { + "x": 569.4, + "y": 166 + }, + { + "x": 569.6, + "y": 188.8 + }, + { + "x": 570, + "y": 240 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(package -> step)[0]", + "src": "package", + "srcArrow": "none", + "srcLabel": "", + "dst": "step", + "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": 569, + "y": 366 + }, + { + "x": 569.4, + "y": 417.2 + }, + { + "x": 569.6, + "y": 441.8 + }, + { + "x": 570, + "y": 489 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(callout -> stored_data)[0]", + "src": "callout", + "srcArrow": "none", + "srcLabel": "", + "dst": "stored_data", + "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": 807, + "y": 126 + }, + { + "x": 806.6, + "y": 166 + }, + { + "x": 806.6, + "y": 188.8 + }, + { + "x": 807, + "y": 240 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(stored_data -> person)[0]", + "src": "stored_data", + "srcArrow": "none", + "srcLabel": "", + "dst": "person", + "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": 806, + "y": 366 + }, + { + "x": 806.4, + "y": 417.2 + }, + { + "x": 806.6, + "y": 441.8 + }, + { + "x": 807, + "y": 489 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(diamond -> oval)[0]", + "src": "diamond", + "srcArrow": "none", + "srcLabel": "", + "dst": "oval", + "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": 1030, + "y": 126 + }, + { + "x": 1030, + "y": 166 + }, + { + "x": 1030, + "y": 188.8 + }, + { + "x": 1030, + "y": 240 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(oval -> circle)[0]", + "src": "oval", + "srcArrow": "none", + "srcLabel": "", + "dst": "circle", + "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": 1030, + "y": 366 + }, + { + "x": 1030, + "y": 417.2 + }, + { + "x": 1030, + "y": 440 + }, + { + "x": 1030, + "y": 480 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + }, + { + "id": "(hexagon -> cloud)[0]", + "src": "hexagon", + "srcArrow": "none", + "srcLabel": "", + "dst": "cloud", + "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": 1256, + "y": 126 + }, + { + "x": 1256.4, + "y": 166 + }, + { + "x": 1256.6, + "y": 189.2 + }, + { + "x": 1257, + "y": 242 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + } + ] +} diff --git a/e2etests/testdata/stable/all_shapes_shadow/sketch.exp.svg b/e2etests/testdata/stable/all_shapes_shadow/sketch.exp.svg new file mode 100644 index 000000000..504093354 --- /dev/null +++ b/e2etests/testdata/stable/all_shapes_shadow/sketch.exp.svg @@ -0,0 +1,30 @@ + + + + + + + + + +rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud \ No newline at end of file From 9dd1334363f8288e66d8335beb213d3536b512b4 Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 9 Nov 2022 19:24:27 -0800 Subject: [PATCH 4/5] always wrap shape in g element --- d2renderers/d2svg/class.go | 4 +- d2renderers/d2svg/d2svg.go | 62 ++++++++++--------- d2renderers/d2svg/table.go | 4 +- .../testdata/stable/all_shapes/sketch.exp.svg | 2 +- .../stable/all_shapes_multiple/sketch.exp.svg | 2 +- .../stable/all_shapes_shadow/sketch.exp.svg | 2 +- .../arrowhead_adjustment/sketch.exp.svg | 2 +- .../stable/binary_tree/sketch.exp.svg | 2 +- .../testdata/stable/chaos1/sketch.exp.svg | 2 +- .../testdata/stable/chaos2/sketch.exp.svg | 8 +-- .../stable/child_parent_edges/sketch.exp.svg | 2 +- .../stable/circular_dependency/sketch.exp.svg | 2 +- .../stable/code_snippet/sketch.exp.svg | 4 +- .../stable/connected_container/sketch.exp.svg | 2 +- .../stable/container_edges/sketch.exp.svg | 2 +- e2etests/testdata/stable/dense/sketch.exp.svg | 2 +- .../stable/different_subgraphs/sketch.exp.svg | 2 +- .../stable/giant_markdown_test/sketch.exp.svg | 4 +- e2etests/testdata/stable/hr/sketch.exp.svg | 4 +- .../stable/investigate/sketch.exp.svg | 2 +- .../testdata/stable/large_arch/sketch.exp.svg | 2 +- e2etests/testdata/stable/li1/sketch.exp.svg | 4 +- e2etests/testdata/stable/li2/sketch.exp.svg | 4 +- e2etests/testdata/stable/li3/sketch.exp.svg | 4 +- e2etests/testdata/stable/li4/sketch.exp.svg | 4 +- .../testdata/stable/lone_h1/sketch.exp.svg | 4 +- .../testdata/stable/markdown/sketch.exp.svg | 4 +- .../md_code_block_fenced/sketch.exp.svg | 4 +- .../md_code_block_indented/sketch.exp.svg | 4 +- .../stable/md_code_inline/sketch.exp.svg | 4 +- .../stable/multiline_text/sketch.exp.svg | 2 +- .../stable/multiple_trees/sketch.exp.svg | 2 +- .../testdata/stable/n22_e32/sketch.exp.svg | 2 +- .../stable/one_container_loop/sketch.exp.svg | 2 +- .../one_three_one_container/sketch.exp.svg | 2 +- e2etests/testdata/stable/p/sketch.exp.svg | 4 +- e2etests/testdata/stable/pre/sketch.exp.svg | 4 +- .../sketch.exp.svg | 2 +- .../testdata/stable/us_map/sketch.exp.svg | 2 +- 39 files changed, 89 insertions(+), 87 deletions(-) diff --git a/d2renderers/d2svg/class.go b/d2renderers/d2svg/class.go index 2aaa6ee19..befe5c47e 100644 --- a/d2renderers/d2svg/class.go +++ b/d2renderers/d2svg/class.go @@ -97,8 +97,8 @@ func visibilityToken(visibility string) string { } func drawClass(writer io.Writer, targetShape d2target.Shape) { - fmt.Fprintf(writer, ``, - targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, shapeStyle(targetShape)) + fmt.Fprintf(writer, ``, + targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height) box := geo.NewBox( geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)), diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 9f979b182..d8ef126af 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -444,14 +444,12 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma } } -func renderOval(tl *geo.Point, width, height float64, style, shadowAttr string) string { +func renderOval(tl *geo.Point, width, height float64) string { rx := width / 2 ry := height / 2 cx := tl.X + rx cy := tl.Y + ry - return fmt.Sprintf(``, - cx, cy, rx, ry, style, shadowAttr, - ) + return fmt.Sprintf(``, cx, cy, rx, ry) } func defineShadowFilter(writer io.Writer) { @@ -475,16 +473,25 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { s := shape.NewShape(shapeType, geo.NewBox(tl, width, height)) + var shadowAttr string + if targetShape.Shadow && d2target.IsShape(targetShape.Type) { + switch targetShape.Type { + case d2target.ShapeText, + d2target.ShapeCode, + d2target.ShapeClass, + d2target.ShapeSQLTable: + default: + shadowAttr = `filter="url(#shadow-filter)" ` + } + } + + fmt.Fprintf(writer, ``, style, shadowAttr) + var multipleTL *geo.Point if targetShape.Multiple { multipleTL = tl.AddVector(multipleOffset) } - var shadowAttr string - if targetShape.Shadow { - shadowAttr = `filter="url(#shadow-filter)" ` - } - switch targetShape.Type { case d2target.ShapeClass: drawClass(writer, targetShape) @@ -494,45 +501,40 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { return nil case d2target.ShapeOval: if targetShape.Multiple { - fmt.Fprint(writer, renderOval(multipleTL, width, height, style, shadowAttr)) + fmt.Fprint(writer, renderOval(multipleTL, width, height)) } - fmt.Fprint(writer, renderOval(tl, width, height, style, shadowAttr)) + fmt.Fprint(writer, renderOval(tl, width, height)) case d2target.ShapeImage: - fmt.Fprintf(writer, ``, + fmt.Fprintf(writer, ``, targetShape.Icon.String(), - targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style, shadowAttr) - case d2target.ShapeText: - case d2target.ShapeCode: - // TODO should standardize "" to rectangle + targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height) + + // TODO should standardize "" to rectangle case d2target.ShapeRectangle, "": if targetShape.Multiple { - fmt.Fprintf(writer, ``, - targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style, shadowAttr) + fmt.Fprintf(writer, ``, + targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height) } - fmt.Fprintf(writer, ``, - targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style, shadowAttr) + fmt.Fprintf(writer, ``, + targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height) + case d2target.ShapeText, d2target.ShapeCode: default: if targetShape.Multiple { multiplePathData := shape.NewShape(shapeType, geo.NewBox(multipleTL, width, height)).GetSVGPathData() for _, pathData := range multiplePathData { - fmt.Fprintf(writer, ``, pathData, style, shadowAttr) + fmt.Fprintf(writer, ``, pathData) } } - paths := s.GetSVGPathData() - if len(paths) == 1 { - fmt.Fprintf(writer, ``, paths[0], style, shadowAttr) - } else { - fmt.Fprintf(writer, ``, style, shadowAttr) - for _, pathData := range paths { - fmt.Fprintf(writer, ``, pathData) - } - fmt.Fprintf(writer, ``) + for _, pathData := range s.GetSVGPathData() { + fmt.Fprintf(writer, ``, pathData) } } + fmt.Fprintf(writer, ``) + if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage { iconPosition := label.Position(targetShape.IconPosition) var box *geo.Box diff --git a/d2renderers/d2svg/table.go b/d2renderers/d2svg/table.go index da08c628e..de378793e 100644 --- a/d2renderers/d2svg/table.go +++ b/d2renderers/d2svg/table.go @@ -98,8 +98,8 @@ func constraintAbbr(constraint string) string { } func drawTable(writer io.Writer, targetShape d2target.Shape) { - fmt.Fprintf(writer, ``, - targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, shapeStyle(targetShape)) + fmt.Fprintf(writer, ``, + targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height) box := geo.NewBox( geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)), diff --git a/e2etests/testdata/stable/all_shapes/sketch.exp.svg b/e2etests/testdata/stable/all_shapes/sketch.exp.svg index 34e7ec310..a5c75da47 100644 --- a/e2etests/testdata/stable/all_shapes/sketch.exp.svg +++ b/e2etests/testdata/stable/all_shapes/sketch.exp.svg @@ -12,7 +12,7 @@ width="1539" height="824" viewBox="-100 -100 1539 824">rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud cba cba abcdefghijklmno abcdefghijklmno aaadddeeebbbccc +aaadddeeebbbccc 111 diff --git a/e2etests/testdata/stable/chaos2/sketch.exp.svg b/e2etests/testdata/stable/chaos2/sketch.exp.svg index 049910b68..909270b15 100644 --- a/e2etests/testdata/stable/chaos2/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/sketch.exp.svg @@ -788,10 +788,10 @@ width="1317" height="1854" viewBox="-100 -100 1317 1854">aabbllmm

nn

-
oocciikkdd

gg

-
hhjj

ee

-
ff +aabbllmm

nn

+
oocciikkdd

gg

+
hhjj

ee

+
ff 11 diff --git a/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg b/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg index 9b0a000cf..557b9d8b4 100644 --- a/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg +++ b/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg @@ -12,7 +12,7 @@ width="694" height="626" viewBox="-100 -100 694 626">abcd abcd abc abc // RegisterHash registers a function that returns a new instance of the given +// RegisterHash registers a function that returns a new instance of the given // hash function. This is intended to be called from the init function in // packages that implement hash functions. func RegisterHash(h Hash, f func() hash.Hash) { @@ -20,7 +20,7 @@ width="955" height="818" viewBox="-100 -100 955 818">acfbdhg acfbdhg agdfbhec agdfbhec abcdefghijklmnopq abcdefghijklmnopq finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot

Markdown: Syntax

+

Markdown: Syntax

  • Overview
      @@ -1045,7 +1045,7 @@ 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

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 aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac +aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 1 diff --git a/e2etests/testdata/stable/large_arch/sketch.exp.svg b/e2etests/testdata/stable/large_arch/sketch.exp.svg index 251783510..bd20bb27d 100644 --- a/e2etests/testdata/stable/large_arch/sketch.exp.svg +++ b/e2etests/testdata/stable/large_arch/sketch.exp.svg @@ -12,7 +12,7 @@ width="3244" height="1780" viewBox="-100 -100 3244 1780">abcdefghiqrjmnoszaabbeeffggklptuwxyccddv abcdefghiqrjmnoszaabbeeffggklptuwxyccddv
    +
    • Overview
      • Philosophy
      • @@ -800,7 +800,7 @@ width="579" height="752" viewBox="-100 -100 579 752">
          +
          • Overview ok this is all measured
            • Philosophy
            • @@ -796,7 +796,7 @@ width="445" height="728" viewBox="-100 -100 445 728">
                +
                • Overview
                  • Philosophy
                  • @@ -821,7 +821,7 @@ width="547" height="1164" viewBox="-100 -100 547 1164">

                    List items may consist of multiple paragraphs. Each subsequent +

                    List items may consist of multiple paragraphs. Each subsequent paragraph in a list item must be indented by either 4 spaces or one tab:

                      @@ -819,7 +819,7 @@ sit amet, consectetuer adipiscing elit.

                      Another item in the same list.

                  -
                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
                {
                +
                {
                 	fenced: "block",
                 	of: "json",
                 }
                 
                -
                ab

                a line of text and an

                +

                a line of text and an

                {
                 	indented: "block",
                 	of: "json",
                 }
                 
                -
                ab

                code

                -
                ab

                code

                +
                ab thisgoesmultiple linesthisgoesmultiple linesabcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvw abcdefghijklmnopqrstu abcdefghijklmnopqrstu acdefgbh acdefgbh topabcbottomstartend topabcbottomstartend

                A paragraph is simply one or more consecutive lines of text, separated +

                A paragraph is simply one or more consecutive lines of text, separated by one or more blank lines. (A blank line is any line that looks like a blank line -- a line containing nothing but spaces or tabs is considered blank.) Normal paragraphs should not be indented with spaces or tabs.

                -
                ab

                Here is an example of AppleScript:

                +

                Here is an example of AppleScript:

                tell application "Foo"
                     beep
                 end tell
                 

                A code block continues until it reaches a line that is not indented (or the end of the article).

                -
                ab acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDrectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud cba cba abcdefghijklmno abcdefghijklmno aaadddeeebbbccc +aaadddeeebbbccc 111 diff --git a/e2etests/testdata/stable/chaos2/sketch.exp.svg b/e2etests/testdata/stable/chaos2/sketch.exp.svg index 909270b15..0af7dde11 100644 --- a/e2etests/testdata/stable/chaos2/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/sketch.exp.svg @@ -788,10 +788,10 @@ width="1317" height="1854" viewBox="-100 -100 1317 1854">aabbllmm

                nn

                -
                oocciikkdd

                gg

                -
                hhjj

                ee

                -
                ff +aabbllmm

                nn

                +
                oocciikkdd

                gg

                +
                hhjj

                ee

                +
                ff 11 diff --git a/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg b/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg index 557b9d8b4..5bcec0606 100644 --- a/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg +++ b/e2etests/testdata/stable/child_parent_edges/sketch.exp.svg @@ -12,7 +12,7 @@ width="694" height="626" viewBox="-100 -100 694 626">abcd abcd abc abc acfbdhg acfbdhg agdfbhec agdfbhec abcdefghijklmnopq abcdefghijklmnopq finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac +aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac 1 diff --git a/e2etests/testdata/stable/large_arch/sketch.exp.svg b/e2etests/testdata/stable/large_arch/sketch.exp.svg index bd20bb27d..74ce868a3 100644 --- a/e2etests/testdata/stable/large_arch/sketch.exp.svg +++ b/e2etests/testdata/stable/large_arch/sketch.exp.svg @@ -12,7 +12,7 @@ width="3244" height="1780" viewBox="-100 -100 3244 1780">abcdefghiqrjmnoszaabbeeffggklptuwxyccddv abcdefghiqrjmnoszaabbeeffggklptuwxyccddv

                Markdown: Syntax

                -
                ab

                code

                -
                ab thisgoesmultiple linesthisgoesmultiple linesabcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvw abcdefghijklmnopqrstu abcdefghijklmnopqrstu acdefgbh acdefgbh topabcbottomstartend topabcbottomstartend acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTND