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);