Amcharts 5 图表在 MUI 对话框中不起作用:无法找到带有 id 的 HTML 元素

问题描述 投票:0回答:1

我正在使用 AmChart 5 的 XY 图表来显示一些数据。单击按钮时,用户可以在 MUI 对话框中看到该图表并对其进行一些操作。但是,当我想在 MUI 对话框中显示具有唯一 ID 的图表时,它会给出“无法找到具有 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)]);
    

    // 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>
    </>
  );
reactjs typescript material-ui amcharts amcharts5
1个回答
1
投票

要解决此问题,您需要确保仅在

amChart 5
打开并安装元素后创建
Dialog
实例。您可以使用
ref
而不是
id
来访问元素,并使用
onEntered
组件的
Dialog
属性来触发创建图表的回调函数。

例如:

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>
);
© www.soinside.com 2019 - 2024. All rights reserved.