Răsfoiți Sursa

♻️ refactor(charts): 重构 BaseChartOriginal2D 组件以简化尺寸计算和生命周期

- 移除 `pixelRatio` 属性,使用 Canvas 原生尺寸
- 将 `useEffect` 和 `useReady` 合并为 `useLayoutEffect`,简化初始化逻辑
- 移除数据变化时的重绘逻辑,依赖 `useLayoutEffect` 的依赖项自动更新
- 将默认宽度和高度设为固定值(750 和 500)
- 使用 `useState` 管理动态计算的 `cWidth` 和 `cHeight`
- 将 `canvasId` 属性改为 `canvas-id` 以符合 Taro 规范
- 移除 `ColumnChartOriginal2D` 中未使用的 `pixelRatio` 属性传递
yourname 2 săptămâni în urmă
părinte
comite
cc70100afb

+ 32 - 97
mini-ui-packages/mini-charts/src/components/BaseChartOriginal2D.tsx

@@ -1,5 +1,5 @@
-import React, { useEffect, useRef, useMemo } from 'react';
-import Taro, { useReady } from '@tarojs/taro';
+import React, { useState, useRef, useLayoutEffect } from 'react';
+import Taro 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';
@@ -12,12 +12,10 @@ import type { ExtendedCanvasContext } from '../types';
 export interface BaseChartOriginal2DProps {
   /** Canvas 元素的 ID,必须唯一 */
   canvasId: string;
-  /** 图表宽度(像素),默认为屏幕宽度 */
+  /** 图表宽度(像素),默认为 750 */
   width?: number;
-  /** 图表高度(像素),默认根据宽高比计算 */
+  /** 图表高度(像素),默认为 500 */
   height?: number;
-  /** 设备像素比,默认根据环境自动设置 */
-  pixelRatio?: number;
   /** 图表类型 */
   type: ChartsConfig['type'];
   /** X 轴分类数据 */
@@ -43,9 +41,8 @@ export interface BaseChartOriginal2DProps {
 export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) => {
   const {
     canvasId,
-    width,
-    height,
-    pixelRatio,
+    width = 750,
+    height = 500,
     type,
     categories = [],
     series = [],
@@ -55,37 +52,29 @@ export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) =
     onTouchEnd,
   } = props;
 
+  const [cWidth, setCWidth] = useState(750);
+  const [cHeight, setCHeight] = useState(500);
+
   const chartRef = useRef<any>(null);
 
   /**
-   * 计算响应式尺寸和像素比
+   * 初始化图表实例
+   * 使用 Canvas 2D API + 原始 u-charts.js
+   * 参考 ColumnChartFCExample 的实现方式
    */
-  const { cWidth, cHeight, actualPixelRatio } = useMemo(() => {
+  useLayoutEffect(() => {
+    console.debug('[BaseChartOriginal2D] useLayoutEffect 开始', { canvasId, width, height });
+
+    // 计算响应式尺寸
     const sysInfo = Taro.getSystemInfoSync();
-    const pr = pixelRatio ?? sysInfo.pixelRatio;
-    // width 和 height 是逻辑像素(CSS 像素)
-    const cw = width ?? (750 / 750 * sysInfo.windowWidth);
-    const ch = height ?? (500 / 750 * cw);
-    return { cWidth: cw, cHeight: ch, actualPixelRatio: pr };
-  }, [width, height, pixelRatio]);
+    // 这里的第一个 750 对应 css .charts 的 width
+    const cw = width / 750 * sysInfo.windowWidth;
+    // 这里的 500 对应 css .charts 的 height
+    const ch = height / 750 * sysInfo.windowWidth;
 
-  /**
-   * Canvas props - Canvas 2D API
-   * - width/height 属性:实际像素尺寸(逻辑像素 * pixelRatio)
-   * - style.width/style.height:CSS 显示尺寸(逻辑像素)
-   */
-  const canvasProps = useMemo(() => ({
-    width: String(cWidth * actualPixelRatio),
-    height: String(cHeight * actualPixelRatio),
-    style: { width: `${cWidth}px`, height: `${cHeight}px` }
-  }), [cWidth, cHeight, actualPixelRatio]);
+    setCWidth(cw);
+    setCHeight(ch);
 
-  /**
-   * 初始化图表实例
-   * 使用 Canvas 2D API + 原始 u-charts.js
-   * 只在数据准备好后才初始化(参考官方示例)
-   */
-  useReady(() => {
     // 确保数据已准备好:categories 和 series 都有数据
     const isDataReady = categories.length > 0 && series.length > 0;
 
@@ -105,22 +94,20 @@ export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) =
         const canvas = res[0].node;
         const ctx = canvas.getContext('2d');
 
-        // 设置 canvas 的实际像素尺寸
-        canvas.width = res[0].width * actualPixelRatio;
-        canvas.height = res[0].height * actualPixelRatio;
+        console.debug('[BaseChartOriginal2D] canvas.width', canvas.width);
+        console.debug('[BaseChartOriginal2D] canvas.height', canvas.height);
 
         // 将 Taro CanvasContext 转换为 uCharts 需要的 CanvasContext
         const extendedCtx = ctx as ExtendedCanvasContext;
 
-        // Canvas 2D: 传入 uCharts 的 width/height 需要乘以 pixelRatio
+        // Canvas 2D: 使用 canvas 的实际 width/height
         const chartConfig: ChartsConfig = {
           type,
           context: extendedCtx,
           categories,
           series,
-          width: cWidth * actualPixelRatio,
-          height: cHeight * actualPixelRatio,
-          pixelRatio: actualPixelRatio,
+          width: canvas.width,
+          height: canvas.height,
           animation: true,
           background: '#FFFFFF',
           color: ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', '#ef4444'],
@@ -146,7 +133,7 @@ export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) =
 
         chartRef.current = new uChartsClass(chartConfig);
         console.log('[BaseChartOriginal2D] 图表初始化完成:', canvasId, {
-          cWidth, cHeight, actualPixelRatio,
+          cWidth, cHeight,
           canvasWidth: canvas.width,
           canvasHeight: canvas.height,
           categoriesLength: categories.length,
@@ -156,61 +143,7 @@ export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) =
         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]);
+  }, [canvasId, width, height, categories, series, config]);
 
   /**
    * 触摸事件处理
@@ -238,9 +171,11 @@ export const BaseChartOriginal2D: React.FC<BaseChartOriginal2DProps> = (props) =
     onTouchEnd?.(e as TouchEvent);
   };
 
+  const canvasProps = { style: { width: cWidth, height: cHeight } };
+
   return (
     <Canvas
-      canvasId={canvasId}
+      canvas-id={canvasId}
       id={canvasId}
       {...canvasProps}
       onTouchStart={handleTouchStart}

+ 0 - 4
mini-ui-packages/mini-charts/src/components/ColumnChartOriginal2D.tsx

@@ -13,8 +13,6 @@ export interface ColumnChartOriginal2DProps {
   width?: number;
   /** 图表高度(像素) */
   height?: number;
-  /** 设备像素比 */
-  pixelRatio?: number;
   /** X 轴分类数据 */
   categories: string[];
   /** 系列数据 */
@@ -36,7 +34,6 @@ export const ColumnChartOriginal2D: React.FC<ColumnChartOriginal2DProps> = (prop
     canvasId,
     width,
     height,
-    pixelRatio,
     categories,
     series,
     config = {},
@@ -78,7 +75,6 @@ export const ColumnChartOriginal2D: React.FC<ColumnChartOriginal2DProps> = (prop
       canvasId={canvasId}
       width={width}
       height={height}
-      pixelRatio={pixelRatio}
       type="column"
       categories={categories}
       series={series}