import { useEffect, useState } from 'react' import { Canvas, View, Text } from '@tarojs/components' import Taro from '@tarojs/taro' const V_PADDING = 8 const HEIGHT = 110 interface Props { points: number[] canvasId?: string } export function VitalWave({ points, canvasId = 'vitalWave' }: Props) { const [width, setWidth] = useState(200) const empty = !points || points.length < 2 // 测量容器宽度 useEffect(() => { const query = Taro.createSelectorQuery() query.select(`#${canvasId}-wrap`).boundingClientRect((rect: any) => { if (rect && rect.width > 0) { setWidth(Math.floor(rect.width)) } }).exec() }, [canvasId]) // 数据变化重绘 useEffect(() => { if (empty || width <= 0) return drawWave(canvasId, width, HEIGHT, points) }, [points, width, empty, canvasId]) return ( {!empty && ( <> )} {empty && ( 暂无数据 )} ) } function drawWave(canvasId: string, w: number, h: number, pts: number[]) { const ctx = Taro.createCanvasContext(canvasId) const min = Math.min(...pts) const max = Math.max(...pts) const span = max - min || 1 const xAt = (i: number) => (pts.length <= 1 ? 0 : (i / (pts.length - 1)) * w) const yAt = (v: number) => h - V_PADDING - ((v - min) / span) * (h - V_PADDING * 2) const pathTo = (closeBottom: boolean) => { ctx.beginPath() ctx.moveTo(xAt(0), yAt(pts[0])) for (let i = 0; i < pts.length - 1; i++) { const x0 = xAt(Math.max(0, i - 1)) const y0 = yAt(pts[Math.max(0, i - 1)]) const x1 = xAt(i) const y1 = yAt(pts[i]) const x2 = xAt(i + 1) const y2 = yAt(pts[i + 1]) const x3 = xAt(Math.min(pts.length - 1, i + 2)) const y3 = yAt(pts[Math.min(pts.length - 1, i + 2)]) const c1x = x1 + (x2 - x0) / 6 const c1y = y1 + (y2 - y0) / 6 const c2x = x2 - (x3 - x1) / 6 const c2y = y2 - (y3 - y1) / 6 ctx.bezierCurveTo(c1x, c1y, c2x, c2y, x2, y2) } if (closeBottom) { ctx.lineTo(w, h) ctx.lineTo(0, h) ctx.closePath() } } pathTo(true) const grad = ctx.createLinearGradient(0, 0, 0, h) grad.addColorStop(0, 'rgba(245, 34, 45, 0.25)') grad.addColorStop(1, 'rgba(245, 34, 45, 0)') ctx.setFillStyle(grad) ctx.fill() pathTo(false) ctx.setStrokeStyle('#f5222d') ctx.setLineWidth(2) ctx.stroke() ctx.draw() }