Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to animate shape or image file along SVG paths with the Vivus js?

I am using vivusjs library to animate SVG, i want to animate an image file or a shape along animated SVG . somthing like as below:

enter image description here

White line is an animating SVG path and green pen is my image file. i need it in Vivusjs library.

like image 315
MHS Avatar asked Oct 26 '25 11:10

MHS


1 Answers

No need for a library, you can do all with native JSWC JavaScript

Create your own JavaScript Web Component (JSWC) <draw-path> (supported in all modern browsers)

Do all animations with JavaScript. Key is to set the pathLength to 1 and use getPointAtLength to position the SVG pen at the correct location.

Then all HTML required to display (see SO snippet below):

is:

<draw-path d='M25 50a25 25 0 1 1 80 0a25 25 0 1 1-80 0'></draw-path>
<draw-path d='M25 25h50v50h-50v-50z' stroke='green' stroke-width='5' speed="0.007"></draw-path>
<draw-path stroke='red' stroke-width='5' speed=".01"></draw-path>

window.customElements.define("draw-path", class extends HTMLElement {
    constructor() {
      let template = (id) => document.getElementById(id).content.cloneNode(true);
      super() // super sets and returns this scope
        .attachShadow({mode: "open"}) // sets and returns this.shadowRoot
        .append(template(this.nodeName));
      this.line = this.shadowRoot.querySelector("#line");
      this.line.setAttribute("d", this.getAttribute("d") || "m10 60c30-70 55-70 75 0s55 70 85 0");
      this.line.setAttribute("stroke", this.getAttribute("stroke") || "black");
      this.line.setAttribute("stroke-width", this.getAttribute("stroke-width") || "2");
      this.pen = this.shadowRoot.querySelector("#pen");
      this.onmouseover = (evt) => this.draw();
    }
    connectedCallback() {
      this.draw();
    }
    showpen(state = true, scale) {
      this.pen.style.display = state ? 'initial' : 'none';
    }
    draw() {
      clearInterval(this.drawing);
      this.showpen();
      this.dashoffset = 1;
      this.pathlength = this.line.getTotalLength();
      this.drawing = setInterval(() => this.update(), 50);
    }
    update() {
      this.dashoffset -= this.getAttribute("speed") || 0.02;
      let {x,y} = this.line.getPointAtLength(this.pathlength - this.dashoffset * this.pathlength);
      this.pen.setAttribute("transform", `translate(${x-2} ${y-2})`);
      this.line.style.strokeDashoffset = this.dashoffset;
      if (this.dashoffset <= 0) this.end();
    }
    end() {
      clearInterval(this.drawing);
      this.showpen(false);
      //console.log("end",this.line);
      clearTimeout(this.timeout);
      this.timeout = setTimeout(()=>this.draw(),2000);
    }
  });
<draw-path d='M25 50a25 25 0 1 1 80 0a25 25 0 1 1-80 0'></draw-path>
<draw-path d='M25 25h50v50h-50v-50z' stroke='green' stroke-width='5' speed="0.007"></draw-path>
<draw-path stroke='red' stroke-width='8' speed=".01"></draw-path>

<template id="DRAW-PATH">
  <style>
    :host {  display: inline-block }
    svg { width: 180px; height: 130px; background: beige }
  </style>
  <svg xmlns="http://www.w3.org/2000/svg">
    <path id='line' pathlength='1' stroke-dasharray='1' stroke-dashoffse='1' fill='transparent'/>
    <path id='pen' stroke='black' stroke-width='2' fill='gold' d='m12 19l7-7l3 3l-7 7l-3-3zm6-6l-2-8l-14-3l4 15l7 1l5-5zm-16-11l8 8m-1 1a2 2 0 104 0a2 2 0 10-4 0'/>
  </svg>
</template>

Note:

Be aware M or m (moves) in paths create a new stroke, drawn at the same time, not sequentially.

So stroke-dash* settings are applied concurrent.

That is why in all blogs you only see single stroke simple paths or polylines used.

like image 51
Danny '365CSI' Engelman Avatar answered Oct 29 '25 01:10

Danny '365CSI' Engelman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!