Browse Source

♻️ refactor(charts): 重构 Canvas 上下文类型系统以提升跨平台兼容性

- 将 CanvasContext 接口定义移至共享类型文件 (types.ts)
- 引入 ExtendedCanvasContext 类型,扩展 Taro CanvasContext 并添加 uCharts 所需属性
- 在 BaseChart 组件中使用 ExtendedCanvasContext 类型,简化上下文转换逻辑
- 在 u-charts.ts 中导入并使用共享的 CanvasContext 类型定义
- 在 draw-charts.ts 中移除所有 context.clearRect?() 的可选链调用,因为 clearRect 方法现在被确保存在
- 为 Canvas 组件添加 type="2d" 属性以明确渲染模式
- 将 canvas-id 属性更新为 canvasId 以遵循 Taro 3.x 规范
yourname 3 tuần trước cách đây
mục cha
commit
8cf8a2cb18

+ 9 - 9
mini-ui-packages/mini-charts/src/components/BaseChart.tsx

@@ -2,7 +2,8 @@ import React, { useEffect, useRef, useMemo } from 'react';
 import Taro from '@tarojs/taro';
 import { Canvas } from '@tarojs/components';
 import { uCharts } from '../lib/charts/index';
-import type { ChartsConfig, CanvasContext, TouchEvent, LegendConfig, XAxisConfig, YAxisConfig } from '../lib/charts/index';
+import type { ChartsConfig, TouchEvent } from '../lib/charts/index';
+import type { ExtendedCanvasContext } from '../types';
 
 /**
  * BaseChart 组件的 Props 接口
@@ -105,13 +106,11 @@ export const BaseChart: React.FC<BaseChartProps> = (props) => {
       }
 
       // 将 Taro CanvasContext 转换为 uCharts 需要的 CanvasContext
-      // Taro 的 CanvasContext 有一个 __raw__ 属性包含真正的 CanvasRenderingContext2D
-      const rawContext = (rawCtx as any).__raw__ || rawCtx;
-      const ctx: CanvasContext = {
-        width: cWidth,
-        height: cHeight,
-        ...rawContext
-      };
+      // 注意:不能使用展开运算符,因为这会复制方法但丢失 this 指向
+      const ctx = rawCtx as ExtendedCanvasContext;
+      // 添加 uCharts 需要的 width 和 height 属性
+      ctx.width = cWidth;
+      ctx.height = cHeight;
       console.debug('[BaseChart] 转换后的CanvasContext:', ctx)
 
       const chartConfig: ChartsConfig = {
@@ -161,12 +160,13 @@ export const BaseChart: React.FC<BaseChartProps> = (props) => {
 
   return (
     <Canvas
-      canvas-id={canvasId}
+      canvasId={canvasId}
       id={canvasId}
       {...canvasProps}
       onTouchStart={handleTouchStart}
       onTouchMove={handleTouchMove}
       onTouchEnd={handleTouchEnd}
+      type="2d"
     />
   );
 };

+ 2 - 48
mini-ui-packages/mini-charts/src/lib/charts/u-charts.ts

@@ -98,55 +98,9 @@ const getTouches = getTouchesUtil;
 
 /**
  * Canvas 上下文接口
- * 兼容小程序和 H5 环境
+ * 使用 ExtendedCanvasContext,兼容 Taro 跨平台环境
  */
-export interface CanvasContext {
-  width: number;
-  height: number;
-  padding?: number[];
-  // 标准 Canvas 2D API
-  strokeStyle?: string;
-  lineWidth?: number;
-  lineCap?: string;
-  font?: string;
-  fillStyle?: string;
-  textAlign?: string;
-  textBaseline?: string;
-  shadowColor?: string;
-  shadowOffsetX?: number;
-  shadowOffsetY?: number;
-  shadowBlur?: number;
-  // 兼容小程序的方法
-  setStrokeStyle?(style: string): void;
-  setLineWidth?(width: number): void;
-  setLineCap?(cap: string): void;
-  setFontSize?(size: number): void;
-  setFillStyle?(style: string): void;
-  setTextAlign?(align: string): void;
-  setTextBaseline?(baseline: string): void;
-  setShadow?(offsetX: number, offsetY: number, blur: number, color: string): void;
-  setLineDash?(segments: number[]): void;
-  draw?(): void;
-  // clearRect 方法(Taro 小程序可能不支持,使用可选)
-  clearRect?(x: number, y: number, width: number, height: number): void;
-  // save/restore 方法(Taro 小程序可能不支持,使用可选)
-  save?(): void;
-  restore?(): void;
-  // 其他常用 Canvas 方法(使用可选以兼容不同平台)
-  beginPath?(): void;
-  closePath?(): void;
-  moveTo?(x: number, y: number): void;
-  lineTo?(x: number, y: number): void;
-  arc?(x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean): void;
-  rect?(x: number, y: number, width: number, height: number): void;
-  fill?(): void;
-  stroke?(): void;
-  fillText?(text: string, x: number, y: number, maxWidth?: number): void;
-  translate?(x: number, y: number): void;
-  rotate?(angle: number): void;
-  scale?(x: number, y: number): void;
-  [key: string]: any;
-}
+export type CanvasContext = import('../../types').ExtendedCanvasContext;
 
 /**
  * 图表标题配置

+ 18 - 18
mini-ui-packages/mini-charts/src/lib/draw-controllers/draw-charts.ts

@@ -296,7 +296,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -309,7 +309,7 @@ export const drawCharts: DrawChartsFunction = function(
       });
       break;
     case 'map':
-      context.clearRect?.(0, 0, opts.width, opts.height);
+      context.clearRect(0, 0, opts.width, opts.height);
       drawMapDataPoints(series, opts, config, context);
       setTimeout(() => {
         _this.uevent.trigger('renderComplete');
@@ -320,7 +320,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -339,7 +339,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -370,7 +370,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -401,7 +401,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -432,7 +432,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -463,7 +463,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -494,7 +494,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -525,7 +525,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -556,7 +556,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -587,7 +587,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -606,7 +606,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -625,7 +625,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -644,7 +644,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -663,7 +663,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -680,7 +680,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }
@@ -697,7 +697,7 @@ export const drawCharts: DrawChartsFunction = function(
         timing: opts.timing,
         duration: duration,
         onProcess: function onProcess(process) {
-          context.clearRect?.(0, 0, opts.width, opts.height);
+          context.clearRect(0, 0, opts.width, opts.height);
           if (opts.rotate) {
             contextRotate(context, opts);
           }

+ 18 - 0
mini-ui-packages/mini-charts/src/types.ts

@@ -0,0 +1,18 @@
+/**
+ * mini-charts 包的共享类型定义
+ */
+
+import type { CanvasContext as TaroCanvasContext } from '@tarojs/taro';
+
+/**
+ * 扩展 Taro CanvasContext,添加 uCharts 需要的属性
+ * 用于统一 BaseChart 组件和 uCharts 库的 Canvas 上下文类型
+ */
+export interface ExtendedCanvasContext extends Omit<TaroCanvasContext, 'lineCap'> {
+  width: number;
+  height: number;
+  // uCharts 需要的额外属性(Taro 只有对应的 set 方法)
+  textAlign?: CanvasTextAlign | string; // 使用 string 类型以兼容 uCharts 的用法
+  textBaseline?: CanvasTextBaseline | string; // 使用 string 类型以兼容 uCharts 的用法
+  lineCap?: CanvasLineCap | string; // 使用 string 类型以兼容 uCharts 的用法
+}