ソースを参照

♻️ refactor(charts): 重构 BaseChartOriginal2D 组件初始化逻辑

- 将图表初始化从 `useEffect` 迁移至 `useReady` 钩子,确保在小程序环境中组件就绪后再执行
- 增加数据准备检查,仅在 `categories` 和 `series` 均有数据时才进行初始化
- 新增 `useEffect` 依赖 `[categories, series, config]`,当数据变化时重新绘制图表
- 移除 `setTimeout` 延迟逻辑,改为依赖 Taro 生命周期钩子
- 优化日志输出,包含数据长度信息便于调试
yourname 2 週間 前
コミット
950bd01e7f

+ 126 - 65
mini-ui-packages/mini-charts/src/components/BaseChartOriginal2D.tsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useRef, useMemo } from 'react';
-import Taro from '@tarojs/taro';
+import Taro, { useReady } from '@tarojs/taro';
 import { Canvas } from '@tarojs/components';
 import uChartsClass from '../lib/u-charts-original.js';
 import type { ChartsConfig, TouchEvent } from '../lib/u-charts-original';
@@ -83,73 +83,134 @@ export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) =
   /**
    * 初始化图表实例
    * 使用 Canvas 2D API + 原始 u-charts.js
+   * 只在数据准备好后才初始化(参考官方示例)
    */
-  useEffect(() => {
-    // 使用 setTimeout 确保 Canvas DOM 元素已渲染完成
-    const timer = setTimeout(() => {
-      // 使用 Canvas 2D API 的方式获取 context
-      const query = Taro.createSelectorQuery();
-      query.select('#' + canvasId).fields({ node: true, size: true }).exec((res) => {
-        if (res[0]) {
-          const canvas = res[0].node;
-          const ctx = canvas.getContext('2d');
-
-          // 设置 canvas 的实际像素尺寸
-          canvas.width = res[0].width * actualPixelRatio;
-          canvas.height = res[0].height * actualPixelRatio;
-
-          // 将 Taro CanvasContext 转换为 uCharts 需要的 CanvasContext
-          const extendedCtx = ctx as ExtendedCanvasContext;
-
-          // Canvas 2D: 传入 uCharts 的 width/height 需要乘以 pixelRatio
-          const chartConfig: ChartsConfig = {
-            type,
-            context: extendedCtx,
-            categories,
-            series,
-            width: cWidth * actualPixelRatio,
-            height: cHeight * actualPixelRatio,
-            pixelRatio: actualPixelRatio,
-            animation: true,
-            background: '#FFFFFF',
-            color: ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', '#ef4444'],
-            padding: [15, 15, 0, 5],
-            enableScroll: false,
-            legend: {},
-            xAxis: {
-              disableGrid: true
-            },
-            yAxis: {
-              data: [{ min: 0 }]
-            },
-            extra: {
-              column: {
-                type: 'group',
-                width: 30,
-                activeBgColor: '#000000',
-                activeBgOpacity: 0.08
-              }
-            },
-            ...config,
-          };
-
-          chartRef.current = new uChartsClass(chartConfig);
-          console.log('[BaseChartOriginal2D] 图表初始化完成:', canvasId, {
-            cWidth, cHeight, actualPixelRatio,
-            canvasWidth: canvas.width,
-            canvasHeight: canvas.height
-          });
-        } else {
-          console.error('[BaseChartOriginal2D] 未获取到 canvas node:', canvasId);
-        }
+  useReady(() => {
+    // 确保数据已准备好:categories 和 series 都有数据
+    const isDataReady = categories.length > 0 && series.length > 0;
+
+    if (!isDataReady) {
+      console.log('[BaseChartOriginal2D] 数据未准备好,等待数据...', {
+        canvasId,
+        categoriesLength: categories.length,
+        seriesLength: series.length
       });
-    }, 100);
+      return;
+    }
 
-    return () => {
-      clearTimeout(timer);
-      chartRef.current = null;
-    };
-  }, [canvasId, type, categories, series, cWidth, cHeight, actualPixelRatio, config]);
+    // 使用 Canvas 2D API 的方式获取 context
+    const query = Taro.createSelectorQuery();
+    query.select('#' + canvasId).fields({ node: true, size: true }).exec((res) => {
+      if (res[0]) {
+        const canvas = res[0].node;
+        const ctx = canvas.getContext('2d');
+
+        // 设置 canvas 的实际像素尺寸
+        canvas.width = res[0].width * actualPixelRatio;
+        canvas.height = res[0].height * actualPixelRatio;
+
+        // 将 Taro CanvasContext 转换为 uCharts 需要的 CanvasContext
+        const extendedCtx = ctx as ExtendedCanvasContext;
+
+        // Canvas 2D: 传入 uCharts 的 width/height 需要乘以 pixelRatio
+        const chartConfig: ChartsConfig = {
+          type,
+          context: extendedCtx,
+          categories,
+          series,
+          width: cWidth * actualPixelRatio,
+          height: cHeight * actualPixelRatio,
+          pixelRatio: actualPixelRatio,
+          animation: true,
+          background: '#FFFFFF',
+          color: ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', '#ef4444'],
+          padding: [15, 15, 0, 5],
+          enableScroll: false,
+          legend: {},
+          xAxis: {
+            disableGrid: true
+          },
+          yAxis: {
+            data: [{ min: 0 }]
+          },
+          extra: {
+            column: {
+              type: 'group',
+              width: 30,
+              activeBgColor: '#000000',
+              activeBgOpacity: 0.08
+            }
+          },
+          ...config,
+        };
+
+        chartRef.current = new uChartsClass(chartConfig);
+        console.log('[BaseChartOriginal2D] 图表初始化完成:', canvasId, {
+          cWidth, cHeight, actualPixelRatio,
+          canvasWidth: canvas.width,
+          canvasHeight: canvas.height,
+          categoriesLength: categories.length,
+          seriesLength: series.length
+        });
+      } else {
+        console.error('[BaseChartOriginal2D] 未获取到 canvas node:', canvasId);
+      }
+    });
+  });
+
+  // 当数据变化时重新绘制
+  useEffect(() => {
+    if (!chartRef.current) return;
+
+    const isDataReady = categories.length > 0 && series.length > 0;
+    if (!isDataReady) return;
+
+    // 数据变化时重新绘制
+    const query = Taro.createSelectorQuery();
+    query.select('#' + canvasId).fields({ node: true, size: true }).exec((res) => {
+      if (res[0]) {
+        const canvas = res[0].node;
+        const ctx = canvas.getContext('2d');
+
+        // 清空画布
+        ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+        // 重新创建图表实例
+        const chartConfig: ChartsConfig = {
+          type,
+          context: ctx as ExtendedCanvasContext,
+          categories,
+          series,
+          width: cWidth * actualPixelRatio,
+          height: cHeight * actualPixelRatio,
+          pixelRatio: actualPixelRatio,
+          animation: true,
+          background: '#FFFFFF',
+          color: ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', '#ef4444'],
+          padding: [15, 15, 0, 5],
+          enableScroll: false,
+          legend: {},
+          xAxis: {
+            disableGrid: true
+          },
+          yAxis: {
+            data: [{ min: 0 }]
+          },
+          extra: {
+            column: {
+              type: 'group',
+              width: 30,
+              activeBgColor: '#000000',
+              activeBgOpacity: 0.08
+            }
+          },
+          ...config,
+        };
+
+        chartRef.current = new uChartsClass(chartConfig);
+      }
+    });
+  }, [categories, series, config]);
 
   /**
    * 触摸事件处理