Add double circle shape
This commit is contained in:
parent
5abde05b86
commit
8bb86250fb
6 changed files with 74 additions and 7 deletions
|
|
@ -804,7 +804,7 @@ func (c *compiler) validateKey(obj *d2graph.Object, m *d2ast.Map, mk *d2ast.Key)
|
||||||
if reserved == "" {
|
if reserved == "" {
|
||||||
c.errorf(mk.Range.Start, mk.Range.End, "image shapes cannot have children.")
|
c.errorf(mk.Range.Start, mk.Range.End, "image shapes cannot have children.")
|
||||||
}
|
}
|
||||||
case d2target.ShapeCircle, d2target.ShapeSquare:
|
case d2target.ShapeCircle, d2target.ShapeSquare, d2target.ShapeDoubleCircle:
|
||||||
checkEqual := (reserved == "width" && obj.Attributes.Height != nil) ||
|
checkEqual := (reserved == "width" && obj.Attributes.Height != nil) ||
|
||||||
(reserved == "height" && obj.Attributes.Width != nil)
|
(reserved == "height" && obj.Attributes.Width != nil)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,7 @@ func (obj *Object) GetFill(theme *d2themes.Theme) string {
|
||||||
|
|
||||||
shape := obj.Attributes.Shape.Value
|
shape := obj.Attributes.Shape.Value
|
||||||
|
|
||||||
if shape == "" || strings.EqualFold(shape, d2target.ShapeSquare) || strings.EqualFold(shape, d2target.ShapeCircle) || strings.EqualFold(shape, d2target.ShapeOval) || strings.EqualFold(shape, d2target.ShapeRectangle) {
|
if shape == "" || strings.EqualFold(shape, d2target.ShapeSquare) || strings.EqualFold(shape, d2target.ShapeCircle) || strings.EqualFold(shape, d2target.ShapeDoubleCircle) || strings.EqualFold(shape, d2target.ShapeOval) || strings.EqualFold(shape, d2target.ShapeRectangle) {
|
||||||
if level == 1 {
|
if level == 1 {
|
||||||
if !obj.IsContainer() {
|
if !obj.IsContainer() {
|
||||||
return theme.Colors.B6
|
return theme.Colors.B6
|
||||||
|
|
@ -1138,7 +1138,7 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
|
||||||
paddingX, paddingY := obj.GetPadding()
|
paddingX, paddingY := obj.GetPadding()
|
||||||
|
|
||||||
switch shapeType {
|
switch shapeType {
|
||||||
case d2target.ShapeSquare, d2target.ShapeCircle:
|
case d2target.ShapeSquare, d2target.ShapeCircle, d2target.ShapeDoubleCircle:
|
||||||
if desiredWidth != 0 || desiredHeight != 0 {
|
if desiredWidth != 0 || desiredHeight != 0 {
|
||||||
paddingX = 0.
|
paddingX = 0.
|
||||||
paddingY = 0.
|
paddingY = 0.
|
||||||
|
|
|
||||||
|
|
@ -589,6 +589,17 @@ func renderOval(tl *geo.Point, width, height float64, style string) string {
|
||||||
return fmt.Sprintf(`<ellipse class="shape" cx="%f" cy="%f" rx="%f" ry="%f" style="%s" />`, cx, cy, rx, ry, style)
|
return fmt.Sprintf(`<ellipse class="shape" cx="%f" cy="%f" rx="%f" ry="%f" style="%s" />`, cx, cy, rx, ry, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderDoubleCircle(tl *geo.Point, width, height float64, style string) string {
|
||||||
|
rx := width / 2
|
||||||
|
ry := height / 2
|
||||||
|
cx := tl.X + rx
|
||||||
|
cy := tl.Y + ry
|
||||||
|
return fmt.Sprintf(`<ellipse class="shape" cx="%f" cy="%f" rx="%f" ry="%f" style="%s" />
|
||||||
|
<ellipse class="shape" cx="%f" cy="%f" rx="%f" ry="%f" style="%s" />`,
|
||||||
|
cx, cy, rx-2, ry-2, style,
|
||||||
|
cx, cy, rx-10, ry-10, style)
|
||||||
|
}
|
||||||
|
|
||||||
func defineShadowFilter(writer io.Writer) {
|
func defineShadowFilter(writer io.Writer) {
|
||||||
fmt.Fprint(writer, `<defs>
|
fmt.Fprint(writer, `<defs>
|
||||||
<filter id="shadow-filter" width="200%" height="200%" x="-50%" y="-50%">
|
<filter id="shadow-filter" width="200%" height="200%" x="-50%" y="-50%">
|
||||||
|
|
@ -772,6 +783,19 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprint(writer, renderOval(tl, width, height, style))
|
fmt.Fprint(writer, renderOval(tl, width, height, style))
|
||||||
}
|
}
|
||||||
|
case d2target.ShapeDoubleCircle:
|
||||||
|
if targetShape.Multiple {
|
||||||
|
fmt.Fprint(writer, renderDoubleCircle(multipleTL, width, height, style))
|
||||||
|
}
|
||||||
|
if sketchRunner != nil {
|
||||||
|
out, err := d2sketch.Oval(sketchRunner, targetShape)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer, out)
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(writer, renderDoubleCircle(tl, width, height, style))
|
||||||
|
}
|
||||||
|
|
||||||
case d2target.ShapeImage:
|
case d2target.ShapeImage:
|
||||||
fmt.Fprintf(writer, `<image href="%s" x="%d" y="%d" width="%d" height="%d" style="%s" />`,
|
fmt.Fprintf(writer, `<image href="%s" x="%d" y="%d" width="%d" height="%d" style="%s" />`,
|
||||||
|
|
|
||||||
|
|
@ -427,6 +427,7 @@ const (
|
||||||
ShapeSQLTable = "sql_table"
|
ShapeSQLTable = "sql_table"
|
||||||
ShapeImage = "image"
|
ShapeImage = "image"
|
||||||
ShapeSequenceDiagram = "sequence_diagram"
|
ShapeSequenceDiagram = "sequence_diagram"
|
||||||
|
ShapeDoubleCircle = "double_circle"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Shapes = []string{
|
var Shapes = []string{
|
||||||
|
|
@ -453,6 +454,7 @@ var Shapes = []string{
|
||||||
ShapeSQLTable,
|
ShapeSQLTable,
|
||||||
ShapeImage,
|
ShapeImage,
|
||||||
ShapeSequenceDiagram,
|
ShapeSequenceDiagram,
|
||||||
|
ShapeDoubleCircle,
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsShape(s string) bool {
|
func IsShape(s string) bool {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const (
|
||||||
CIRCLE_TYPE = "Circle"
|
CIRCLE_TYPE = "Circle"
|
||||||
HEXAGON_TYPE = "Hexagon"
|
HEXAGON_TYPE = "Hexagon"
|
||||||
CLOUD_TYPE = "Cloud"
|
CLOUD_TYPE = "Cloud"
|
||||||
|
DOUBLE_CIRCLE_TYPE = "DoubleCircle"
|
||||||
|
|
||||||
TABLE_TYPE = "Table"
|
TABLE_TYPE = "Table"
|
||||||
CLASS_TYPE = "Class"
|
CLASS_TYPE = "Class"
|
||||||
|
|
@ -108,6 +109,8 @@ func NewShape(shapeType string, box *geo.Box) Shape {
|
||||||
return NewCallout(box)
|
return NewCallout(box)
|
||||||
case CIRCLE_TYPE:
|
case CIRCLE_TYPE:
|
||||||
return NewCircle(box)
|
return NewCircle(box)
|
||||||
|
case DOUBLE_CIRCLE_TYPE:
|
||||||
|
return NewDoubleCircle(box)
|
||||||
case CLASS_TYPE:
|
case CLASS_TYPE:
|
||||||
return NewClass(box)
|
return NewClass(box)
|
||||||
case CLOUD_TYPE:
|
case CLOUD_TYPE:
|
||||||
|
|
@ -168,6 +171,7 @@ func NewShape(shapeType string, box *geo.Box) Shape {
|
||||||
// │
|
// │
|
||||||
// │
|
// │
|
||||||
// ▼
|
// ▼
|
||||||
|
//
|
||||||
// ┌────r─────────────────────────┐
|
// ┌────r─────────────────────────┐
|
||||||
// │ │
|
// │ │
|
||||||
// │ │ │
|
// │ │ │
|
||||||
|
|
|
||||||
37
lib/shape/shape_double_circle.go
Normal file
37
lib/shape/shape_double_circle.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package shape
|
||||||
|
|
||||||
|
import (
|
||||||
|
"oss.terrastruct.com/d2/lib/geo"
|
||||||
|
"oss.terrastruct.com/d2/lib/svg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type shapeDoubleCircle struct {
|
||||||
|
*baseShape
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDoubleCircle(box *geo.Box) Shape {
|
||||||
|
return shapeDoubleCircle{
|
||||||
|
baseShape: &baseShape{
|
||||||
|
Type: DOUBLE_CIRCLE_TYPE,
|
||||||
|
Box: box,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doubleCirclePath(box *geo.Box) *svg.SvgPathContext {
|
||||||
|
// halfYFactor := 43.6 / 87.3
|
||||||
|
pc := svg.NewSVGPathContext(box.TopLeft, box.Width, box.Height)
|
||||||
|
pc.StartAt(pc.Absolute(0.25, 0))
|
||||||
|
// pc
|
||||||
|
return pc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s shapeDoubleCircle) Perimeter() []geo.Intersectable {
|
||||||
|
return doubleCirclePath(s.Box).Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s shapeDoubleCircle) GetSVGPathData() []string {
|
||||||
|
return []string{
|
||||||
|
doubleCirclePath(s.Box).PathData(),
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue