d2render: support gradient values
This commit is contained in:
parent
7f2e1f4fce
commit
09cf9ae7d1
10 changed files with 908 additions and 6 deletions
|
|
@ -253,16 +253,16 @@ func (s *Style) Apply(key, value string) error {
|
|||
if s.Stroke == nil {
|
||||
break
|
||||
}
|
||||
if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) {
|
||||
return errors.New(`expected "stroke" to be a valid named color ("orange") or a hex code ("#f0ff3a")`)
|
||||
if !color.ValidColor(value) {
|
||||
return errors.New(`expected "stroke" to be a valid named color ("orange"), a hex code ("#f0ff3a"), or a gradient ("linear-gradient(red, blue)")`)
|
||||
}
|
||||
s.Stroke.Value = value
|
||||
case "fill":
|
||||
if s.Fill == nil {
|
||||
break
|
||||
}
|
||||
if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) {
|
||||
return errors.New(`expected "fill" to be a valid named color ("orange") or a hex code ("#f0ff3a")`)
|
||||
if !color.ValidColor(value) {
|
||||
return errors.New(`expected "fill" to be a valid named color ("orange"), a hex code ("#f0ff3a"), or a gradient ("linear-gradient(red, blue)")`)
|
||||
}
|
||||
s.Fill.Value = value
|
||||
case "fill-pattern":
|
||||
|
|
@ -348,8 +348,8 @@ func (s *Style) Apply(key, value string) error {
|
|||
if s.FontColor == nil {
|
||||
break
|
||||
}
|
||||
if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) {
|
||||
return errors.New(`expected "font-color" to be a valid named color ("orange") or a hex code ("#f0ff3a")`)
|
||||
if !color.ValidColor(value) {
|
||||
return errors.New(`expected "font-color" to be a valid named color ("orange"), a hex code ("#f0ff3a"), or a gradient ("linear-gradient(red, blue)")`)
|
||||
}
|
||||
s.FontColor.Value = value
|
||||
case "animated":
|
||||
|
|
|
|||
|
|
@ -706,6 +706,11 @@ func renderDoubleOval(tl *geo.Point, width, height float64, fill, fillStroke, st
|
|||
return renderOval(tl, width, height, fill, fillStroke, stroke, style) + renderOval(innerTL, width-10, height-10, fill, "", stroke, style)
|
||||
}
|
||||
|
||||
func defineGradients(writer io.Writer, cssGradient string) {
|
||||
gradient, _ := color.ParseGradient(cssGradient)
|
||||
fmt.Fprint(writer, fmt.Sprintf(`<defs>%s</defs>`, color.GradientToSVG(gradient)))
|
||||
}
|
||||
|
||||
func defineShadowFilter(writer io.Writer) {
|
||||
fmt.Fprint(writer, `<defs>
|
||||
<filter id="shadow-filter" width="200%" height="200%" x="-50%" y="-50%">
|
||||
|
|
@ -1824,6 +1829,29 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if color.IsGradient(diagram.Root.Fill) {
|
||||
defineGradients(buf, diagram.Root.Fill)
|
||||
}
|
||||
if color.IsGradient(diagram.Root.Stroke) {
|
||||
defineGradients(buf, diagram.Root.Stroke)
|
||||
}
|
||||
for _, s := range diagram.Shapes {
|
||||
if color.IsGradient(s.Fill) {
|
||||
defineGradients(buf, s.Fill)
|
||||
}
|
||||
if color.IsGradient(s.Stroke) {
|
||||
defineGradients(buf, s.Stroke)
|
||||
}
|
||||
if color.IsGradient(s.Color) {
|
||||
defineGradients(buf, s.Color)
|
||||
}
|
||||
}
|
||||
for _, c := range diagram.Connections {
|
||||
if color.IsGradient(c.Stroke) {
|
||||
defineGradients(buf, c.Stroke)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply hash on IDs for targeting, to be specific for this diagram
|
||||
diagramHash, err := diagram.HashID()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -178,11 +178,17 @@ func (el *ThemableElement) Render() string {
|
|||
if color.IsThemeColor(el.Stroke) {
|
||||
class += fmt.Sprintf(" stroke-%s", el.Stroke)
|
||||
} else if len(el.Stroke) > 0 {
|
||||
if color.IsGradient(el.Stroke) {
|
||||
el.Stroke = fmt.Sprintf("url('#%s')", color.UniqueGradientID(el.Stroke))
|
||||
}
|
||||
out += fmt.Sprintf(` stroke="%s"`, el.Stroke)
|
||||
}
|
||||
if color.IsThemeColor(el.Fill) {
|
||||
class += fmt.Sprintf(" fill-%s", el.Fill)
|
||||
} else if len(el.Fill) > 0 {
|
||||
if color.IsGradient(el.Fill) {
|
||||
el.Fill = fmt.Sprintf("url('#%s')", color.UniqueGradientID(el.Fill))
|
||||
}
|
||||
out += fmt.Sprintf(` fill="%s"`, el.Fill)
|
||||
}
|
||||
if color.IsThemeColor(el.BackgroundColor) {
|
||||
|
|
|
|||
178
e2etests/testdata/txtar/gradient/dagre/board.exp.json
generated
vendored
Normal file
178
e2etests/testdata/txtar/gradient/dagre/board.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
{
|
||||
"name": "",
|
||||
"isFolderOnly": false,
|
||||
"fontFamily": "SourceSansPro",
|
||||
"shapes": [
|
||||
{
|
||||
"id": "gradient",
|
||||
"type": "rectangle",
|
||||
"pos": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"width": 106,
|
||||
"height": 66,
|
||||
"opacity": 1,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 2,
|
||||
"borderRadius": 0,
|
||||
"fill": "linear-gradient(#f69d3c, #3f87a6)",
|
||||
"stroke": "linear-gradient(to top right, red, blue)",
|
||||
"shadow": false,
|
||||
"3d": false,
|
||||
"multiple": false,
|
||||
"double-border": false,
|
||||
"tooltip": "",
|
||||
"link": "",
|
||||
"icon": null,
|
||||
"iconPosition": "",
|
||||
"blend": false,
|
||||
"fields": null,
|
||||
"methods": null,
|
||||
"columns": null,
|
||||
"label": "gradient",
|
||||
"fontSize": 16,
|
||||
"fontFamily": "DEFAULT",
|
||||
"language": "",
|
||||
"color": "radial-gradient(red, yellow, green, cyan, blue)",
|
||||
"italic": false,
|
||||
"bold": true,
|
||||
"underline": false,
|
||||
"labelWidth": 61,
|
||||
"labelHeight": 21,
|
||||
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||
"zIndex": 0,
|
||||
"level": 1
|
||||
},
|
||||
{
|
||||
"id": "colors",
|
||||
"type": "rectangle",
|
||||
"pos": {
|
||||
"x": 9,
|
||||
"y": 166
|
||||
},
|
||||
"width": 89,
|
||||
"height": 66,
|
||||
"opacity": 1,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 2,
|
||||
"borderRadius": 0,
|
||||
"fill": "linear-gradient(45deg, rgba(255,0,0,0.5) 0%, rgba(0,0,255,0.5) 100%)",
|
||||
"stroke": "linear-gradient(to right, red, blue, green)",
|
||||
"shadow": false,
|
||||
"3d": false,
|
||||
"multiple": false,
|
||||
"double-border": false,
|
||||
"tooltip": "",
|
||||
"link": "",
|
||||
"icon": null,
|
||||
"iconPosition": "",
|
||||
"blend": false,
|
||||
"fields": null,
|
||||
"methods": null,
|
||||
"columns": null,
|
||||
"label": "colors",
|
||||
"fontSize": 16,
|
||||
"fontFamily": "DEFAULT",
|
||||
"language": "",
|
||||
"color": "linear-gradient(to bottom right, red 0%, yellow 25%, green 50%, cyan 75%, blue 100%)",
|
||||
"italic": false,
|
||||
"bold": true,
|
||||
"underline": false,
|
||||
"labelWidth": 44,
|
||||
"labelHeight": 21,
|
||||
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||
"zIndex": 0,
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "(gradient -> colors)[0]",
|
||||
"src": "gradient",
|
||||
"srcArrow": "none",
|
||||
"dst": "colors",
|
||||
"dstArrow": "triangle",
|
||||
"opacity": 1,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 2,
|
||||
"stroke": "B1",
|
||||
"borderRadius": 10,
|
||||
"label": "",
|
||||
"fontSize": 16,
|
||||
"fontFamily": "DEFAULT",
|
||||
"language": "",
|
||||
"color": "N2",
|
||||
"italic": true,
|
||||
"bold": false,
|
||||
"underline": false,
|
||||
"labelWidth": 0,
|
||||
"labelHeight": 0,
|
||||
"labelPosition": "",
|
||||
"labelPercentage": 0,
|
||||
"route": [
|
||||
{
|
||||
"x": 53,
|
||||
"y": 66
|
||||
},
|
||||
{
|
||||
"x": 53,
|
||||
"y": 106
|
||||
},
|
||||
{
|
||||
"x": 53,
|
||||
"y": 126
|
||||
},
|
||||
{
|
||||
"x": 53,
|
||||
"y": 166
|
||||
}
|
||||
],
|
||||
"isCurve": true,
|
||||
"animated": false,
|
||||
"tooltip": "",
|
||||
"icon": null,
|
||||
"zIndex": 0
|
||||
}
|
||||
],
|
||||
"root": {
|
||||
"id": "",
|
||||
"type": "",
|
||||
"pos": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"opacity": 0,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 0,
|
||||
"borderRadius": 0,
|
||||
"fill": "radial-gradient(circle, white 0%, #8A2BE2 60%, #4B0082 100%)",
|
||||
"stroke": "",
|
||||
"shadow": false,
|
||||
"3d": false,
|
||||
"multiple": false,
|
||||
"double-border": false,
|
||||
"tooltip": "",
|
||||
"link": "",
|
||||
"icon": null,
|
||||
"iconPosition": "",
|
||||
"blend": false,
|
||||
"fields": null,
|
||||
"methods": null,
|
||||
"columns": null,
|
||||
"label": "",
|
||||
"fontSize": 0,
|
||||
"fontFamily": "",
|
||||
"language": "",
|
||||
"color": "",
|
||||
"italic": false,
|
||||
"bold": false,
|
||||
"underline": false,
|
||||
"labelWidth": 0,
|
||||
"labelHeight": 0,
|
||||
"zIndex": 0,
|
||||
"level": 0
|
||||
}
|
||||
}
|
||||
125
e2etests/testdata/txtar/gradient/dagre/sketch.exp.svg
vendored
Normal file
125
e2etests/testdata/txtar/gradient/dagre/sketch.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.6-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 108 234"><svg id="d2-svg" class="d2-387748570" width="108" height="234" viewBox="-1 -1 108 234"><rect x="-1.000000" y="-1.000000" width="108.000000" height="234.000000" rx="0.000000" fill="url('#grad-748b4596c77533b881df8829b0adfb302f4dd5d0')" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-387748570 .text-bold {
|
||||
font-family: "d2-387748570-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-387748570-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-387748570 .fill-N1{fill:#0A0F25;}
|
||||
.d2-387748570 .fill-N2{fill:#676C7E;}
|
||||
.d2-387748570 .fill-N3{fill:#9499AB;}
|
||||
.d2-387748570 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-387748570 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-387748570 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-387748570 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-387748570 .fill-B1{fill:#0D32B2;}
|
||||
.d2-387748570 .fill-B2{fill:#0D32B2;}
|
||||
.d2-387748570 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-387748570 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-387748570 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-387748570 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-387748570 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-387748570 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-387748570 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-387748570 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-387748570 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-387748570 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-387748570 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-387748570 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-387748570 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-387748570 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-387748570 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-387748570 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-387748570 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-387748570 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-387748570 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-387748570 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-387748570 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-387748570 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-387748570 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-387748570 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-387748570 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-387748570 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-387748570 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-387748570 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-387748570 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-387748570 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-387748570 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-387748570 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-387748570 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-387748570 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-387748570 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-387748570 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-387748570 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-387748570 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-387748570 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-387748570 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-387748570 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-387748570 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-387748570 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-387748570 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-387748570 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-387748570 .color-N1{color:#0A0F25;}
|
||||
.d2-387748570 .color-N2{color:#676C7E;}
|
||||
.d2-387748570 .color-N3{color:#9499AB;}
|
||||
.d2-387748570 .color-N4{color:#CFD2DD;}
|
||||
.d2-387748570 .color-N5{color:#DEE1EB;}
|
||||
.d2-387748570 .color-N6{color:#EEF1F8;}
|
||||
.d2-387748570 .color-N7{color:#FFFFFF;}
|
||||
.d2-387748570 .color-B1{color:#0D32B2;}
|
||||
.d2-387748570 .color-B2{color:#0D32B2;}
|
||||
.d2-387748570 .color-B3{color:#E3E9FD;}
|
||||
.d2-387748570 .color-B4{color:#E3E9FD;}
|
||||
.d2-387748570 .color-B5{color:#EDF0FD;}
|
||||
.d2-387748570 .color-B6{color:#F7F8FE;}
|
||||
.d2-387748570 .color-AA2{color:#4A6FF3;}
|
||||
.d2-387748570 .color-AA4{color:#EDF0FD;}
|
||||
.d2-387748570 .color-AA5{color:#F7F8FE;}
|
||||
.d2-387748570 .color-AB4{color:#EDF0FD;}
|
||||
.d2-387748570 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><defs><radialGradient id="grad-748b4596c77533b881df8829b0adfb302f4dd5d0">
|
||||
<stop offset="0%" stop-color="white" />
|
||||
<stop offset="60%" stop-color="#8A2BE2" />
|
||||
<stop offset="100%" stop-color="#4B0082" />
|
||||
</radialGradient></defs><defs><linearGradient id="grad-984dfec132f72578000afe61cf8daaed70c7c3de" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0.00%" stop-color="#f69d3c" />
|
||||
<stop offset="100.00%" stop-color="#3f87a6" />
|
||||
</linearGradient></defs><defs><linearGradient id="grad-38ebdc3aba5158fdec998f13cadd2b81d5d3e467" x1="0%" y1="100%" x2="100%" y2="0%">
|
||||
<stop offset="0.00%" stop-color="red" />
|
||||
<stop offset="100.00%" stop-color="blue" />
|
||||
</linearGradient></defs><defs><radialGradient id="grad-df376e8348556a67f106fb4c1ec75fc6e38aabea">
|
||||
<stop offset="0.00%" stop-color="red" />
|
||||
<stop offset="25.00%" stop-color="yellow" />
|
||||
<stop offset="50.00%" stop-color="green" />
|
||||
<stop offset="75.00%" stop-color="cyan" />
|
||||
<stop offset="100.00%" stop-color="blue" />
|
||||
</radialGradient></defs><defs><linearGradient id="grad-867086f31fcac752507fbbbe0405e35050a4704e" x1="50.00%" y1="50.00%" x2="85.36%" y2="85.36%">
|
||||
<stop offset="0%" stop-color="rgba(255,0,0,0.5)" />
|
||||
<stop offset="100%" stop-color="rgba(0,0,255,0.5)" />
|
||||
</linearGradient></defs><defs><linearGradient id="grad-6a6578853b2dd58addb4313cedbcddecb53a2df1" x1="0%" y1="50%" x2="100%" y2="50%">
|
||||
<stop offset="0.00%" stop-color="red" />
|
||||
<stop offset="50.00%" stop-color="blue" />
|
||||
<stop offset="100.00%" stop-color="green" />
|
||||
</linearGradient></defs><defs><linearGradient id="grad-ac2d0b347164c939a2dee5c122da0c2ada91319c" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="red" />
|
||||
<stop offset="25%" stop-color="yellow" />
|
||||
<stop offset="50%" stop-color="green" />
|
||||
<stop offset="75%" stop-color="cyan" />
|
||||
<stop offset="100%" stop-color="blue" />
|
||||
</linearGradient></defs><g id="gradient"><g class="shape" ><rect x="0.000000" y="0.000000" width="106.000000" height="66.000000" stroke="url('#grad-38ebdc3aba5158fdec998f13cadd2b81d5d3e467')" fill="url('#grad-984dfec132f72578000afe61cf8daaed70c7c3de')" style="stroke-width:2;" /></g><text x="53.000000" y="38.500000" fill="url('#grad-df376e8348556a67f106fb4c1ec75fc6e38aabea')" class="text-bold" style="text-anchor:middle;font-size:16px">gradient</text></g><g id="colors"><g class="shape" ><rect x="9.000000" y="166.000000" width="89.000000" height="66.000000" stroke="url('#grad-6a6578853b2dd58addb4313cedbcddecb53a2df1')" fill="url('#grad-867086f31fcac752507fbbbe0405e35050a4704e')" style="stroke-width:2;" /></g><text x="53.500000" y="204.500000" fill="url('#grad-ac2d0b347164c939a2dee5c122da0c2ada91319c')" class="text-bold" style="text-anchor:middle;font-size:16px">colors</text></g><g id="(gradient -> colors)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 53.000000 68.000000 C 53.000000 106.000000 53.000000 126.000000 53.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-387748570)" /></g><mask id="d2-387748570" maskUnits="userSpaceOnUse" x="-1" y="-1" width="108" height="234">
|
||||
<rect x="-1" y="-1" width="108" height="234" fill="white"></rect>
|
||||
<rect x="22.500000" y="22.500000" width="61" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="31.500000" y="188.500000" width="44" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
169
e2etests/testdata/txtar/gradient/elk/board.exp.json
generated
vendored
Normal file
169
e2etests/testdata/txtar/gradient/elk/board.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
{
|
||||
"name": "",
|
||||
"isFolderOnly": false,
|
||||
"fontFamily": "SourceSansPro",
|
||||
"shapes": [
|
||||
{
|
||||
"id": "gradient",
|
||||
"type": "rectangle",
|
||||
"pos": {
|
||||
"x": 12,
|
||||
"y": 12
|
||||
},
|
||||
"width": 106,
|
||||
"height": 66,
|
||||
"opacity": 1,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 2,
|
||||
"borderRadius": 0,
|
||||
"fill": "linear-gradient(#f69d3c, #3f87a6)",
|
||||
"stroke": "linear-gradient(to top right, red, blue)",
|
||||
"shadow": false,
|
||||
"3d": false,
|
||||
"multiple": false,
|
||||
"double-border": false,
|
||||
"tooltip": "",
|
||||
"link": "",
|
||||
"icon": null,
|
||||
"iconPosition": "",
|
||||
"blend": false,
|
||||
"fields": null,
|
||||
"methods": null,
|
||||
"columns": null,
|
||||
"label": "gradient",
|
||||
"fontSize": 16,
|
||||
"fontFamily": "DEFAULT",
|
||||
"language": "",
|
||||
"color": "radial-gradient(red, yellow, green, cyan, blue)",
|
||||
"italic": false,
|
||||
"bold": true,
|
||||
"underline": false,
|
||||
"labelWidth": 61,
|
||||
"labelHeight": 21,
|
||||
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||
"zIndex": 0,
|
||||
"level": 1
|
||||
},
|
||||
{
|
||||
"id": "colors",
|
||||
"type": "rectangle",
|
||||
"pos": {
|
||||
"x": 20,
|
||||
"y": 148
|
||||
},
|
||||
"width": 89,
|
||||
"height": 66,
|
||||
"opacity": 1,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 2,
|
||||
"borderRadius": 0,
|
||||
"fill": "linear-gradient(45deg, rgba(255,0,0,0.5) 0%, rgba(0,0,255,0.5) 100%)",
|
||||
"stroke": "linear-gradient(to right, red, blue, green)",
|
||||
"shadow": false,
|
||||
"3d": false,
|
||||
"multiple": false,
|
||||
"double-border": false,
|
||||
"tooltip": "",
|
||||
"link": "",
|
||||
"icon": null,
|
||||
"iconPosition": "",
|
||||
"blend": false,
|
||||
"fields": null,
|
||||
"methods": null,
|
||||
"columns": null,
|
||||
"label": "colors",
|
||||
"fontSize": 16,
|
||||
"fontFamily": "DEFAULT",
|
||||
"language": "",
|
||||
"color": "linear-gradient(to bottom right, red 0%, yellow 25%, green 50%, cyan 75%, blue 100%)",
|
||||
"italic": false,
|
||||
"bold": true,
|
||||
"underline": false,
|
||||
"labelWidth": 44,
|
||||
"labelHeight": 21,
|
||||
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||
"zIndex": 0,
|
||||
"level": 1
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "(gradient -> colors)[0]",
|
||||
"src": "gradient",
|
||||
"srcArrow": "none",
|
||||
"dst": "colors",
|
||||
"dstArrow": "triangle",
|
||||
"opacity": 1,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 2,
|
||||
"stroke": "B1",
|
||||
"borderRadius": 10,
|
||||
"label": "",
|
||||
"fontSize": 16,
|
||||
"fontFamily": "DEFAULT",
|
||||
"language": "",
|
||||
"color": "N2",
|
||||
"italic": true,
|
||||
"bold": false,
|
||||
"underline": false,
|
||||
"labelWidth": 0,
|
||||
"labelHeight": 0,
|
||||
"labelPosition": "",
|
||||
"labelPercentage": 0,
|
||||
"route": [
|
||||
{
|
||||
"x": 65,
|
||||
"y": 78
|
||||
},
|
||||
{
|
||||
"x": 65,
|
||||
"y": 148
|
||||
}
|
||||
],
|
||||
"animated": false,
|
||||
"tooltip": "",
|
||||
"icon": null,
|
||||
"zIndex": 0
|
||||
}
|
||||
],
|
||||
"root": {
|
||||
"id": "",
|
||||
"type": "",
|
||||
"pos": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"opacity": 0,
|
||||
"strokeDash": 0,
|
||||
"strokeWidth": 0,
|
||||
"borderRadius": 0,
|
||||
"fill": "radial-gradient(circle, white 0%, #8A2BE2 60%, #4B0082 100%)",
|
||||
"stroke": "",
|
||||
"shadow": false,
|
||||
"3d": false,
|
||||
"multiple": false,
|
||||
"double-border": false,
|
||||
"tooltip": "",
|
||||
"link": "",
|
||||
"icon": null,
|
||||
"iconPosition": "",
|
||||
"blend": false,
|
||||
"fields": null,
|
||||
"methods": null,
|
||||
"columns": null,
|
||||
"label": "",
|
||||
"fontSize": 0,
|
||||
"fontFamily": "",
|
||||
"language": "",
|
||||
"color": "",
|
||||
"italic": false,
|
||||
"bold": false,
|
||||
"underline": false,
|
||||
"labelWidth": 0,
|
||||
"labelHeight": 0,
|
||||
"zIndex": 0,
|
||||
"level": 0
|
||||
}
|
||||
}
|
||||
125
e2etests/testdata/txtar/gradient/elk/sketch.exp.svg
vendored
Normal file
125
e2etests/testdata/txtar/gradient/elk/sketch.exp.svg
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.6-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 108 204"><svg id="d2-svg" class="d2-3100767741" width="108" height="204" viewBox="11 11 108 204"><rect x="11.000000" y="11.000000" width="108.000000" height="204.000000" rx="0.000000" fill="url('#grad-748b4596c77533b881df8829b0adfb302f4dd5d0')" stroke-width="0" /><style type="text/css"><![CDATA[
|
||||
.d2-3100767741 .text-bold {
|
||||
font-family: "d2-3100767741-font-bold";
|
||||
}
|
||||
@font-face {
|
||||
font-family: d2-3100767741-font-bold;
|
||||
src: url("data:application/font-woff;base64,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");
|
||||
}]]></style><style type="text/css"><![CDATA[.shape {
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.connection {
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.blend {
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.d2-3100767741 .fill-N1{fill:#0A0F25;}
|
||||
.d2-3100767741 .fill-N2{fill:#676C7E;}
|
||||
.d2-3100767741 .fill-N3{fill:#9499AB;}
|
||||
.d2-3100767741 .fill-N4{fill:#CFD2DD;}
|
||||
.d2-3100767741 .fill-N5{fill:#DEE1EB;}
|
||||
.d2-3100767741 .fill-N6{fill:#EEF1F8;}
|
||||
.d2-3100767741 .fill-N7{fill:#FFFFFF;}
|
||||
.d2-3100767741 .fill-B1{fill:#0D32B2;}
|
||||
.d2-3100767741 .fill-B2{fill:#0D32B2;}
|
||||
.d2-3100767741 .fill-B3{fill:#E3E9FD;}
|
||||
.d2-3100767741 .fill-B4{fill:#E3E9FD;}
|
||||
.d2-3100767741 .fill-B5{fill:#EDF0FD;}
|
||||
.d2-3100767741 .fill-B6{fill:#F7F8FE;}
|
||||
.d2-3100767741 .fill-AA2{fill:#4A6FF3;}
|
||||
.d2-3100767741 .fill-AA4{fill:#EDF0FD;}
|
||||
.d2-3100767741 .fill-AA5{fill:#F7F8FE;}
|
||||
.d2-3100767741 .fill-AB4{fill:#EDF0FD;}
|
||||
.d2-3100767741 .fill-AB5{fill:#F7F8FE;}
|
||||
.d2-3100767741 .stroke-N1{stroke:#0A0F25;}
|
||||
.d2-3100767741 .stroke-N2{stroke:#676C7E;}
|
||||
.d2-3100767741 .stroke-N3{stroke:#9499AB;}
|
||||
.d2-3100767741 .stroke-N4{stroke:#CFD2DD;}
|
||||
.d2-3100767741 .stroke-N5{stroke:#DEE1EB;}
|
||||
.d2-3100767741 .stroke-N6{stroke:#EEF1F8;}
|
||||
.d2-3100767741 .stroke-N7{stroke:#FFFFFF;}
|
||||
.d2-3100767741 .stroke-B1{stroke:#0D32B2;}
|
||||
.d2-3100767741 .stroke-B2{stroke:#0D32B2;}
|
||||
.d2-3100767741 .stroke-B3{stroke:#E3E9FD;}
|
||||
.d2-3100767741 .stroke-B4{stroke:#E3E9FD;}
|
||||
.d2-3100767741 .stroke-B5{stroke:#EDF0FD;}
|
||||
.d2-3100767741 .stroke-B6{stroke:#F7F8FE;}
|
||||
.d2-3100767741 .stroke-AA2{stroke:#4A6FF3;}
|
||||
.d2-3100767741 .stroke-AA4{stroke:#EDF0FD;}
|
||||
.d2-3100767741 .stroke-AA5{stroke:#F7F8FE;}
|
||||
.d2-3100767741 .stroke-AB4{stroke:#EDF0FD;}
|
||||
.d2-3100767741 .stroke-AB5{stroke:#F7F8FE;}
|
||||
.d2-3100767741 .background-color-N1{background-color:#0A0F25;}
|
||||
.d2-3100767741 .background-color-N2{background-color:#676C7E;}
|
||||
.d2-3100767741 .background-color-N3{background-color:#9499AB;}
|
||||
.d2-3100767741 .background-color-N4{background-color:#CFD2DD;}
|
||||
.d2-3100767741 .background-color-N5{background-color:#DEE1EB;}
|
||||
.d2-3100767741 .background-color-N6{background-color:#EEF1F8;}
|
||||
.d2-3100767741 .background-color-N7{background-color:#FFFFFF;}
|
||||
.d2-3100767741 .background-color-B1{background-color:#0D32B2;}
|
||||
.d2-3100767741 .background-color-B2{background-color:#0D32B2;}
|
||||
.d2-3100767741 .background-color-B3{background-color:#E3E9FD;}
|
||||
.d2-3100767741 .background-color-B4{background-color:#E3E9FD;}
|
||||
.d2-3100767741 .background-color-B5{background-color:#EDF0FD;}
|
||||
.d2-3100767741 .background-color-B6{background-color:#F7F8FE;}
|
||||
.d2-3100767741 .background-color-AA2{background-color:#4A6FF3;}
|
||||
.d2-3100767741 .background-color-AA4{background-color:#EDF0FD;}
|
||||
.d2-3100767741 .background-color-AA5{background-color:#F7F8FE;}
|
||||
.d2-3100767741 .background-color-AB4{background-color:#EDF0FD;}
|
||||
.d2-3100767741 .background-color-AB5{background-color:#F7F8FE;}
|
||||
.d2-3100767741 .color-N1{color:#0A0F25;}
|
||||
.d2-3100767741 .color-N2{color:#676C7E;}
|
||||
.d2-3100767741 .color-N3{color:#9499AB;}
|
||||
.d2-3100767741 .color-N4{color:#CFD2DD;}
|
||||
.d2-3100767741 .color-N5{color:#DEE1EB;}
|
||||
.d2-3100767741 .color-N6{color:#EEF1F8;}
|
||||
.d2-3100767741 .color-N7{color:#FFFFFF;}
|
||||
.d2-3100767741 .color-B1{color:#0D32B2;}
|
||||
.d2-3100767741 .color-B2{color:#0D32B2;}
|
||||
.d2-3100767741 .color-B3{color:#E3E9FD;}
|
||||
.d2-3100767741 .color-B4{color:#E3E9FD;}
|
||||
.d2-3100767741 .color-B5{color:#EDF0FD;}
|
||||
.d2-3100767741 .color-B6{color:#F7F8FE;}
|
||||
.d2-3100767741 .color-AA2{color:#4A6FF3;}
|
||||
.d2-3100767741 .color-AA4{color:#EDF0FD;}
|
||||
.d2-3100767741 .color-AA5{color:#F7F8FE;}
|
||||
.d2-3100767741 .color-AB4{color:#EDF0FD;}
|
||||
.d2-3100767741 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><defs><radialGradient id="grad-748b4596c77533b881df8829b0adfb302f4dd5d0">
|
||||
<stop offset="0%" stop-color="white" />
|
||||
<stop offset="60%" stop-color="#8A2BE2" />
|
||||
<stop offset="100%" stop-color="#4B0082" />
|
||||
</radialGradient></defs><defs><linearGradient id="grad-984dfec132f72578000afe61cf8daaed70c7c3de" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0.00%" stop-color="#f69d3c" />
|
||||
<stop offset="100.00%" stop-color="#3f87a6" />
|
||||
</linearGradient></defs><defs><linearGradient id="grad-38ebdc3aba5158fdec998f13cadd2b81d5d3e467" x1="0%" y1="100%" x2="100%" y2="0%">
|
||||
<stop offset="0.00%" stop-color="red" />
|
||||
<stop offset="100.00%" stop-color="blue" />
|
||||
</linearGradient></defs><defs><radialGradient id="grad-df376e8348556a67f106fb4c1ec75fc6e38aabea">
|
||||
<stop offset="0.00%" stop-color="red" />
|
||||
<stop offset="25.00%" stop-color="yellow" />
|
||||
<stop offset="50.00%" stop-color="green" />
|
||||
<stop offset="75.00%" stop-color="cyan" />
|
||||
<stop offset="100.00%" stop-color="blue" />
|
||||
</radialGradient></defs><defs><linearGradient id="grad-867086f31fcac752507fbbbe0405e35050a4704e" x1="50.00%" y1="50.00%" x2="85.36%" y2="85.36%">
|
||||
<stop offset="0%" stop-color="rgba(255,0,0,0.5)" />
|
||||
<stop offset="100%" stop-color="rgba(0,0,255,0.5)" />
|
||||
</linearGradient></defs><defs><linearGradient id="grad-6a6578853b2dd58addb4313cedbcddecb53a2df1" x1="0%" y1="50%" x2="100%" y2="50%">
|
||||
<stop offset="0.00%" stop-color="red" />
|
||||
<stop offset="50.00%" stop-color="blue" />
|
||||
<stop offset="100.00%" stop-color="green" />
|
||||
</linearGradient></defs><defs><linearGradient id="grad-ac2d0b347164c939a2dee5c122da0c2ada91319c" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="red" />
|
||||
<stop offset="25%" stop-color="yellow" />
|
||||
<stop offset="50%" stop-color="green" />
|
||||
<stop offset="75%" stop-color="cyan" />
|
||||
<stop offset="100%" stop-color="blue" />
|
||||
</linearGradient></defs><g id="gradient"><g class="shape" ><rect x="12.000000" y="12.000000" width="106.000000" height="66.000000" stroke="url('#grad-38ebdc3aba5158fdec998f13cadd2b81d5d3e467')" fill="url('#grad-984dfec132f72578000afe61cf8daaed70c7c3de')" style="stroke-width:2;" /></g><text x="65.000000" y="50.500000" fill="url('#grad-df376e8348556a67f106fb4c1ec75fc6e38aabea')" class="text-bold" style="text-anchor:middle;font-size:16px">gradient</text></g><g id="colors"><g class="shape" ><rect x="20.000000" y="148.000000" width="89.000000" height="66.000000" stroke="url('#grad-6a6578853b2dd58addb4313cedbcddecb53a2df1')" fill="url('#grad-867086f31fcac752507fbbbe0405e35050a4704e')" style="stroke-width:2;" /></g><text x="64.500000" y="186.500000" fill="url('#grad-ac2d0b347164c939a2dee5c122da0c2ada91319c')" class="text-bold" style="text-anchor:middle;font-size:16px">colors</text></g><g id="(gradient -> colors)[0]"><marker id="mk-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 65.000000 80.000000 L 65.000000 144.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3100767741)" /></g><mask id="d2-3100767741" maskUnits="userSpaceOnUse" x="11" y="11" width="108" height="204">
|
||||
<rect x="11" y="11" width="108" height="204" fill="white"></rect>
|
||||
<rect x="34.500000" y="34.500000" width="61" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
<rect x="42.500000" y="170.500000" width="44" height="21" fill="rgba(0,0,0,0.75)"></rect>
|
||||
</mask></svg></svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
|
@ -455,3 +455,17 @@ bob -> alice: The ability to play bridge or\ngolf as if they were games.
|
|||
◎: |md
|
||||
◎ foo bar
|
||||
|
|
||||
|
||||
-- gradient --
|
||||
style.fill: "radial-gradient(circle, white 0%, #8A2BE2 60%, #4B0082 100%)"
|
||||
gradient: {
|
||||
style.fill: "linear-gradient(#f69d3c, #3f87a6)"
|
||||
style.stroke: "linear-gradient(to top right, red, blue)"
|
||||
style.font-color: "radial-gradient(red, yellow, green, cyan, blue)"
|
||||
}
|
||||
colors: {
|
||||
style.fill: "linear-gradient(45deg, rgba(255,0,0,0.5) 0%, rgba(0,0,255,0.5) 100%)"
|
||||
style.stroke: "linear-gradient(to right, red, blue, green)"
|
||||
style.font-color: "linear-gradient(to bottom right, red 0%, yellow 25%, green 50%, cyan 75%, blue 100%)"
|
||||
}
|
||||
gradient -> colors
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/lucasb-eyer/go-colorful"
|
||||
"github.com/mazznoer/csscolorparser"
|
||||
"oss.terrastruct.com/util-go/go2"
|
||||
)
|
||||
|
||||
var themeColorRegex = regexp.MustCompile(`^(N[1-7]|B[1-6]|AA[245]|AB[45])$`)
|
||||
|
|
@ -503,3 +504,11 @@ var NamedColors = []string{
|
|||
}
|
||||
|
||||
var ColorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`)
|
||||
|
||||
func ValidColor(color string) bool {
|
||||
if !go2.Contains(NamedColors, strings.ToLower(color)) && !ColorHexRegex.MatchString(color) && !IsGradient(color) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
248
lib/color/gradient.go
Normal file
248
lib/color/gradient.go
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Gradient struct {
|
||||
Type string
|
||||
Direction string
|
||||
ColorStops []ColorStop
|
||||
ID string
|
||||
}
|
||||
|
||||
type ColorStop struct {
|
||||
Color string
|
||||
Position string
|
||||
}
|
||||
|
||||
func ParseGradient(cssGradient string) (Gradient, error) {
|
||||
cssGradient = strings.TrimSpace(cssGradient)
|
||||
|
||||
re := regexp.MustCompile(`^(linear-gradient|radial-gradient)\((.*)\)$`)
|
||||
matches := re.FindStringSubmatch(cssGradient)
|
||||
if matches == nil {
|
||||
return Gradient{}, errors.New("invalid gradient syntax")
|
||||
}
|
||||
|
||||
gradientType := matches[1]
|
||||
params := matches[2]
|
||||
|
||||
gradient := Gradient{
|
||||
Type: strings.TrimSuffix(gradientType, "-gradient"),
|
||||
}
|
||||
|
||||
paramList := splitParams(params)
|
||||
|
||||
if len(paramList) == 0 {
|
||||
return Gradient{}, errors.New("no parameters in gradient")
|
||||
}
|
||||
|
||||
firstParam := strings.TrimSpace(paramList[0])
|
||||
|
||||
if gradient.Type == "linear" && (strings.HasSuffix(firstParam, "deg") || strings.HasPrefix(firstParam, "to ")) {
|
||||
gradient.Direction = firstParam
|
||||
colorStops := paramList[1:]
|
||||
if len(colorStops) == 0 {
|
||||
return Gradient{}, errors.New("no color stops in gradient")
|
||||
}
|
||||
gradient.ColorStops = parseColorStops(colorStops)
|
||||
} else if gradient.Type == "radial" && (firstParam == "circle" || firstParam == "ellipse") {
|
||||
gradient.Direction = firstParam
|
||||
colorStops := paramList[1:]
|
||||
if len(colorStops) == 0 {
|
||||
return Gradient{}, errors.New("no color stops in gradient")
|
||||
}
|
||||
gradient.ColorStops = parseColorStops(colorStops)
|
||||
} else {
|
||||
gradient.ColorStops = parseColorStops(paramList)
|
||||
}
|
||||
gradient.ID = UniqueGradientID(cssGradient)
|
||||
|
||||
return gradient, nil
|
||||
}
|
||||
|
||||
func splitParams(params string) []string {
|
||||
var parts []string
|
||||
var buf strings.Builder
|
||||
nesting := 0
|
||||
|
||||
for _, r := range params {
|
||||
switch r {
|
||||
case ',':
|
||||
if nesting == 0 {
|
||||
parts = append(parts, buf.String())
|
||||
buf.Reset()
|
||||
continue
|
||||
}
|
||||
case '(':
|
||||
nesting++
|
||||
case ')':
|
||||
if nesting > 0 {
|
||||
nesting--
|
||||
}
|
||||
}
|
||||
buf.WriteRune(r)
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
parts = append(parts, buf.String())
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
func parseColorStops(params []string) []ColorStop {
|
||||
var colorStops []ColorStop
|
||||
for _, p := range params {
|
||||
p = strings.TrimSpace(p)
|
||||
parts := strings.Fields(p)
|
||||
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
colorStops = append(colorStops, ColorStop{Color: parts[0]})
|
||||
case 2:
|
||||
colorStops = append(colorStops, ColorStop{Color: parts[0], Position: parts[1]})
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
return colorStops
|
||||
}
|
||||
|
||||
func GradientToSVG(gradient Gradient) string {
|
||||
switch gradient.Type {
|
||||
case "linear":
|
||||
return LinearGradientToSVG(gradient)
|
||||
case "radial":
|
||||
return RadialGradientToSVG(gradient)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func LinearGradientToSVG(gradient Gradient) string {
|
||||
x1, y1, x2, y2 := parseLinearGradientDirection(gradient.Direction)
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf(`<linearGradient id="%s" `, gradient.ID))
|
||||
sb.WriteString(fmt.Sprintf(`x1="%s" y1="%s" x2="%s" y2="%s">`, x1, y1, x2, y2))
|
||||
sb.WriteString("\n")
|
||||
|
||||
totalStops := len(gradient.ColorStops)
|
||||
for i, cs := range gradient.ColorStops {
|
||||
offset := cs.Position
|
||||
if offset == "" {
|
||||
offsetValue := float64(i) / float64(totalStops-1) * 100
|
||||
offset = fmt.Sprintf("%.2f%%", offsetValue)
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf(`<stop offset="%s" stop-color="%s" />`, offset, cs.Color))
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
sb.WriteString(`</linearGradient>`)
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func parseLinearGradientDirection(direction string) (x1, y1, x2, y2 string) {
|
||||
x1, y1, x2, y2 = "0%", "0%", "0%", "100%"
|
||||
|
||||
direction = strings.TrimSpace(direction)
|
||||
if strings.HasPrefix(direction, "to ") {
|
||||
dir := strings.TrimPrefix(direction, "to ")
|
||||
dir = strings.TrimSpace(dir)
|
||||
parts := strings.Fields(dir)
|
||||
xStart, yStart := "50%", "50%"
|
||||
xEnd, yEnd := "50%", "50%"
|
||||
|
||||
xDirSet, yDirSet := false, false
|
||||
|
||||
for _, part := range parts {
|
||||
switch part {
|
||||
case "left":
|
||||
xStart = "100%"
|
||||
xEnd = "0%"
|
||||
xDirSet = true
|
||||
case "right":
|
||||
xStart = "0%"
|
||||
xEnd = "100%"
|
||||
xDirSet = true
|
||||
case "top":
|
||||
yStart = "100%"
|
||||
yEnd = "0%"
|
||||
yDirSet = true
|
||||
case "bottom":
|
||||
yStart = "0%"
|
||||
yEnd = "100%"
|
||||
yDirSet = true
|
||||
}
|
||||
}
|
||||
|
||||
if !xDirSet {
|
||||
xStart = "50%"
|
||||
xEnd = "50%"
|
||||
}
|
||||
|
||||
if !yDirSet {
|
||||
yStart = "50%"
|
||||
yEnd = "50%"
|
||||
}
|
||||
|
||||
x1, y1 = xStart, yStart
|
||||
x2, y2 = xEnd, yEnd
|
||||
} else if strings.HasSuffix(direction, "deg") {
|
||||
angleStr := strings.TrimSuffix(direction, "deg")
|
||||
angle, err := strconv.ParseFloat(strings.TrimSpace(angleStr), 64)
|
||||
if err == nil {
|
||||
cssAngle := angle
|
||||
svgAngle := (90 - cssAngle) * (math.Pi / 180)
|
||||
|
||||
x1f := 50.0
|
||||
y1f := 50.0
|
||||
x2f := x1f + 50*math.Cos(svgAngle)
|
||||
y2f := y1f + 50*math.Sin(svgAngle)
|
||||
|
||||
x1 = fmt.Sprintf("%.2f%%", x1f)
|
||||
y1 = fmt.Sprintf("%.2f%%", y1f)
|
||||
x2 = fmt.Sprintf("%.2f%%", x2f)
|
||||
y2 = fmt.Sprintf("%.2f%%", y2f)
|
||||
}
|
||||
}
|
||||
|
||||
return x1, y1, x2, y2
|
||||
}
|
||||
|
||||
func RadialGradientToSVG(gradient Gradient) string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf(`<radialGradient id="%s">`, gradient.ID))
|
||||
sb.WriteString("\n")
|
||||
totalStops := len(gradient.ColorStops)
|
||||
for i, cs := range gradient.ColorStops {
|
||||
offset := cs.Position
|
||||
if offset == "" {
|
||||
offsetValue := float64(i) / float64(totalStops-1) * 100
|
||||
offset = fmt.Sprintf("%.2f%%", offsetValue)
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf(`<stop offset="%s" stop-color="%s" />`, offset, cs.Color))
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
sb.WriteString(`</radialGradient>`)
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func UniqueGradientID(cssGradient string) string {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(cssGradient))
|
||||
hash := hex.EncodeToString(h.Sum(nil))
|
||||
return "grad-" + hash
|
||||
}
|
||||
|
||||
var GradientRegex = regexp.MustCompile(`^(linear|radial)-gradient\((.+)\)$`)
|
||||
|
||||
func IsGradient(color string) bool {
|
||||
return GradientRegex.MatchString(color)
|
||||
}
|
||||
Loading…
Reference in a new issue