You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React/TypeScript中让amCharts气泡图网格自适应为正方形

React/TypeScript 实现 AmCharts 气泡图响应式正方形网格(无需固定容器宽高)

当然可以实现,核心是通过动态计算可用空间结合 AmCharts 的响应式配置,同时兼顾坐标轴标签的占用,以下是具体实现方案:

核心思路

不固定容器的宽高,让它自适应父元素;通过监听窗口 resize 事件,实时计算扣除坐标轴标签后的可用宽/高,取两者中的较小值作为正方形网格的边长,再同步给图表实例。

具体实现步骤

1. 组件基础结构

先搭建 React 组件的基本框架,容器不设固定宽高,让它占满父容器的可用空间:

import React, { useEffect, useRef } from 'react';
import * as am4core from "@amcharts/amcharts4/core";
import * as am4charts from "@amcharts/amcharts4/charts";

const SquareBubbleChart = () => {
  const chartRef = useRef<HTMLDivElement>(null);
  const chartInstanceRef = useRef<am4charts.BubbleChart | null>(null);

  // 后续逻辑写在这里

  return <div ref={chartRef} style={{ width: "100%", height: "100%" }}></div>;
};

export default SquareBubbleChart;

2. 初始化图表并配置响应式

初始化气泡图时,开启响应式配置,同时预留坐标轴标签的空间计算逻辑:

useEffect(() => {
  if (!chartRef.current) return;

  // 创建图表实例
  const chart = am4core.create(chartRef.current, am4charts.BubbleChart);
  
  // 示例数据源
  chart.data = [
    { category: "分类A", value: 120, size: 25 },
    { category: "分类B", value: 180, size: 35 },
    { category: "分类C", value: 90, size: 18 },
    { category: "分类D", value: 210, size: 40 },
  ];

  // 配置X轴
  const xAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  xAxis.dataFields.category = "category";
  xAxis.renderer.grid.template.disabled = false;
  // 长标签自动换行,避免占用过多空间
  xAxis.renderer.labels.template.wrap = true;
  xAxis.renderer.labels.template.maxWidth = 80;

  // 配置Y轴
  const yAxis = chart.yAxes.push(new am4charts.ValueAxis());
  yAxis.renderer.grid.template.disabled = false;

  // 配置气泡系列
  const series = chart.series.push(new am4charts.BubbleSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "category";
  series.dataFields.value = "size";
  series.tooltipText = "{categoryX}: {valueY} (尺寸: {size})";

  // 开启响应式
  chart.responsive.enabled = true;

  chartInstanceRef.current = chart;

  // 组件卸载时销毁图表,避免内存泄漏
  return () => {
    chart.dispose();
    chartInstanceRef.current = null;
  };
}, []);

3. 监听窗口 resize 并调整网格尺寸

添加防抖的 resize 事件监听,实时计算可用空间并设置正方形网格:

useEffect(() => {
  const handleResize = () => {
    const chart = chartInstanceRef.current;
    if (!chart || !chartRef.current) return;

    // 获取容器当前的宽高
    const containerRect = chartRef.current.getBoundingClientRect();
    // 计算坐标轴标签占用的额外空间(可根据实际显示效果调整)
    const yAxisLabelWidth = chart.yAxes.getIndex(0).renderer.labelWidth + 20;
    const xAxisLabelHeight = chart.xAxes.getIndex(0).renderer.labelHeight + 20;

    // 扣除标签占用后,取宽高中的较小值作为正方形边长
    const availableWidth = containerRect.width - yAxisLabelWidth;
    const availableHeight = containerRect.height - xAxisLabelHeight;
    const squareSize = Math.min(availableWidth, availableHeight);

    // 设置绘图区域为正方形
    chart.plotContainer.width = squareSize;
    chart.plotContainer.height = squareSize;

    // 触发图表重绘
    chart.invalidate();
  };

  // 初始化时执行一次,确保首次加载就是正方形
  handleResize();

  // 防抖处理,避免窗口 resize 时频繁重绘
  const debouncedResize = debounce(handleResize, 200);
  window.addEventListener("resize", debouncedResize);

  return () => {
    window.removeEventListener("resize", debouncedResize);
  };
}, []);

// 防抖工具函数
const debounce = (func: (...args: any[]) => void, delay: number) => {
  let timeoutId: NodeJS.Timeout;
  return (...args: any[]) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func(...args), delay);
  };
};

4. 关键注意事项

  • 防抖处理:resize 事件触发频率极高,必须加防抖避免图表频繁重绘导致性能问题。
  • 标签适配:如果坐标轴标签过长,一定要开启自动换行或限制宽度,否则会导致空间计算偏差。
  • 父容器限制:确保图表的父容器没有固定宽高,让图表容器能自由拉伸,才能实现真正的响应式。

内容的提问来源于stack exchange,提问作者tallman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 11:40:37