Skip to content

# SVG

## Create SVG

You can create SVG using JSX or lit-HTML. For example, below is a reimplementation of a snabbdom example by Jon Kleiser (@jkleiser).

### SVG use JSX

    const style=`
    svg {
      display: block;
      margin-bottom: 10px;
      border: 1px solid gray;
    }
    g#carousel {
      -webkit-transition: -webkit-transform 1s ease;
      transition: transform 1s ease;
    }
    polygon {
      stroke: #808000;
      transition: fill 0.5s linear;
    }
    polygon#yellow {
      fill: rgba(255,255,0,0.4);
    }
    polygon#yellow:hover, polygon#yellow:active {
      fill: yellow;
    }
    polygon#green {
      fill: rgba(0,128,0,0.4);
    }
    polygon#green:hover, polygon#green:active {
      fill: green;
    }
    polygon#magenta {
      fill: rgba(255,0,255,0.4);
    }
    polygon#magenta:hover, polygon#magenta:active {
      fill: magenta;
    }
    polygon#red {
      fill: rgba(255,0,0,0.4);
    }
    polygon#red:hover, polygon#red:active {
      fill: red;
    }
    polygon#cyan {
      fill: rgba(0,255,255,0.4);
    }
    polygon#cyan:hover, polygon#cyan:active {
      fill: cyan;
    }
    polygon#blue {
      fill: rgba(0,0,255,0.4);
    }
    polygon#blue:hover, polygon#blue:active {
      fill: blue;
    }
    `
    const triangles = [
    {id: "yellow", rot: 0},
    {id: "green", rot: 60},
    {id: "magenta", rot: 120},
    {id: "red", rot: 180},
    {id: "cyan", rot: 240},
    {id: "blue", rot: 300}
    ];

    class SvgComponent extends Component {
      state = 0;

     view = state => {
        const transform = "rotate(" + state + "deg)";
        return <div className="view">
        <style>{style}</style>
          <svg width="380" height="380" viewBox="-190,-190,380,380">
            <g id="carousel" style={{transform}}>
              {triangles.map(t =>
                <polygon id={t.id}
                  points="-50,-88 0,-175 50,-88"
                  transform={`rotate(${t.rot})`}
                  stroke-width="3" />
              )}
            </g>
          </svg>
          <button $onclick="rot+60">Rotate Clockwise</button>
          <button $onclick="rot-60">Rotate Anticlockwise</button>
          <button $onclick="reset">Reset</button>
        </div>
      };

      update = {
        "rot+60": state => state + 60,
        "rot-60": state => state - 60,
        "reset": state => 0,
      };
    }
    new SvgComponent().start(document.body);

### SVG use lit-HTML

    const style=`
    svg {
      display: block;
      margin-bottom: 10px;
      border: 1px solid gray;
    }
    g#carousel {
      -webkit-transition: -webkit-transform 1s ease;
      transition: transform 1s ease;
    }
    polygon {
      stroke: #808000;
      transition: fill 0.5s linear;
    }
    polygon#yellow {
      fill: rgba(255,255,0,0.4);
    }
    polygon#yellow:hover, polygon#yellow:active {
      fill: yellow;
    }
    polygon#green {
      fill: rgba(0,128,0,0.4);
    }
    polygon#green:hover, polygon#green:active {
      fill: green;
    }
    polygon#magenta {
      fill: rgba(255,0,255,0.4);
    }
    polygon#magenta:hover, polygon#magenta:active {
      fill: magenta;
    }
    polygon#red {
      fill: rgba(255,0,0,0.4);
    }
    polygon#red:hover, polygon#red:active {
      fill: red;
    }
    polygon#cyan {
      fill: rgba(0,255,255,0.4);
    }
    polygon#cyan:hover, polygon#cyan:active {
      fill: cyan;
    }
    polygon#blue {
      fill: rgba(0,0,255,0.4);
    }
    polygon#blue:hover, polygon#blue:active {
      fill: blue;
    }
    `
    const triangles = [
    {id: "yellow", rot: 0},
    {id: "green", rot: 60},
    {id: "magenta", rot: 120},
    {id: "red", rot: 180},
    {id: "cyan", rot: 240},
    {id: "blue", rot: 300}
    ];

    class SvgComponent extends Component {
      state = 0;

      view = state => {
        const items = triangles.map(t =>
          svg`<polygon id="${t.id}"
            points="-50,-88 0,-175 50,-88"
            transform="rotate(${t.rot})"
            stroke-width="3" />`
        );
        return html`<div class="view">
          <style>${style}</style>
          <svg width="380" height="380" viewBox="-190,-190,380,380">
            <g id="carousel" style="transform: rotate(${state}deg);">
              ${items}
            </g>
          </svg>
          <button @click=${run("@rot+60")}>Rotate Clockwise</button>
          <button @click=${run("@rot-60")}>Rotate Anticlockwise</button>
          <button @click=${run("@reset")}>Reset</button>
        </div>`;
      };

      update = {
        "@rot+60": state => state + 60,
        "@rot-60": state => state - 60,
        "@reset": () => 0,
      };
    }
    new SvgComponent().start(document.body);

## SVG - xlink:href

You can use xlinkHref to define the xlink:href attribute of SVG.

    // SVG - xlink
    const view = () => <svg viewBox="0 0 150 20">
      <a xlinkHref="https://apprun.js.org/">
        <text x="10" y="10" font-size="5">Click Here</text></a>
    </svg>

    app.start(document.body, {}, view);

## SVG Event Handlers

You can handle the onclick event of SVG elements. Or use the $onclick directive

    // SVG - $onclick
    const view = state => <>
    <div>click the buttons:</div>
    <svg viewBox="0 0 520 520" xmlns="http://www.w3.org/2000/svg">
      <rect x="10" y="10" width="90" height="20" fill="#aaa"
        $onclick="test" id="$onclick"/>
      <rect x="110" y="10" width="90" height="20" fill="#bbb"
        onclick="app.run('test', event)" id="onclick"/>
    </svg>
    </>

    const update = {
      test: (state, evt) => alert("You have used: " + evt.target.id)
    }
    app.start(document.body, '', view, update);

## SVG Animation

You can use the animate element to add animation to SVG.

    // SVG - animation
    const view = () => <>
      <svg height="60" width="160">
        <rect width="100%" height="100%" rx="10" ry="10" fill="lightgrey" />
        <circle cx="30" cy="30" r="20" fill='lime'>
        <animate
              attributeType="XML"
              attributeName="fill"
              values="lime;lightgrey;lime;lightgrey"
              dur="0.5s"
              repeatCount="indefinite"/>
        </circle>
        <circle cx="80" cy="30" r="20" fill='yellow' fill-opacity='0.2'/>
        <circle cx="130" cy="30" r="20" fill='orangered' fill-opacity='0.2' />
      </svg>
    </>;
    app.start(document.body, {}, view);