javascript - 即使在 React 中使用 .exit().remove(),D3 也会继续重新渲染

标签 javascript reactjs d3.js

我想在窗口调整大小时刷新仪表,因为出于某种原因,手动调整大小时,在 d3 中创建的仪表在小屏幕上被裁剪,但如果您在同一个较小的屏幕上刷新,它的位置很好。这使我得出结论,我需要在调整屏幕大小时重绘 d3 组件。

这是我的代码:

import * as d3 from "d3";
import React, { useRef, useEffect, useContext } from "react";
import styled, {ThemeContext} from "styled-components"

const Container = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid ${({theme}) => theme.colors.primaryBlack};
  border-radius: 10px;
  box-shadow: 0.5px 0.5px 3.5px ${props => props.theme.colors.primaryBlack};
`

const SVGContainer = styled.svg`
  display: block;  
  width: 23em;
  height: 20em;
`

const Gauge = ({percent}) => {

  const theme = useContext(ThemeContext)
  const d3Ref = useRef(null)
  const createArc = d3.arc()
    .innerRadius(110)
    .outerRadius(140)
    .startAngle((-2/3)*Math.PI)

  const arcTween = newAngle => {
    return d => {
        const interpolate = d3.interpolate(d.endAngle, newAngle)
        return t => {
          d.endAngle = interpolate(t)
          return createArc(d)
        }
    }
  }

  const draw = () => {
    const d3Container = d3.select(d3Ref.current)

    // Refresh the container, remove old drawings
    const container = d3Container.append("g").style("transform", "translate(50%, 60%)")

    // Create the 100% custom arc for background
    container.append("path")
        .datum({endAngle: (2/3)*Math.PI})
        .style("fill", "#F2F2F2")
        .attr("d", createArc)

    // Create the progress custom arc for background
    const progress = container.append("path")
        .datum({endAngle: (-2/3)*Math.PI})
        .style("fill", "#4ABDAC")
        .attr("d", createArc)

    container.append("text")
        .style("font-size", "6.2rem")
        .style("font-weight", "900")
        .style("font-family", "Lato")
        .style("transform", "translate(0%, 7%)")
        .attr("text-anchor", "middle")
        .text(`${percent}`)

    container.append("text")
        .style("font-size", "1.2rem")
        .style("font-family", "Lato")
        .attr("text-anchor", "middle")
        .style("transform", "translate(0%, 15%)")
        .text("Looking good!")

    container.append("text")
        .style("font-size", "1.2rem")
        .style("font-family", "Lato")
        .style("fill", "#4ABDAC")
        .style("transform", "translate(0%, -20%)")
        .attr("text-anchor", "middle")
        .text("↑ 5 pts")

    progress.transition().duration(2000).attrTween("d", arcTween(((2/3)*Math.PI)*(((2*percent)/100)-1)))
    d3Container.exit().remove()
  }

  useEffect(() => {
    if(d3Ref.current){
      draw()
    }
  }, [d3Ref.current])

  useEffect(() => {
    if(typeof window !== undefined){
      window.addEventListener("resize", draw)
    }

    return () => window.removeEventListener("resize", null)
  }, [])

  return (
    <Container theme={theme}>
      <SVGContainer ref={d3Ref} /> 
    </Container>
  )
}

export default Gauge

我遇到的最大问题是 d3 一直在追加,这让我相信 .exit().remove 不起作用,或者我只是缺少某种 React导致这种行为的知识。

有什么线索吗?

最佳答案

经过反复试验,

看来我需要通过D3 手动删除g 元素。 我在每次抽奖前添加了 d3.select("g").remove()

关于javascript - 即使在 React 中使用 .exit().remove(),D3 也会继续重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58055910/

相关文章:

javascript - react lodash 删除不工作

javascript - 在react-redux中异步函数成功后如何调用组件的方法?

html - 文本重叠视频标签 CSS

javascript - 如何在 Material-ui React 表格​​中更改表格单元格宽度

javascript - 使用 d3.js 单击圆圈来显示工具提示

javascript - 使用 Javascript 和 CSS 生成博客文章

javascript - 绑定(bind)类 - 数组的项目

javascript - 如何在对象数组中查找和编辑对象的属性?

javascript - 一次加载数据,但是有一个全局变量 "var data;"是好习惯吗

javascript - 将节点添加到 D3 树 v4