[英]Using transitions in React Hooks and D3
I am trying to replicate the gauge seenhere in React with Hooks.我正在尝试复制在 React with Hooks 中看到的量规。 It's the first time I am working with D3.js and even though I managed to replicate the gauge itself, the behavior is a bit strange (transition of the needles does not work) and I am not fully understanding the dynamics between useEffect and D3.
这是我第一次使用 D3.js,尽管我设法复制了仪表本身,但行为有点奇怪(指针的转换不起作用),我并不完全理解 useEffect 和 D3 之间的动态。 Basically I want to add two needles that will each receive different values and use a transition when their value changes.
基本上我想添加两个针,它们每个都会接收不同的值,并在它们的值发生变化时使用转换。
//declaring angle value
const [angle1, setAngle1] = useState(0)
//useEffect hook
useEffect(() => {
const outerR = Math.min(window.innerWidth, window.innerHeight) / 2
const svg = select(svgRef.current)
svg.selectAll('*').remove()
const EXTRA_ANGLE = 15
const angleScale = scaleLinear()
.domain([0, 100])
.range([-90 - EXTRA_ANGLE, 90 + EXTRA_ANGLE])
const arcAxis = axisRadialInner(
angleScale.copy().range(angleScale.range().map(deg2rad)),
outerR - 5
)
svg
.attr('width', outerR * 2)
.attr('height', outerR * 1.5)
.attr(
'viewBox',
`${-outerR} ${-outerR * 0.8} ${outerR * 2} ${outerR * 1}`
)
.append('g')
.classed('axis', true)
.call(arcAxis)
const needle1 = svg
.append('g')
.attr('transform', `scale(${outerR * 0.85})`)
.append('path')
.classed('needle1', true)
.attr(
'd',
['M0 -1', 'L0.03 0', 'A 0.03 0.03 0 0 1 -0.03 0', 'Z'].join(' ')
)
.transition()
.attr('transform', `rotate(${angleScale(angle1)})`)
const needle2 = svg
.append('g')
.attr('transform', `scale(${outerR * 0.85})`)
.append('path')
.classed(needle2, true)
.attr(
'd',
['M0 -1', 'L0.03 0', 'A 0.03 0.03 0 0 1 -0.03 0', 'Z'].join(' ')
)
.transition()
.attr('transform', `rotate(${angleScale(angle2)})`)
// Add val label
const label = svg
.append('text')
.classed('label', true)
.attr('x', 0)
.attr('y', outerR * 0.2)
.attr('text-anchor', 'middle')
.text(angle1)
function deg2rad (deg) {
return (deg * Math.PI) / 180
}
}, [angle1, angle2])
//updating an angle
function updateAngle1(){
setInterval(() => {
setAngle1(angle1 => angle1 + 1)
}, 200);
Angle1 and angle2 are updated via useState hook, but the transition does not work and makes the needles look bugged. Angle1 和 angle2 是通过 useState 钩子更新的,但是过渡不起作用并且使针看起来有问题。 Without the transition it works OK, but the movement of the needles looks very rough.
如果没有过渡,它可以正常工作,但是针的运动看起来很粗糙。 I am not sure if the problem is in the way I am integrating the d3 part or if all the re-renders (because I am changing two values in paralel) affect the performance of the hook and maybe I should update the angles in a different way.
我不确定问题是否出在我整合 d3 部分的方式上,或者是否所有重新渲染(因为我正在并行更改两个值)影响钩子的性能,也许我应该以不同的方式更新角度方法。 Thank you for your time!
感谢您的时间!
I'm not a react
expert but it seems to me your want to create two useEffect
blocks.我不是
react
专家,但在我看来你想创建两个useEffect
块。 The first, only fires once to do the initial d3
set-up.第一个,只触发一次以进行初始
d3
设置。 The second, to update your angle and move the needle.第二,更新你的角度并移动指针。
const {useState, useEffect} = React; const App = () => { //declaring angle value let [angle1, setAngle1] = useState(0); function deg2rad (deg) { return (deg * Math.PI) / 180; } const EXTRA_ANGLE = 15; const angleScale = d3.scaleLinear().domain([0, 100]).range([-90 - EXTRA_ANGLE, 90 + EXTRA_ANGLE]); useEffect(() => { const svg = d3.select('svg'); const outerR = Math.min(window.innerWidth, window.innerHeight) / 2; const arcAxis = d3.axisRadialInner( angleScale.copy().range(angleScale.range().map(deg2rad)), outerR - 5 ); svg.attr('width', outerR * 2).attr('height', outerR * 1.5).attr( 'viewBox', `${-outerR} ${-outerR * 0.8} ${outerR * 2} ${outerR * 1}` ).append('g').classed('axis', true).call(arcAxis); const needle1 = svg.append('g').attr('transform', `scale(${outerR * 0.85})`).append('path').classed('needle1', true).attr( 'd', ['M0 -1', 'L0.03 0', 'A 0.03 0.03 0 0 1 -0.03 0', 'Z'].join(' ') ); // Add val label const label = svg.append('text').classed('label', true).attr('x', 0).attr('y', outerR * 0.2).attr('text-anchor', 'middle'); // kick off updates setInterval(() => { angle1 += 1; if (angle1 > 100) angle1 = 100; setAngle1(angle1); }, 500); },[]) useEffect(() => { d3.select('.needle1').transition().attr('transform', `rotate(${angleScale(angle1)})`); d3.select('.label').text(angle1); }, [angle1]) return <svg></svg>; } // Render it ReactDOM.render( <App />, document.getElementById("react") );
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/d3-radial-axis@1.6.4/dist/d3-radial-axis.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="react"></div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.