1 package d2themes
2
3 import (
4 "fmt"
5 "math"
6
7 "oss.terrastruct.com/d2/lib/color"
8 )
9
10
11
12
13
14 type ThemableElement struct {
15 tag string
16
17 X float64
18 X1 float64
19 X2 float64
20 Y float64
21 Y1 float64
22 Y2 float64
23 Width float64
24 Height float64
25 R float64
26 Rx float64
27 Ry float64
28 Cx float64
29 Cy float64
30
31 D string
32 Mask string
33 Points string
34 Transform string
35 Href string
36 Xmlns string
37
38 Fill string
39 Stroke string
40 StrokeDashArray string
41 BackgroundColor string
42 Color string
43
44 ClassName string
45 Style string
46 Attributes string
47
48 Content string
49 ClipPath string
50
51 FillPattern string
52 }
53
54 func NewThemableElement(tag string) *ThemableElement {
55 xmlns := ""
56 if tag == "div" {
57 xmlns = "http://www.w3.org/1999/xhtml"
58 }
59
60 return &ThemableElement{
61 tag,
62 math.MaxFloat64,
63 math.MaxFloat64,
64 math.MaxFloat64,
65 math.MaxFloat64,
66 math.MaxFloat64,
67 math.MaxFloat64,
68 math.MaxFloat64,
69 math.MaxFloat64,
70 math.MaxFloat64,
71 math.MaxFloat64,
72 math.MaxFloat64,
73 math.MaxFloat64,
74 math.MaxFloat64,
75 "",
76 "",
77 "",
78 "",
79 "",
80 xmlns,
81 color.Empty,
82 color.Empty,
83 color.Empty,
84 color.Empty,
85 "",
86 "",
87 "",
88 "",
89 "",
90 "",
91 "",
92 }
93 }
94
95 func (el *ThemableElement) Copy() *ThemableElement {
96 tmp := *el
97 return &tmp
98 }
99
100 func (el *ThemableElement) SetTranslate(x, y float64) {
101 el.Transform = fmt.Sprintf("translate(%f %f)", x, y)
102 }
103
104 func (el *ThemableElement) SetMaskUrl(url string) {
105 el.Mask = fmt.Sprintf("url(#%s)", url)
106 }
107
108 func (el *ThemableElement) Render() string {
109 out := "<" + el.tag
110
111
112 if len(el.Href) > 0 {
113 out += fmt.Sprintf(` href="%s"`, el.Href)
114 }
115 if el.X != math.MaxFloat64 {
116 out += fmt.Sprintf(` x="%f"`, el.X)
117 }
118 if el.X1 != math.MaxFloat64 {
119 out += fmt.Sprintf(` x1="%f"`, el.X1)
120 }
121 if el.X2 != math.MaxFloat64 {
122 out += fmt.Sprintf(` x2="%f"`, el.X2)
123 }
124 if el.Y != math.MaxFloat64 {
125 out += fmt.Sprintf(` y="%f"`, el.Y)
126 }
127 if el.Y1 != math.MaxFloat64 {
128 out += fmt.Sprintf(` y1="%f"`, el.Y1)
129 }
130 if el.Y2 != math.MaxFloat64 {
131 out += fmt.Sprintf(` y2="%f"`, el.Y2)
132 }
133 if el.Width != math.MaxFloat64 {
134 out += fmt.Sprintf(` width="%f"`, el.Width)
135 }
136 if el.Height != math.MaxFloat64 {
137 out += fmt.Sprintf(` height="%f"`, el.Height)
138 }
139 if el.R != math.MaxFloat64 {
140 out += fmt.Sprintf(` r="%f"`, el.R)
141 }
142 if el.Rx != math.MaxFloat64 {
143 out += fmt.Sprintf(` rx="%f"`, calculateAxisRadius(el.Rx, el.Width, el.Height))
144 }
145 if el.Ry != math.MaxFloat64 {
146 out += fmt.Sprintf(` ry="%f"`, calculateAxisRadius(el.Ry, el.Width, el.Height))
147 }
148 if el.Cx != math.MaxFloat64 {
149 out += fmt.Sprintf(` cx="%f"`, el.Cx)
150 }
151 if el.Cy != math.MaxFloat64 {
152 out += fmt.Sprintf(` cy="%f"`, el.Cy)
153 }
154 if el.StrokeDashArray != "" {
155 out += fmt.Sprintf(` stroke-dasharray="%s"`, el.StrokeDashArray)
156 }
157
158 if len(el.D) > 0 {
159 out += fmt.Sprintf(` d="%s"`, el.D)
160 }
161 if len(el.Mask) > 0 {
162 out += fmt.Sprintf(` mask="%s"`, el.Mask)
163 }
164 if len(el.Points) > 0 {
165 out += fmt.Sprintf(` points="%s"`, el.Points)
166 }
167 if len(el.Transform) > 0 {
168 out += fmt.Sprintf(` transform="%s"`, el.Transform)
169 }
170 if len(el.Xmlns) > 0 {
171 out += fmt.Sprintf(` xmlns="%s"`, el.Xmlns)
172 }
173
174 class := el.ClassName
175 style := el.Style
176
177
178 if color.IsThemeColor(el.Stroke) {
179 class += fmt.Sprintf(" stroke-%s", el.Stroke)
180 } else if len(el.Stroke) > 0 {
181 out += fmt.Sprintf(` stroke="%s"`, el.Stroke)
182 }
183 if color.IsThemeColor(el.Fill) {
184 class += fmt.Sprintf(" fill-%s", el.Fill)
185 } else if len(el.Fill) > 0 {
186 out += fmt.Sprintf(` fill="%s"`, el.Fill)
187 }
188 if color.IsThemeColor(el.BackgroundColor) {
189 class += fmt.Sprintf(" background-color-%s", el.BackgroundColor)
190 } else if len(el.BackgroundColor) > 0 {
191 out += fmt.Sprintf(` background-color="%s"`, el.BackgroundColor)
192 }
193 if color.IsThemeColor(el.Color) {
194 class += fmt.Sprintf(" color-%s", el.Color)
195 } else if len(el.Color) > 0 {
196 out += fmt.Sprintf(` color="%s"`, el.Color)
197 }
198
199 if len(class) > 0 {
200 out += fmt.Sprintf(` class="%s"`, class)
201 }
202 if len(style) > 0 {
203 out += fmt.Sprintf(` style="%s"`, style)
204 }
205 if len(el.Attributes) > 0 {
206 out += fmt.Sprintf(` %s`, el.Attributes)
207 }
208
209 if len(el.ClipPath) > 0 {
210 out += fmt.Sprintf(` clip-path="url(#%s)"`, el.ClipPath)
211 }
212
213 if len(el.Content) > 0 {
214 return fmt.Sprintf("%s>%s</%s>", out, el.Content, el.tag)
215 }
216
217 out += " />"
218 if el.FillPattern != "" {
219 patternEl := el.Copy()
220 patternEl.Fill = ""
221 patternEl.Stroke = ""
222 patternEl.BackgroundColor = ""
223 patternEl.Color = ""
224 patternEl.ClassName = fmt.Sprintf("%s-overlay", el.FillPattern)
225 patternEl.FillPattern = ""
226 out += patternEl.Render()
227 }
228 return out
229 }
230
231 func calculateAxisRadius(borderRadius, width, height float64) float64 {
232 minimumSideSize := math.Min(width, height)
233 maximumBorderRadiusValue := minimumSideSize / 2.0
234 return math.Min(borderRadius, maximumBorderRadiusValue)
235 }
236
View as plain text