From 8d2c377b689b083d31bfdcd5c397ee838dded10b Mon Sep 17 00:00:00 2001 From: iven Date: Fri, 22 May 2026 08:20:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(miniprogram):=20TrendChart=20Canvas=20?= =?UTF-8?q?=E9=80=82=E8=80=81=E5=8C=96=20=E2=80=94=20useCanvasTokens=20+?= =?UTF-8?q?=20=E6=96=9C=E7=BA=BF=E7=BA=B9=E7=90=86=20+=20tooltip=20?= =?UTF-8?q?=E5=B8=B8=E9=A9=BB=20(U2-1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 替换所有硬编码字号/颜色为 useCanvasTokens 动态 token - 关怀模式 Y/X 轴字号 14px,异常点半径 8px,正常点半径 5px - 参考区间带增加斜线纹理增强区分度(关怀模式) - 关怀模式 tooltip 默认显示最后一个数据点(常驻) - tooltip SCSS 适老:padding 12/16px,min-height 44px --- .../src/components/TrendChart/index.scss | 12 ++++ .../src/components/TrendChart/index.tsx | 58 +++++++++++++++---- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/apps/miniprogram/src/components/TrendChart/index.scss b/apps/miniprogram/src/components/TrendChart/index.scss index 8fa4a72..f0ceaa9 100644 --- a/apps/miniprogram/src/components/TrendChart/index.scss +++ b/apps/miniprogram/src/components/TrendChart/index.scss @@ -57,9 +57,21 @@ white-space: nowrap; pointer-events: none; z-index: 10; + + .elder-mode & { + padding: 12px 16px; + border-radius: 8px; + min-height: 44px; + display: flex; + align-items: center; + } } .trend-tooltip-text { font-size: 12px; color: #fff; + + .elder-mode & { + font-size: var(--tk-font-body-sm); + } } diff --git a/apps/miniprogram/src/components/TrendChart/index.tsx b/apps/miniprogram/src/components/TrendChart/index.tsx index 3e4435a..1f6dd99 100644 --- a/apps/miniprogram/src/components/TrendChart/index.tsx +++ b/apps/miniprogram/src/components/TrendChart/index.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useCallback, useState } from 'react'; import { Canvas, View, Text } from '@tarojs/components'; import Taro from '@tarojs/taro'; +import { useCanvasTokens } from '@/hooks/useCanvasTokens'; import './index.scss'; /** Canvas 2D 上下文类型 — 微信小程序 Canvas 2d 接口 */ @@ -44,9 +45,28 @@ export default React.memo(function TrendChart({ unit = '', height = 500, }: TrendChartProps) { + const tokens = useCanvasTokens(); const canvasRef = useRef(null); const [tooltip, setTooltip] = useState<{ date: string; value: number; x: number } | null>(null); + // 关怀模式默认显示最后一个数据点 tooltip + useEffect(() => { + if (tokens.yLabelFontSize >= 14 && data && data.length > 0 && canvasRef.current) { + const dpr = getDPR(); + const w = canvasRef.current.width / dpr; + const pad = { left: 45, right: 15 }; + const cw = w - pad.left - pad.right; + const lastIdx = data.length - 1; + setTooltip({ + date: data[lastIdx].date, + value: data[lastIdx].value, + x: pad.left + (lastIdx / Math.max(data.length - 1, 1)) * cw, + }); + } else if (tokens.yLabelFontSize < 14) { + setTooltip(null); + } + }, [data, tokens.yLabelFontSize]); + const draw = useCallback(() => { const node = canvasRef.current; if (!node || !data || data.length === 0) return; @@ -82,12 +102,29 @@ export default React.memo(function TrendChart({ if (referenceMin != null && referenceMax != null) { const ry1 = toY(referenceMax); const ry2 = toY(referenceMin); - ctx.fillStyle = 'rgba(5,150,105,0.08)'; + ctx.fillStyle = tokens.referenceBandColor; ctx.fillRect(pad.left, ry1, cw, ry2 - ry1); + + // 关怀模式增加斜线纹理增强区分度 + if (tokens.yLabelFontSize >= 14) { + ctx.save(); + ctx.strokeStyle = 'rgba(5,150,105,0.18)'; + ctx.lineWidth = 1; + const step = 8; + ctx.beginPath(); + for (let x = pad.left; x < pad.left + cw; x += step) { + const x1 = Math.min(x, pad.left + cw); + const x2 = Math.min(x + (ry2 - ry1), pad.left + cw); + ctx.moveTo(x1, ry2); + ctx.lineTo(x2, ry1); + } + ctx.stroke(); + ctx.restore(); + } } // Grid lines - ctx.strokeStyle = '#F3F4F6'; + ctx.strokeStyle = tokens.gridColor; ctx.lineWidth = 1; const gridLines = 4; for (let i = 0; i <= gridLines; i++) { @@ -99,8 +136,8 @@ export default React.memo(function TrendChart({ } // Y-axis labels - ctx.fillStyle = '#94A3B8'; - ctx.font = '10px sans-serif'; + ctx.fillStyle = tokens.tx2; + ctx.font = `${tokens.yLabelFontSize}px sans-serif`; ctx.textAlign = 'right'; for (let i = 0; i <= gridLines; i++) { const val = yMax - (yTotal / gridLines) * i; @@ -109,6 +146,7 @@ export default React.memo(function TrendChart({ } // X-axis labels + ctx.font = `${tokens.xLabelFontSize}px sans-serif`; ctx.textAlign = 'center'; const step = Math.max(1, Math.floor(data.length / 5)); for (let i = 0; i < data.length; i += step) { @@ -130,13 +168,13 @@ export default React.memo(function TrendChart({ ctx.lineTo(chartPoints[chartPoints.length - 1].x, toY(yMin)); ctx.closePath(); const grad = ctx.createLinearGradient(0, pad.top, 0, pad.top + ch); - grad.addColorStop(0, 'rgba(8,145,178,0.15)'); - grad.addColorStop(1, 'rgba(8,145,178,0.01)'); + grad.addColorStop(0, tokens.areaGradientStart); + grad.addColorStop(1, tokens.areaGradientEnd); ctx.fillStyle = grad; ctx.fill(); // Line - ctx.strokeStyle = '#0891B2'; + ctx.strokeStyle = tokens.lineColor; ctx.lineWidth = 2; drawLine(ctx, chartPoints); @@ -147,13 +185,13 @@ export default React.memo(function TrendChart({ (referenceMin != null && d.value < referenceMin) || (referenceMax != null && d.value > referenceMax); ctx.beginPath(); - ctx.arc(chartPoints[i].x, chartPoints[i].y, isAbnormal ? 5 : 3, 0, Math.PI * 2); - ctx.fillStyle = isAbnormal ? '#DC2626' : '#0891B2'; + ctx.arc(chartPoints[i].x, chartPoints[i].y, isAbnormal ? tokens.pointAbnormalRadius : tokens.pointNormalRadius, 0, Math.PI * 2); + ctx.fillStyle = isAbnormal ? tokens.abnormalColor : tokens.lineColor; ctx.fill(); } ctx.restore(); - }, [data, referenceMin, referenceMax]); + }, [data, referenceMin, referenceMax, tokens]); const handleTouchStart = useCallback((e: any) => { if (!data || data.length === 0 || !canvasRef.current) return;