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 042ecc48e..41447a5bc 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -444,14 +444,24 @@ 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) 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) +} + +func defineShadowFilter(writer io.Writer) { + fmt.Fprint(writer, ` + + + + + + + +`) } func drawShape(writer io.Writer, targetShape d2target.Shape) error { @@ -463,6 +473,20 @@ 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) @@ -477,37 +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)) + fmt.Fprint(writer, renderOval(multipleTL, width, height)) } - fmt.Fprint(writer, renderOval(tl, width, height, style)) + 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) - 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) + 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) + 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) + fmt.Fprintf(writer, ``, pathData) } } + for _, pathData := range s.GetSVGPathData() { - fmt.Fprintf(writer, ``, pathData, style) + fmt.Fprintf(writer, ``, pathData) } } + fmt.Fprintf(writer, ``) + if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage { iconPosition := label.Position(targetShape.IconPosition) var box *geo.Box @@ -796,6 +823,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) 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/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/sketch.exp.svg b/e2etests/testdata/stable/all_shapes/sketch.exp.svg index 3c83a55c5..a13f8af56 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 + + + + + + + +rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud \ No newline at end of file diff --git a/e2etests/testdata/stable/arrowhead_adjustment/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_adjustment/sketch.exp.svg index fec0fb5f6..6d3395d24 100644 --- a/e2etests/testdata/stable/arrowhead_adjustment/sketch.exp.svg +++ b/e2etests/testdata/stable/arrowhead_adjustment/sketch.exp.svg @@ -12,7 +12,7 @@ width="480" height="778" viewBox="-100 -100 480 778">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 195c0f5f6..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 9b0a000cf..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 // 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..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
    +
    • 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 AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTND