add shadow keyword

This commit is contained in:
Gavin Nishizawa 2022-11-09 11:10:51 -08:00
parent 2c4cc34277
commit 3d9c35d244

View file

@ -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 rx := width / 2
ry := height / 2 ry := height / 2
cx := tl.X + rx cx := tl.X + rx
cy := tl.Y + ry cy := tl.Y + ry
return fmt.Sprintf(`<ellipse class="shape" cx="%f" cy="%f" rx="%f" ry="%f" style="%s" />`, return fmt.Sprintf(`<ellipse class="shape" cx="%f" cy="%f" rx="%f" ry="%f" style="%s" %s/>`,
cx, cy, rx, ry, style, cx, cy, rx, ry, style, shadowAttr,
) )
} }
func defineShadowFilter(writer io.Writer) {
fmt.Fprint(writer, `<defs>
<filter id="shadow-filter" width="200%" height="200%" x="-50%" y="-50%">
<feGaussianBlur stdDeviation="1.7 " in="SourceGraphic"></feGaussianBlur>
<feFlood flood-color="#3d4574" flood-opacity="0.4" result="ShadowFeFloodOut" in="SourceGraphic"></feFlood>
<feComposite in="ShadowFeFloodOut" in2="SourceAlpha" operator="in" result="ShadowFeCompositeOut"></feComposite>
<feOffset dx="3" dy="5" result="ShadowFeOffsetOut" in="ShadowFeCompositeOut"></feOffset>
<feBlend in="SourceGraphic" in2="ShadowFeOffsetOut" mode="normal" result="ShadowFeBlendOut"></feBlend>
</filter>
</defs>`)
}
func drawShape(writer io.Writer, targetShape d2target.Shape) error { func drawShape(writer io.Writer, targetShape d2target.Shape) error {
tl := geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)) tl := geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y))
width := float64(targetShape.Width) width := float64(targetShape.Width)
@ -468,6 +480,11 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error {
multipleTL = tl.AddVector(multipleOffset) multipleTL = tl.AddVector(multipleOffset)
} }
var shadowAttr string
if targetShape.Shadow {
shadowAttr = `filter="url(#shadow-filter)" `
}
switch targetShape.Type { switch targetShape.Type {
case d2target.ShapeClass: case d2target.ShapeClass:
drawClass(writer, targetShape) drawClass(writer, targetShape)
@ -477,34 +494,34 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error {
return nil return nil
case d2target.ShapeOval: case d2target.ShapeOval:
if targetShape.Multiple { 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: case d2target.ShapeImage:
fmt.Fprintf(writer, `<image class="shape" href="%s" x="%d" y="%d" width="%d" height="%d" style="%s" />`, fmt.Fprintf(writer, `<image class="shape" href="%s" x="%d" y="%d" width="%d" height="%d" style="%s" %s/>`,
targetShape.Icon.String(), 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.ShapeText:
case d2target.ShapeCode: case d2target.ShapeCode:
// TODO should standardize "" to rectangle // TODO should standardize "" to rectangle
case d2target.ShapeRectangle, "": case d2target.ShapeRectangle, "":
if targetShape.Multiple { if targetShape.Multiple {
fmt.Fprintf(writer, `<rect class="shape" x="%d" y="%d" width="%d" height="%d" style="%s" />`, fmt.Fprintf(writer, `<rect class="shape" x="%d" y="%d" width="%d" height="%d" style="%s" %s/>`,
targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style) targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style, shadowAttr)
} }
fmt.Fprintf(writer, `<rect class="shape" x="%d" y="%d" width="%d" height="%d" style="%s" />`, fmt.Fprintf(writer, `<rect class="shape" x="%d" y="%d" width="%d" height="%d" style="%s" %s/>`,
targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style) targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style, shadowAttr)
default: default:
if targetShape.Multiple { if targetShape.Multiple {
multiplePathData := shape.NewShape(shapeType, geo.NewBox(multipleTL, width, height)).GetSVGPathData() multiplePathData := shape.NewShape(shapeType, geo.NewBox(multipleTL, width, height)).GetSVGPathData()
for _, pathData := range multiplePathData { for _, pathData := range multiplePathData {
fmt.Fprintf(writer, `<path class="shape" d="%s" style="%s" />`, pathData, style) fmt.Fprintf(writer, `<path class="shape" d="%s" style="%s" %s/>`, pathData, style, shadowAttr)
} }
} }
for _, pathData := range s.GetSVGPathData() { for _, pathData := range s.GetSVGPathData() {
fmt.Fprintf(writer, `<path class="shape" d="%s" style="%s" />`, pathData, style) fmt.Fprintf(writer, `<path class="shape" d="%s" style="%s" %s/>`, pathData, style, shadowAttr)
} }
} }
@ -796,6 +813,14 @@ func Render(diagram *d2target.Diagram) ([]byte, error) {
fmt.Fprintf(buf, `<style type="text/css">%s</style>`, mdCSS) fmt.Fprintf(buf, `<style type="text/css">%s</style>`, 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. // 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 // So draw from the least nested to most nested
idToShape := make(map[string]d2target.Shape) idToShape := make(map[string]d2target.Shape)