import { MainColorType } from "@/context/themes/color"; import { rpxToPx } from "@/utils/tools"; import { Canvas } from "@tarojs/components"; import Taro, { useReady } from "@tarojs/taro"; import { useEffect, useRef, useState } from "react"; export default function RingProgress(props: { canvasId?: string; bgRing: any; target?: any; real?: any; scale?: number; radius: number; width?: number; height?: number; extra?: any; count?: number; shareBg?: any; shareCover?: any; isCompleted?: boolean; }) { const canvasId = props.canvasId ?? new Date().getTime() + '' const info = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync() const dpr = info.pixelRatio; // 获取设备的像素比 const [ctx, setCtx] = useState(null) const [canvas, setCanvas] = useState(null) const canvasRef = useRef(null); const canvasWidth = props.width ?? rpxToPx(900) const canvasHeight = props.height ?? rpxToPx(720) const scale = props.scale ?? 1 useEffect(() => { if (ctx) { drawContent(ctx, canvas) } else { initCanvas() } }, [props.canvasId, props.count]) useReady(() => { initCanvas() }) var retryCount = 0; function initCanvas() { const query = Taro.createSelectorQuery(); query.select(`#${canvasId}`).fields({ node: true, size: true }); query.exec((res) => { if (res[0] == null) { retryCount++; if (retryCount > 5) { return; } initCanvas() return } const _canvas = res[0].node; _canvas.width = res[0].width * dpr; _canvas.height = res[0].height * dpr; const ctx = _canvas.getContext('2d'); ctx.scale(dpr, dpr) ctx.translate(0, 0) ctx.scale(scale, scale); ctx.translate(0, 0); drawContent(ctx, _canvas) setCtx(ctx) setCanvas(_canvas) }) } function drawContent(ctx, _canvas) { ctx.clearRect(0, 0, canvasWidth, canvasHeight); // 清除画布 // 设置画布尺寸 if (props.shareBg) { if (props.shareBg.length == 1) { ctx.fillStyle = props.shareBg[0]; ctx.fillRect(0, 0, canvasWidth, canvasHeight) } else { const grd = ctx.createLinearGradient(0, 0, 0, canvasHeight); grd.addColorStop(0, props.shareBg[0]) grd.addColorStop(1, props.shareBg[1]) ctx.fillStyle = grd; ctx.fillRect(0, 0, canvasWidth, canvasHeight) } } ctx.beginPath(); ctx.arc(canvasWidth / 2.0, canvasHeight / 2.0, props.radius, 0, 2 * Math.PI); ctx.lineWidth = props.bgRing.width; ctx.strokeStyle = props.bgRing.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); if (props.target) { ctx.beginPath(); ctx.arc(canvasWidth / 2.0, canvasHeight / 2.0, props.radius, props.target.start, props.target.start + Math.max(props.target.duration, 0.01)); ctx.lineWidth = props.target.width; ctx.strokeStyle = props.target.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); } if (props.real) { if (props.isCompleted) { ctx.beginPath(); ctx.arc(canvasWidth / 2.0, canvasHeight / 2.0, props.radius, 0, Math.PI*2); ctx.lineWidth = rpxToPx(4); ctx.strokeStyle = 'rgba(0,0,0,0.05)'; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); } ctx.beginPath(); ctx.arc(canvasWidth / 2.0, canvasHeight / 2.0, props.radius, props.real.start, props.real.start + Math.max(props.real.duration, 0.01)); ctx.lineWidth = props.real.width; ctx.strokeStyle = props.real.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); } // ctx.beginPath() // ctx.arc(100, 100, 30, 0, 2 * Math.PI, false); // ctx.clip(); // ctx.beginPath(); // ctx.arc(100, 100, 30, 0, 2 * Math.PI, true); // ctx.fill(); // 设置混合模式为擦除 // ctx.globalCompositeOperation = 'destination-out' // // 绘制透明环 // ctx.beginPath() // ctx.arc(100, 100, 50, 0, 2 * Math.PI) // ctx.lineWidth = 10 // ctx.stroke() // // 重置混合模式 // ctx.globalCompositeOperation = 'source-over' if (!props.isCompleted) { var time = new Date(); var seconds = time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds(); // seconds += props.currentDot.offset! * 60 if (seconds > 24 * 3600) { seconds -= 24 * 3600 } else if (seconds < 0) { seconds += 24 * 3600 } var arc = seconds / 86400 * 2 * Math.PI - Math.PI / 2.0; const radians = arc;//angle * Math.PI / 180; // 将角度转换为弧度 const xPrime = canvasWidth / 2.0 + props.radius * Math.cos(radians); const yPrime = canvasHeight / 2.0 + props.radius * Math.sin(radians); ctx.globalCompositeOperation = 'destination-out' ctx.beginPath(); var dotLineWidth = 4 // if (lineWidth == 28) { // dotLineWidth = 4 // } ctx.arc(xPrime, yPrime, props.target.width / 2.0, 0, 2 * Math.PI); ctx.lineWidth = dotLineWidth; ctx.fillStyle = 'transparent' ctx.fill() ctx.strokeStyle = '#1C1C1C'; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); ctx.globalCompositeOperation = 'source-over' } if (props.extra) { const { goal, target, progress, value, footer, color, result } = props.extra // if (header) { // ctx.font = `bold ${12}px sans-serif` // ctx.fillStyle = '#000' // ctx.textAlign = 'center' // ctx.fillText(header, rpxToPx(450), rpxToPx(350)); // } if (target) { ctx.font = `bold ${rpxToPx(50)}px sans-serif` ctx.fillStyle = '#000' ctx.textAlign = 'center' ctx.textBaseline = 'top'; ctx.fillText(target, rpxToPx(450), rpxToPx(324)); } if (progress) { ctx.font = `bold ${rpxToPx(72)}px sans-serif` ctx.fillStyle = '#000' ctx.textAlign = 'center' ctx.textBaseline = 'top'; ctx.fillText(progress, rpxToPx(450), rpxToPx(314)); } if (goal) { ctx.font = `bold ${rpxToPx(30)}px sans-serif` ctx.fillStyle = MainColorType.orange ctx.textAlign = 'center' ctx.textBaseline = 'top'; ctx.fillText(goal, rpxToPx(450), rpxToPx(416)); } if (footer) { ctx.font = `bold ${rpxToPx(24)}px sans-serif` ctx.fillStyle = 'rgba(0,0,0,0.5)' ctx.textAlign = 'center' ctx.textBaseline = 'top'; ctx.fillText(footer, rpxToPx(450), rpxToPx(420)); } if (result) { ctx.font = `bold ${rpxToPx(44)}px sans-serif` ctx.fillStyle = '#fff' ctx.textAlign = 'center' ctx.textBaseline = 'top'; ctx.fillText(result, rpxToPx(450), rpxToPx(414)); } } if (props.isCompleted) { if (_canvas) { const img1 = _canvas.createImage(); // 创建图像对象 img1.src = global.checkImg img1.onload = () => { ctx.drawImage(img1, 162, 30, rpxToPx(400), rpxToPx(340)); ctx.stroke(); if (props.shareCover && _canvas) { save(_canvas) } } } } else { if (props.shareCover && _canvas) { save(_canvas) } } } function save(_canvas) { Taro.canvasToTempFilePath({ canvas: _canvas, success: (res) => { console.log('图片保存成功:', res.tempFilePath); props.shareCover(res.tempFilePath) }, fail: (err) => { console.error('转为图片失败:', err); } }); } return }