简体   繁体   English

在 React Hooks 和 D3 中使用转换

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM