SVG Morphing

SVG morphing in Datastar requires special handling because, as an XML dialect, SVG is namespaced. This means that <svg> elements (as well as <math> elements) create their own namespace, separate from the HTML namespace.

To morph an SVG element, you must ensure that the target element is wrapped in an outer <svg> tag. This ensures that the inner SVG element is created under the correct namespace.

1<svg>
2    <svg id="target">
3        <circle cx="50" cy="100" r="50" fill="red" />
4    </svg>
5    <circle cx="150" cy="100" r="50" fill="red" />
6</svg>

Basic Circle Color Change #

This example demonstrates morphing an SVG circle’s color. Click the button to change the circle from red to blue.

Demo
1svgMorphingRouter.Get("/circle_color", func(w http.ResponseWriter, r *http.Request) {
2    sse := datastar.NewSSE(w, r)
3    color := svgColors[rand.N(len(svgColors))]
4    sse.PatchElements(fmt.Sprintf(`<svg id="circle-demo"><circle cx="50" cy="50" r="40" fill="%s" /></svg>`, color))
5})

Circle Radius Change #

This example shows how to morph the size of an SVG element. The circle will change to a random radius when you click the button.

Demo
1svgMorphingRouter.Get("/circle_size", func(w http.ResponseWriter, r *http.Request) {
2    sse := datastar.NewSSE(w, r)
3    radius := 15 + rand.N(45) // Random radius between 15-60
4    sse.PatchElements(fmt.Sprintf(`<svg id="size-demo"><circle cx="50" cy="50" r="%d" fill="green" /></svg>`, radius))
5})

Random Shape Transformation #

SVG morphing can handle changing between different shape types. This example morphs to a random shape each time you click.

Demo
1svgMorphingRouter.Get("/shape_transform", func(w http.ResponseWriter, r *http.Request) {
2    sse := datastar.NewSSE(w, r)
3    shape := svgShapes[rand.N(len(svgShapes))]
4    sse.PatchElements(fmt.Sprintf(`<svg id="shape-demo">%s</svg>`, shape))
5})

Multiple Random Elements #

You can morph multiple SVG elements at once. This example updates three circles with random colors and sizes each time you click.

Demo
 1svgMorphingRouter.Get("/multiple_elements", func(w http.ResponseWriter, r *http.Request) {
 2    sse := datastar.NewSSE(w, r)
 3    color1 := svgColors[rand.N(len(svgColors))]
 4    color2 := svgColors[rand.N(len(svgColors))]
 5    color3 := svgColors[rand.N(len(svgColors))]
 6    r1 := 10 + rand.N(20) // radius 10-30
 7    r2 := 10 + rand.N(20)
 8    r3 := 10 + rand.N(20)
 9    sse.PatchElements(fmt.Sprintf(`<svg id="multi-demo">
10        <circle cx="30" cy="30" r="%d" fill="%s" />
11        <circle cx="70" cy="30" r="%d" fill="%s" />
12        <circle cx="50" cy="70" r="%d" fill="%s" />
13    </svg>`, r1, color1, r2, color2, r3, color3))
14})

Animated Sequence #

This example demonstrates a sequence of SVG morphs that happen automatically when triggered, creating a smooth animation effect.

Demo
 1svgMorphingRouter.Get("/animated_morph", func(w http.ResponseWriter, r *http.Request) {
 2    sse := datastar.NewSSE(w, r)
 3    
 4    // First morph
 5    sse.PatchElements(`<svg id="animated-demo"><circle cx="50" cy="50" r="30" fill="red" /></svg>`)
 6    time.Sleep(500 * time.Millisecond)
 7    
 8    // Second morph
 9    sse.PatchElements(`<svg id="animated-demo"><circle cx="50" cy="50" r="45" fill="orange" /></svg>`)
10    time.Sleep(500 * time.Millisecond)
11    
12    // Third morph
13    sse.PatchElements(`<svg id="animated-demo"><circle cx="50" cy="50" r="60" fill="yellow" /></svg>`)
14    time.Sleep(500 * time.Millisecond)
15    
16    // Reset
17    sse.PatchElements(`<svg id="animated-demo"><circle cx="50" cy="50" r="20" fill="green" /></svg>`)
18})

Key Points #