0

我正在尝试复制在 React with Hooks 中看到的量规。这是我第一次使用 D3.js,尽管我设法复制了仪表本身,但行为有点奇怪(指针的转换不起作用)而且我不完全理解 useEffect 和 D3 之间的动态。基本上我想添加两个针,它们每个都会接收不同的值,并在它们的值发生变化时使用转换。

//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 和 angle2 是通过 useState 钩子更新的,但是转换不起作用并且使针看起来有问题。如果没有过渡,它可以正常工作,但是针的运动看起来很粗糙。我不确定问题是否出在我整合 d3 部分的方式上,或者是否所有重新渲染(因为我正在并行更改两个值)影响钩子的性能,也许我应该以不同的方式更新角度方法。感谢您的时间!

4

1 回答 1

2

我不是react专家,但在我看来你想创建两个useEffect块。第一个,只触发一次以进行初始d3设置。第二,更新你的角度并移动指针。

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>

于 2021-01-05T16:10:34.740 回答