feat: ability to add border-radius to d2 icons
This commit is contained in:
parent
32c14d586c
commit
9603f1ae3b
6 changed files with 67 additions and 14 deletions
|
|
@ -383,7 +383,9 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
|
||||||
|
|
||||||
} else if isReserved {
|
} else if isReserved {
|
||||||
c.compileReserved(&obj.Attributes, f)
|
c.compileReserved(&obj.Attributes, f)
|
||||||
|
if keyword != "icon" {
|
||||||
return
|
return
|
||||||
|
}
|
||||||
} else if f.Name.ScalarString() == "style" && f.Name.IsUnquoted() {
|
} else if f.Name.ScalarString() == "style" && f.Name.IsUnquoted() {
|
||||||
if f.Map() == nil || len(f.Map().Fields) == 0 {
|
if f.Map() == nil || len(f.Map().Fields) == 0 {
|
||||||
c.errorf(f.LastRef().AST(), `"style" expected to be set to a map of key-values, or contain an additional keyword like "style.opacity: 0.4"`)
|
c.errorf(f.LastRef().AST(), `"style" expected to be set to a map of key-values, or contain an additional keyword like "style.opacity: 0.4"`)
|
||||||
|
|
@ -473,8 +475,11 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) {
|
||||||
}
|
}
|
||||||
attrs.Label.Value = scalar.ScalarString()
|
attrs.Label.Value = scalar.ScalarString()
|
||||||
default:
|
default:
|
||||||
|
name := f.LastPrimaryKey().Key.Path[0].UnquotedString.Value[0].String
|
||||||
|
if *name != "icon" {
|
||||||
attrs.Label.Value = scalar.ScalarString()
|
attrs.Label.Value = scalar.ScalarString()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
attrs.Label.MapKey = f.LastPrimaryKey()
|
attrs.Label.MapKey = f.LastPrimaryKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -757,7 +762,15 @@ func (c *compiler) compileStyleField(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||||
}
|
}
|
||||||
compileStyleFieldInit(attrs, f)
|
compileStyleFieldInit(attrs, f)
|
||||||
scalar := f.Primary().Value
|
scalar := f.Primary().Value
|
||||||
err := attrs.Style.Apply(f.Name.ScalarString(), scalar.ScalarString())
|
|
||||||
|
parentKeyword := f.LastPrimaryKey().Key.Path[0].ScalarString()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if parentKeyword == "icon" {
|
||||||
|
err = attrs.IconStyle.Apply(f.Name.ScalarString(), scalar.ScalarString())
|
||||||
|
} else {
|
||||||
|
err = attrs.Style.Apply(f.Name.ScalarString(), scalar.ScalarString())
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.errorf(scalar, err.Error())
|
c.errorf(scalar, err.Error())
|
||||||
return
|
return
|
||||||
|
|
@ -779,7 +792,12 @@ func compileStyleFieldInit(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||||
case "stroke-dash":
|
case "stroke-dash":
|
||||||
attrs.Style.StrokeDash = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
attrs.Style.StrokeDash = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
||||||
case "border-radius":
|
case "border-radius":
|
||||||
|
if attrs.Style.BorderRadius == nil {
|
||||||
attrs.Style.BorderRadius = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
attrs.Style.BorderRadius = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
||||||
|
}
|
||||||
|
if attrs.IconStyle.BorderRadius == nil {
|
||||||
|
attrs.IconStyle.BorderRadius = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
||||||
|
}
|
||||||
case "shadow":
|
case "shadow":
|
||||||
attrs.Style.Shadow = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
attrs.Style.Shadow = &d2graph.Scalar{MapKey: f.LastPrimaryKey()}
|
||||||
case "3d":
|
case "3d":
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,9 @@ func applyStyles(shape *d2target.Shape, obj *d2graph.Object) {
|
||||||
if obj.Style.DoubleBorder != nil {
|
if obj.Style.DoubleBorder != nil {
|
||||||
shape.DoubleBorder, _ = strconv.ParseBool(obj.Style.DoubleBorder.Value)
|
shape.DoubleBorder, _ = strconv.ParseBool(obj.Style.DoubleBorder.Value)
|
||||||
}
|
}
|
||||||
|
if obj.IconStyle.BorderRadius != nil {
|
||||||
|
shape.IconBorderRadius, _ = strconv.Atoi(obj.IconStyle.BorderRadius.Value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toShape(obj *d2graph.Object, g *d2graph.Graph) d2target.Shape {
|
func toShape(obj *d2graph.Object, g *d2graph.Graph) d2target.Shape {
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@ type Attributes struct {
|
||||||
|
|
||||||
Style Style `json:"style"`
|
Style Style `json:"style"`
|
||||||
Icon *url.URL `json:"icon,omitempty"`
|
Icon *url.URL `json:"icon,omitempty"`
|
||||||
|
IconStyle Style `json:"iconStyle"`
|
||||||
Tooltip *Scalar `json:"tooltip,omitempty"`
|
Tooltip *Scalar `json:"tooltip,omitempty"`
|
||||||
Link *Scalar `json:"link,omitempty"`
|
Link *Scalar `json:"link,omitempty"`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1163,6 +1163,7 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
}
|
}
|
||||||
|
|
||||||
case d2target.ShapeImage:
|
case d2target.ShapeImage:
|
||||||
|
fmt.Fprint(writer, clipPathForIconBorderRadius(diagramHash, targetShape))
|
||||||
el := d2themes.NewThemableElement("image", inlineTheme)
|
el := d2themes.NewThemableElement("image", inlineTheme)
|
||||||
el.X = float64(targetShape.Pos.X)
|
el.X = float64(targetShape.Pos.X)
|
||||||
el.Y = float64(targetShape.Pos.Y)
|
el.Y = float64(targetShape.Pos.Y)
|
||||||
|
|
@ -1172,6 +1173,7 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
el.Fill = fill
|
el.Fill = fill
|
||||||
el.Stroke = stroke
|
el.Stroke = stroke
|
||||||
el.Style = style
|
el.Style = style
|
||||||
|
el.ClipPath = fmt.Sprintf("%v-%v-icon", diagramHash, targetShape.ID)
|
||||||
fmt.Fprint(writer, el.Render())
|
fmt.Fprint(writer, el.Render())
|
||||||
|
|
||||||
// TODO should standardize "" to rectangle
|
// TODO should standardize "" to rectangle
|
||||||
|
|
@ -1364,12 +1366,13 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
|
||||||
|
|
||||||
tl := iconPosition.GetPointOnBox(box, label.PADDING, float64(iconSize), float64(iconSize))
|
tl := iconPosition.GetPointOnBox(box, label.PADDING, float64(iconSize), float64(iconSize))
|
||||||
|
|
||||||
fmt.Fprintf(writer, `<image href="%s" x="%f" y="%f" width="%d" height="%d" />`,
|
fmt.Fprintf(writer, `<image href="%s" x="%f" y="%f" width="%d" height="%d" clip-path="inset(0 round %dpx)" />`,
|
||||||
html.EscapeString(targetShape.Icon.String()),
|
html.EscapeString(targetShape.Icon.String()),
|
||||||
tl.X,
|
tl.X,
|
||||||
tl.Y,
|
tl.Y,
|
||||||
iconSize,
|
iconSize,
|
||||||
iconSize,
|
iconSize,
|
||||||
|
targetShape.IconBorderRadius,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,33 @@ func clipPathForBorderRadius(diagramHash string, shape d2target.Shape) string {
|
||||||
return out + `fill="none" /> </clipPath>`
|
return out + `fill="none" /> </clipPath>`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clipPathForIconBorderRadius(diagramHash string, shape d2target.Shape) string {
|
||||||
|
box := geo.NewBox(
|
||||||
|
geo.NewPoint(float64(shape.Pos.X), float64(shape.Pos.Y)),
|
||||||
|
float64(shape.Width),
|
||||||
|
float64(shape.Height),
|
||||||
|
)
|
||||||
|
topX, topY := box.TopLeft.X+box.Width, box.TopLeft.Y
|
||||||
|
|
||||||
|
out := fmt.Sprintf(`<clipPath id="%v-%v-icon">`, diagramHash, shape.ID)
|
||||||
|
out += fmt.Sprintf(`<path d="M %f %f L %f %f S %f %f %f %f `, box.TopLeft.X, box.TopLeft.Y+float64(shape.IconBorderRadius), box.TopLeft.X, box.TopLeft.Y+float64(shape.IconBorderRadius), box.TopLeft.X, box.TopLeft.Y, box.TopLeft.X+float64(shape.IconBorderRadius), box.TopLeft.Y)
|
||||||
|
out += fmt.Sprintf(`L %f %f L %f %f `, box.TopLeft.X+box.Width-float64(shape.IconBorderRadius), box.TopLeft.Y, topX-float64(shape.IconBorderRadius), topY)
|
||||||
|
|
||||||
|
out += fmt.Sprintf(`S %f %f %f %f `, topX, topY, topX, topY+float64(shape.IconBorderRadius))
|
||||||
|
out += fmt.Sprintf(`L %f %f `, topX, topY+box.Height-float64(shape.IconBorderRadius))
|
||||||
|
|
||||||
|
if len(shape.Columns) != 0 {
|
||||||
|
out += fmt.Sprintf(`L %f %f L %f %f`, topX, topY+box.Height, box.TopLeft.X, box.TopLeft.Y+box.Height)
|
||||||
|
} else {
|
||||||
|
out += fmt.Sprintf(`S %f % f %f %f `, topX, topY+box.Height, topX-float64(shape.IconBorderRadius), topY+box.Height)
|
||||||
|
out += fmt.Sprintf(`L %f %f `, box.TopLeft.X+float64(shape.IconBorderRadius), box.TopLeft.Y+box.Height)
|
||||||
|
out += fmt.Sprintf(`S %f %f %f %f`, box.TopLeft.X, box.TopLeft.Y+box.Height, box.TopLeft.X, box.TopLeft.Y+box.Height-float64(shape.IconBorderRadius))
|
||||||
|
out += fmt.Sprintf(`L %f %f`, box.TopLeft.X, box.TopLeft.Y+float64(shape.IconBorderRadius))
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(`Z %f %f" `, box.TopLeft.X, box.TopLeft.Y)
|
||||||
|
return out + `fill="none" /> </clipPath>`
|
||||||
|
}
|
||||||
|
|
||||||
func tableHeader(diagramHash string, shape d2target.Shape, box *geo.Box, text string, textWidth, textHeight, fontSize float64, inlineTheme *d2themes.Theme) string {
|
func tableHeader(diagramHash string, shape d2target.Shape, box *geo.Box, text string, textWidth, textHeight, fontSize float64, inlineTheme *d2themes.Theme) string {
|
||||||
rectEl := d2themes.NewThemableElement("rect", inlineTheme)
|
rectEl := d2themes.NewThemableElement("rect", inlineTheme)
|
||||||
rectEl.X, rectEl.Y = box.TopLeft.X, box.TopLeft.Y
|
rectEl.X, rectEl.Y = box.TopLeft.X, box.TopLeft.Y
|
||||||
|
|
|
||||||
|
|
@ -497,6 +497,7 @@ type Shape struct {
|
||||||
Link string `json:"link"`
|
Link string `json:"link"`
|
||||||
PrettyLink string `json:"prettyLink,omitempty"`
|
PrettyLink string `json:"prettyLink,omitempty"`
|
||||||
Icon *url.URL `json:"icon"`
|
Icon *url.URL `json:"icon"`
|
||||||
|
IconBorderRadius int `json:"iconBorderRadius"`
|
||||||
IconPosition string `json:"iconPosition"`
|
IconPosition string `json:"iconPosition"`
|
||||||
|
|
||||||
// Whether the shape should allow shapes behind it to bleed through
|
// Whether the shape should allow shapes behind it to bleed through
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue