diff --git a/d2compiler/compile.go b/d2compiler/compile.go
index 5801712b8..255f8ec64 100644
--- a/d2compiler/compile.go
+++ b/d2compiler/compile.go
@@ -236,6 +236,10 @@ func (c *compiler) compileAttributes(attrs *d2graph.Attributes, mk *d2ast.Key) {
} else if reserved == "height" {
attrs.Height = &d2graph.Scalar{MapKey: mk}
} else if reserved == "double-border" {
+ if attrs.Shape.Value != "" && !strings.EqualFold(attrs.Shape.Value, d2target.ShapeSquare) && !strings.EqualFold(attrs.Shape.Value, d2target.ShapeRectangle) && !strings.EqualFold(attrs.Shape.Value, d2target.ShapeCircle) && !strings.EqualFold(attrs.Shape.Value, d2target.ShapeOval) {
+ c.errorf(mk.Range.Start, mk.Range.End, `key "double-border" can only be applied to squares, rectangles, circles, ovals`)
+ return
+ }
attrs.Style.DoubleBorder = &d2graph.Scalar{MapKey: mk}
}
}
diff --git a/d2renderers/d2sketch/sketch.go b/d2renderers/d2sketch/sketch.go
index 5aea26fcc..0d7659a79 100644
--- a/d2renderers/d2sketch/sketch.go
+++ b/d2renderers/d2sketch/sketch.go
@@ -108,6 +108,47 @@ func Rect(r *Runner, shape d2target.Shape) (string, error) {
return output, nil
}
+func DoubleRect(r *Runner, shape d2target.Shape) (string, error) {
+ jsBigRect := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
+ fill: "%s",
+ stroke: "%s",
+ strokeWidth: %d,
+ %s
+ });`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
+ pathsBigRect, err := computeRoughPaths(r, jsBigRect)
+ if err != nil {
+ return "", err
+ }
+ jsSmallRect := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
+ fill: "%s",
+ stroke: "%s",
+ strokeWidth: %d,
+ %s
+ });`, shape.Width-10, shape.Height-10, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
+ pathsSmallRect, err := computeRoughPaths(r, jsSmallRect)
+ if err != nil {
+ return "", err
+ }
+ output := ""
+ for _, p := range pathsBigRect {
+ output += fmt.Sprintf(
+ ``,
+ shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape),
+ )
+ }
+ for _, p := range pathsSmallRect {
+ output += fmt.Sprintf(
+ ``,
+ shape.Pos.X+5, shape.Pos.Y+5, p, shapeStyle(shape),
+ )
+ }
+ output += fmt.Sprintf(
+ ``,
+ shape.Pos.X, shape.Pos.Y, shape.Width, shape.Height,
+ )
+ return output, nil
+}
+
func Oval(r *Runner, shape d2target.Shape) (string, error) {
js := fmt.Sprintf(`node = rc.ellipse(%d, %d, %d, %d, {
fill: "%s",
@@ -146,22 +187,22 @@ func DoubleOval(r *Runner, shape d2target.Shape) (string, error) {
strokeWidth: %d,
%s
});`, shape.Width/2, shape.Height/2, shape.Width-15, shape.Height-15, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
- paths_big_circle, err := computeRoughPaths(r, jsBigCircle)
+ pathsBigCircle, err := computeRoughPaths(r, jsBigCircle)
if err != nil {
return "", err
}
- paths_small_circle, err := computeRoughPaths(r, jsSmallCircle)
+ pathsSmallCircle, err := computeRoughPaths(r, jsSmallCircle)
if err != nil {
return "", err
}
output := ""
- for _, p := range paths_big_circle {
+ for _, p := range pathsBigCircle {
output += fmt.Sprintf(
``,
shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape),
)
}
- for _, p := range paths_small_circle {
+ for _, p := range pathsSmallCircle {
output += fmt.Sprintf(
``,
shape.Pos.X, shape.Pos.Y, p, shapeStyle(shape),
diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go
index 625b24ccd..efba73bdd 100644
--- a/d2renderers/d2svg/d2svg.go
+++ b/d2renderers/d2svg/d2svg.go
@@ -698,19 +698,40 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if targetShape.ThreeDee {
fmt.Fprint(writer, render3dRect(targetShape))
} else {
- if targetShape.Multiple {
- fmt.Fprintf(writer, ``,
- targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style)
- }
- if sketchRunner != nil {
- out, err := d2sketch.Rect(sketchRunner, targetShape)
- if err != nil {
- return "", err
+ if !targetShape.DoubleBorder {
+ if targetShape.Multiple {
+ fmt.Fprintf(writer, ``,
+ targetShape.Pos.X+10, targetShape.Pos.Y-10, targetShape.Width, targetShape.Height, style)
+ }
+ if sketchRunner != nil {
+ out, err := d2sketch.Rect(sketchRunner, targetShape)
+ if err != nil {
+ return "", err
+ }
+ fmt.Fprintf(writer, out)
+ } else {
+ fmt.Fprintf(writer, ``,
+ targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style)
}
- fmt.Fprintf(writer, out)
} else {
- fmt.Fprintf(writer, ``,
- targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style)
+ 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+15, targetShape.Pos.Y-5, targetShape.Width-10, targetShape.Height-10, style)
+ }
+ if sketchRunner != nil {
+ out, err := d2sketch.DoubleRect(sketchRunner, targetShape)
+ if err != nil {
+ return "", err
+ }
+ fmt.Fprintf(writer, out)
+ } else {
+ fmt.Fprintf(writer, ``,
+ targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style)
+ fmt.Fprintf(writer, ``,
+ targetShape.Pos.X+5, targetShape.Pos.Y+5, targetShape.Width-10, targetShape.Height-10, style)
+ }
}
}
case d2target.ShapeText, d2target.ShapeCode: