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)