I'm using React, and what I want to achieve is to have an animation on SVG arc path when they change. Basically, I've a gauge that show a certain value between 0 and 100, and the value can change (in the following example it changes every second).
I've created this codepen that simulate what I want (code below): https://codepen.io/Gesma94/pen/oJvjwe
As you can see in the example, I've a Gauge created with d3 inside an SVG, where the blue bar can take more or less space in time; as you can see, when the Gauge is re-rendered, the new blue bar is just rendered, without any animation between the "old point" and "new point".
What I would like to achieve is having a smooth movement between the point the bar was before, and the point where the bar is going to be (hope I've been clear).
class MyComponent extends React.Component {
render() {
console.log("Rendering");
const value = (this.props.value * Math.PI / 100) - Math.PI/2;
const currentValueFilledCircle = d3.arc()
.innerRadius(37.5)
.outerRadius(49.5)
.startAngle(-Math.PI/2)
.endAngle(value)(null);
const currentValueEmptyCircle = d3.arc()
.innerRadius(37.5)
.outerRadius(49.5)
.startAngle(value)
.endAngle(Math.PI/2)(null);
return (
<div style={{width: "300px", height: "300px"}}>
<svg height="100%" width="100%" viewBox="-50 -50 100 100">
<g>
<path d={currentValueFilledCircle} fill="blue" />
<path d={currentValueEmptyCircle} fill="gray" />
</g>
</svg>
</div>
);
};
}
class App extends React.Component {
constructor() {
super();
this.value = 77;
}
componentDidMount() {
this.interval = setInterval(() => {
const diff = Math.floor(Math.random() * 7) - 3;
let newCurrentValue = this.value + diff;
if (newCurrentValue > 100) newCurrentValue = 100;
else if (newCurrentValue < 0) newCurrentValue = 0;
this.value = newCurrentValue;
this.forceUpdate();
}, 500);
}
render() {
return (<MyComponent value={this.value} />)
}
}
ReactDOM.render(<App />, document.getElementById('app'));
So, I struggled for some times, but I found a solution using react-move/Animate
: https://react-move.js.org/#/documentation/animate
Since I couldn't make it work on Codepen, I recreate the situation in a sandbox, there it is: https://codesandbox.io/embed/0qyrmyrw
The gist is the following part of code:
<Animate
start={{ value: this.props.value }}
update={{
value: [this.props.value], // Before the sqaure brackets!!
timing: { duration: 750 }
}}
>
{(state: { value: number }) => {
const scaledValue = (state.value * Math.PI) / 100 - Math.PI / 2;
const currentValueFilledCircle = arc()
.innerRadius(37.5)
.outerRadius(49.5)
.startAngle(-Math.PI / 2)
.endAngle(scaledValue)(null);
const currentValueEmptyCircle = arc()
.innerRadius(37.5)
.outerRadius(49.5)
.startAngle(scaledValue)
.endAngle(Math.PI / 2)(null);
return (
<React.Fragment>
<path d={currentValueFilledCircle} fill="blue" />
<path d={currentValueEmptyCircle} fill="gray" />
</React.Fragment>
);
}}
</Animate>
Basically, by writing update={{value: [this.props.value] ... }}
, the Animate
Component just run a set of render() method with different values, from the previous to the current, and so it gives a smooth-movement effect.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.