skip to Main Content

I need to animate this so that it’ll look like a running conveyor belt, is there are any way to achieve it?

const cx = 50;
const cy = 50;
const width = 40;
const radius = 100; // CV size
const TwoPi = Math.PI * 0.5;

const circ = TwoPi * radius;
const height = circ / 4; // Roller counts
const parent = document.getElementById("bend");

for (let i = 0; i < circ; i += height) {
    let seg = document.createElementNS("http://www.w3.org/2000/svg", "path");
    
    let rs = (i / circ) * TwoPi;
    let re = ((i + height) / circ) * TwoPi;
    
    let ss = Math.sin(rs);
    let cs = Math.cos(rs);
    let se = Math.sin(re);
    let ce = Math.cos(re);
    
    seg.setAttribute("d",
        `M${(cs * radius) + cx},${(ss * radius) + cy}` +
        `A${radius},${radius} ${((re - rs) / Math.PI) * 180},0,1 ${(ce * radius) + cx},${(se * radius) + cy}` +
        `L${(ce * (radius - width)) + cx},${(se * (radius - width)) + cy}` +
        `A${radius - width},${radius - width} ${((re - rs) / Math.PI) * -180},0,0 ${(cs * (radius - width)) + cx},${(ss * (radius - width)) + cy}z`
    );
    
    seg.setAttribute("fill", "url(#grad2)");
    seg.setAttribute("stroke", "#008000");
    
    parent.appendChild(seg);
}
<svg width="200" height="200" viewBox="0 0 200 200" style="transform: rotate(-90deg)">
  <defs>
    <linearGradient id="grad2" x1="0%" y1="0%" x2="40%" y2="100%">
      <stop offset="0%" style="stop-color:#008000;stop-opacity:1"/>
      <stop offset="100%" style="stop-color:#c7fdc7;stop-opacity:1"/>
    </linearGradient>
  </defs>
    <g id="bend"></g>
</svg>

Here’s the preview of the above code, and this is the running animation example.

Thankyou.

2

Answers


  1. Here is a possible solution (run the snippet below):

    const drawSegment = (fromAngle, toAngle, innerRadius, outerRadius, centerX, centerY) => {
      const svg = d3.select('svg');
      const x1 = centerX + innerRadius * Math.sin(fromAngle);
      const y1 = centerY - innerRadius * Math.cos(fromAngle);
      const x2 = centerX + outerRadius * Math.sin(fromAngle);
      const y2 = centerY - outerRadius * Math.cos(fromAngle);
      const x3 = centerX + outerRadius * Math.sin(toAngle);
      const y3 = centerY - outerRadius * Math.cos(toAngle);
      const x4 = centerX + innerRadius * Math.sin(toAngle);
      const y4 = centerY - innerRadius * Math.cos(toAngle);
      const path = `M ${x1},${y1} L ${x2},${y2} A ${outerRadius},${outerRadius} 0 0 1 ${x3},${y3} L ${x4},${y4} A ${innerRadius}, ${innerRadius} 0 0 0 ${x1},${y1} Z`;
      
      svg.append('path')
        .attr('d', path)
        .attr('stroke', '#008000')
        .attr('fill', 'url(#grad)')
    }
    
    const a = Math.PI / 8;
    let start = 0;
    
    setInterval(() => {
      d3.select('svg').selectAll('path').remove();
      if (start < 1) {
        start += 0.02;
      }
      else
        start = 0;
    
      if (start > 0) {
        drawSegment(0, start * a, 50, 80, 20, 100);
      }
      for (let i = start; i < 4; i++) {
        drawSegment(a * i, Math.min((i + 1) * a, a * 4), 50, 80, 20, 100);
      }
    }, 50);
    svg {
      border: 1px solid #000;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg width="200" height="120">
      <defs>
        <linearGradient id="grad" x1="0%" y1="0%" x2="40%" y2="100%">
          <stop offset="0%" style="stop-color:#008000;stop-opacity:1"/>
          <stop offset="100%" style="stop-color:#c7fdc7;stop-opacity:1"/>
        </linearGradient>
      </defs>
        <g id="bend"></g>
    </svg>
    Login or Signup to reply.
  2. Here is a version made with a slice of a circle that is repeated. The animation is made with the <animateTransform> element.

    Less calculations and more construction.

    <svg width="200" viewBox="0 0 200 200">
      <defs>
        <linearGradient id="grad" x1="60%" y1="60%" x2="90%" y2="90%">
          <stop offset="0%" stop-color="#008000" stop-opacity="1"/>
          <stop offset="100%" stop-color="#c7fdc7" stop-opacity="1"/>
        </linearGradient>
        <mask id="m1">
          <rect x="50" y="50" width="100" height="100" fill="white"/>
        </mask>
        <circle id="c1" cx="0" cy="0" r="70" fill="none"
          stroke="url(#grad)" stroke-width="28" pathLength="360"
          stroke-dasharray="19 360" />
      </defs>
      <g mask="url(#m1)">
        <g transform="translate(50 150) rotate(-180)" >
          <g>
            <circle id="c1" cx="0" cy="0" r="70" fill="none"
              stroke="darkgreen" stroke-width="30" />
            <use href="#c1"/>
            <use href="#c1" transform="rotate(20)"/>
            <use href="#c1" transform="rotate(40)"/>
            <use href="#c1" transform="rotate(60)"/>
            <use href="#c1" transform="rotate(80)"/>
            <use href="#c1" transform="rotate(100)"/>
            <use href="#c1" transform="rotate(120)"/>
            <use href="#c1" transform="rotate(140)"/>
            <use href="#c1" transform="rotate(160)"/>
            <animateTransform
              attributeName="transform"
              attributeType="XML"
              type="rotate"
              from="0"
              to="80"
              dur="5s"
              repeatCount="indefinite" />
          </g>
        </g>
      </g>
    </svg>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search