我正在用美国图表5‘S XY图表来展示一些数据.当一个按钮被点击时,用户可以在MUI对话框中看到这个图表,以便对其进行一些操作.然而,当我想要用唯一的ID在MUI对话框中显示我的图表时,它会给出"找不到具有唯一ID的HTML元素"错误.当我将相同的图表放在对话框外部的相同组件中时,一切都工作得很好.

我定义图表的部分:

    useLayoutEffect(() => {
    let root = am5.Root.new(id);
    root.utc = true;

    // Set themes
    // https://www.amcharts.com/docs/v5/concepts/themes/
    root.setThemes([am5themes_Animated.new(root)]);
    root._logo?.dispose();

    // Create chart
    // https://www.amcharts.com/docs/v5/charts/xy-chart/
    let chart = root.container.children.push(
      am5xy.XYChart.new(root, {
        panX: false,
        panY: false,
        pinchZoomX: false,
        pinchZoomY: false,
      })
    );

    // Add cursor
    // https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
    let cursor = chart.set("cursor", am5xy.XYCursor.new(root, {}));
    cursor.lineY.set("visible", false);
    cursor.lineX.set("visible", false);

    // Create axes
    // https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
    let xAxis = chart.xAxes.push(
      am5xy.DateAxis.new(root, {
        baseInterval: {
          timeUnit: "month",
          count: 3,
        },
        gridIntervals: [{ timeUnit: "month", count: 3 }],
        renderer: am5xy.AxisRendererX.new(root, {}),
        tooltip: am5.Tooltip.new(root, {}),
        dateFormats: {
          month: "MM/yy",
        },
        tooltipDateFormats: {
          month: "MM/yy",
        },
      })
    );

    let yAxis = chart.yAxes.push(
      am5xy.ValueAxis.new(root, {
        renderer: am5xy.AxisRendererY.new(root, {}),
      })
    );

    let series = chart.series.push(
      am5xy.LineSeries.new(root, {
        name: "Series",
        xAxis: xAxis,
        yAxis: yAxis,
        valueYField: "value",
        valueXField: "date",
        tooltip: am5.Tooltip.new(root, {
          labelText: "{valueY}",
        }),
        fill: am5.color("#fdce97"),
        stroke: am5.color("#fdce97"),
        width: 4,
      })
    );

    let otherSeries = chart.series.push(
      am5xy.LineSeries.new(root, {
        name: "Other Series",
        xAxis: xAxis,
        yAxis: yAxis,
        valueYField: "value",
        valueXField: "date",
        tooltip: am5.Tooltip.new(root, {
          labelText: "{valueY}",
        }),
        fill: am5.color("#19214d"),
        stroke: am5.color("#19214d"),
      })
    );

    seriesRef.current = otherSeries; // chart assigned to the reference to use later

    series.bullets.push(function () {
      let bulletCircle = am5.Circle.new(root, {
        radius: 2,
        stroke: am5.color("#fdce97"),
        strokeWidth: 1.5,
      });
      return am5.Bullet.new(root, {
        sprite: bulletCircle,
      });
    });

    otherSeries.bullets.push(function () {
      let bulletCircle = am5.Circle.new(root, {
        radius: 2,
        stroke: am5.color("#19214d"),
        strokeWidth: 1.5,
      });
      return am5.Bullet.new(root, {
        sprite: bulletCircle,
      });
    });

    // Invisible bullet which will be dragged (to avoid some conflicting between
    // drag position and bullet position which results flicker)
    otherSeries.bullets.push(() => {
      let bulletCircle = am5.Circle.new(root, {
        radius: 6,
        fillOpacity: 0,
        fill: otherSeries.get("fill"),
        draggable: true,
        cursorOverStyle: "pointer",
      });
      bulletCircle.events.on("dragged", function (e) {
        handleDrag(e);
      });
      bulletCircle.events.on("dragstop", function (e) {
        //handleChange(e, otherSeries);
      });
      return am5.Bullet.new(root, {
        sprite: bulletCircle,
      });
    });

    // Drag handler
    const handleDrag = (e: any) => {
      let point = chart.plotContainer.toLocal(e.point);
      let date = xAxis.positionToValue(xAxis.coordinateToPosition(point.x));
      let value = round(
        yAxis.positionToValue(yAxis.coordinateToPosition(point.y)),
        1
      );

      let dataItem = e.target.dataItem;
      dataItem.set("valueX", date);
      dataItem.set("valueXWorking", date);
      dataItem.set("valueY", value);
      dataItem.set("valueYWorking", value);
    };

    // Set data
    const draggableData: any = [];
    draggableValues.forEach((value: any, index: number) => {
      draggableData.push({
        value: value,
        date: dates[index],
      });
    });

    const originalData: any = [];
    originalValues.forEach((value: any, index: number) => {
      originalData.push({
        value: value,
        date: dates[index],
      });
    });

    //setOriginalData(originalData);

    series.data.processor = am5.DataProcessor.new(root, {
      numericFields: ["value"],
      dateFields: ["date"],
      dateFormat: "dd/MM/yyyy",
    });

    otherSeries.data.processor = am5.DataProcessor.new(root, {
      numericFields: ["value"],
      dateFields: ["date"],
      dateFormat: "dd/MM/yyyy",
    });

    otherSeries.data.setAll(draggableData);
    series.data.setAll(originalData);

    return () => {
      root.dispose();
    };
  }, []);

我称之为图表的部分:

  return (
      <Dialog open={true} onClose={handleCloseDialog} maxWidth={dialogMaxWidth}>
        <Box
          sx={{
            display: "flex",
            flexDirection: "column",
            backgroundColor: "grey.200",
            minWidth: 500,
          }}
        >
          <Box
            sx={{
              display: "inline-flex",
              alignItems: "center",
              px: 2.5,
              py: 2.5,
            }}
          >
            <Box
              sx={{
                display: "inline-flex",
                flexDirection: "column",
                backgroundColor: "white",
                width: "100%",
                boxShadow: 1,
                borderRadius: "6px",
                p: 3,
              }}
            >
           <Box id={id} sx={{ width: "326px", height: "300px" }}></Box>
            </Box>
          </Box>
        </Box>
      </Dialog>
  );

如果我在图表位于图表之外的位置调用此函数,它将完美地工作:

return (
<>
      <Box id={id} sx={{ width: "326px", height: "300px" }}></Box>
      <Dialog open={true} onClose={handleCloseDialog} maxWidth={dialogMaxWidth}>
        <Box
          sx={{
            display: "flex",
            flexDirection: "column",
            backgroundColor: "grey.200",
            minWidth: 500,
          }}
        >
          <Box
            sx={{
              display: "inline-flex",
              alignItems: "center",
              px: 2.5,
              py: 2.5,
            }}
          >
            <Box
              sx={{
                display: "inline-flex",
                flexDirection: "column",
                backgroundColor: "white",
                width: "100%",
                boxShadow: 1,
                borderRadius: "6px",
                p: 3,
              }}
            >
            </Box>
          </Box>
        </Box>
      </Dialog>
    </>
  );

推荐答案

要解决这个问题,您需要确保仅在Dialog打开并挂载元素之后才创建amChart 5实例.您可以使用ref而不是id来访问元素,并使用Dialog组件的onEntered属性来触发创建图表的回调函数.

例如:

const chartRef = useRef(null);
const chartInstanceRef = useRef(null);
useEffect(() => {
  return () => {
    if (chartInstanceRef.current) {
      chartInstanceRef.current.dispose();
    }
  };
}, []);

const handleEntered = () => {
  const element = chartRef.current;
  const root = am5.Root.new(element);

  /* define chart */

  chartInstanceRef.current = root;
};

return (
  <Dialog
    open={open}
    onClose={onClose}
    onEntered={handleEntered}
    maxWidth={dialogMaxWidth}
  >
    <div ref={chartRef} style={{ width: "100%", height: "500px" }}></div>
  </Dialog>
);

Typescript相关问答推荐

net::BER_RECTION_REUSED和Uncatch使用Axios和TanStack-Query useMutation时未捕获错误(DelivercMutation)

您可以创建一个类型来表示打字员吗

在Angular中,如何在文件上传后清除文件上传文本框

Webpack说你可能需要在Reactjs项目中增加一个加载器''

有没有办法解决相互影响的路由之间的合并?

在另一个类型的函数中,编译器不会推断模板文字类型

有什么方法可以类型安全地包装import()函数吗?

对于始终仅在不是对象属性时才抛出的函数,返回Never

将带点的对象键重新映射为具有保留值类型的嵌套对象

TypeScrip中的类型安全包装类

vue-tsc失败,错误引用项目可能无法禁用vue项目上的emit

Typescript 类型守卫一个类泛型?

如何从对象或类动态生成类型

如何键入派生类的实例方法,以便它调用另一个实例方法?

可赋值给类型的类型,从不赋值

作为参数的KeyOf变量的类型

使用RXJS获取数据的3种不同REST API

为什么看起来相似的代码在打字时会产生不同的错误?

仅当定义了值时才按值筛选数组

为什么类方法参数可以比接口参数窄