Skip to content Skip to sidebar Skip to footer

D3 Animate Group By Path

this is my next question to enhance original question. So what I am trying is to animate triangle mark and text tooltip along the filling path. So the main problem here is rotatin

Solution 1:

Firstly, you can offset the turning by using 180 - angleDegrees instead of angleDegrees for the text.

Secondly, you probably want the text to be at about the same distance from the arc at all times, not too close so it overlaps, or too far away because it looks weird. For this, one solution is to make the node text-anchor: middle, and then position it during the transition.

var chart = d3.select("#speedometer");

const arc = d3
  .arc()
  .outerRadius(120)
  .innerRadius(90)
  .startAngle(-Math.PI / 2);

chart
  .append("path")
  .datum({
    endAngle: Math.PI / 2
  })
  .attr("transform", "translate(160, 180)")
  .attr("class", "background")
  .style("fill", "#495270")
  .attr("d", arc);

const mainGroup = chart.append('g')
  .datum({
    endAngle: -Math.PI / 2
  });

const triangle = mainGroup
  .append('path')
  .attr("d", "M3.937,0,7.873,14H0Z")
  .datum({
    endAngle: -Math.PI / 2
  })

const text = mainGroup.append('text')
  .text('hello there')
  .datum({
    endAngle: -Math.PI / 2
  })
  .attr("text-anchor", "middle") // to more easily position the text
  .transition()
  .duration(3000)
  .attrTween("transform", function(d) {
    const topVal = (300 / 2 - 16);
    const interpolateAngle = d3.interpolate(d.endAngle, newAngle);

    // We want to add some offset so the text is always easily visible// Think about what happens when the following functions are called with// angles -90, -45, 0, 45, 90const textWidth = this.getBBox().width;
    const offsetX = function(angle) {
      return (angle / 90) * textWidth / 2;
    };

    const offsetY = function(angle) {
      if (angle < 0) {
        returnoffsetY(-angle);
      }
      
      // The -4 and -3 are a little bit trial and error, and can be// tweaked further toreturn -4 + (1 - angle / 90) * -3;
    };

    returnfunction(t) {
      const angleRadians = interpolateAngle(t);
      const angleDegrees = 360 * angleRadians / (2 * Math.PI);

      return`
        translate(0 15)
        rotate(${180 - angleDegrees})
        translate(${offsetX(angleDegrees)}${offsetY(angleDegrees)})
      `;
    };
  });

const newAngle = (70 / 100) * Math.PI - Math.PI / 2;

const foreground = chart
  .append("path")
  .datum({
    endAngle: -Math.PI / 2
  })
  .style("fill", "rgb(50, 188, 228)")
  .attr("transform", "translate(160, 180)")
  .attr("d", arc);

foreground
  .transition()
  .duration(3000)
  .attrTween("d", function(d) {
    const interpolate = d3.interpolate(d.endAngle, newAngle);
    returnfunction(t) {
      d.endAngle = interpolate(t);
      returnarc(d);
    };
  });

mainGroup
  .transition()
  .duration(3000)
  .attrTween("transform", function(d) {
    const topVal = (300 / 2 - 16);
    const interpolate = d3.interpolate(d.endAngle, newAngle);
    returnfunction(t) {
      const angleRadians = interpolate(t);
      const angleDegrees = 360 * angleRadians / (2 * Math.PI);
      return`
            translate(158 176)
            rotate(${angleDegrees + 180} 3.5 7)
            translate(0 ${topVal})
          `;
    };
  });

functionpathTween(path) {
  const length = path.node().getTotalLength(); // Get the length of the pathconst r = d3.interpolate(0, length); // Set up interpolation from 0 to the path lengthreturnfunction(t) {
    const point = path.node().getPointAtLength(r(t)); // Get the next point along the path
    d3
      .select(this) // Select the circle
      .attr("transform", `translate(${point.x}, ${point.y})`);
  };
}
.main-wrapper {
  max-width: 80%;
  margin: 20px auto;
}

.element {
  display: flex;
  flex-flow: column nowrap;
  margin-bottom: 20px;
  border: 1px solid rgba(0, 0, 0, 0.4);
  padding: 20px;
  border-radius: 6px;
}

.element.title {
  margin-bottom: 4px;
  font-weight: 500;
}

.element.description {
  margin-bottom: 10px;
  color: rgba(0, 0, 0, 0.4);
}

#speedometer {
  width: 300px;
  height: 300px;
  overflow: visible !important;
}

canvas {
  width: 100%;
  height: 100%;
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script><divclass="main-wrapper"><sectionclass="ui-section"><divclass="element"><divclass="title">
        Speedometr
      </div><divclass="content"><svgid="speedometer"viewbox="0 0 300 300"></svg></div></div></section></div>

Post a Comment for "D3 Animate Group By Path"