import { MainColorType } from "@/context/themes/color"; import { Canvas } from "@tarojs/components"; import Taro from "@tarojs/taro"; import { useDidShow, useReady } from "@tarojs/taro"; import { useEffect, useRef, useState } from "react"; import { useSelector } from "react-redux"; import '../../../app.scss' export type RingCommon = { useCase: string; status: string; isFast?: boolean; radius: number; lineWidth: number; } export type CurrentDot = { color: string; lineWidth: number; borderColor: string; timestamp?: number; offset?: number; whiteIcon?: boolean; } export type RealRing = { color: string; startArc: number; durationArc: number; radius?: number; lineWidth?: number; hideBg?: boolean; } export type TargetRing = { color: string; startArc: number; durationArc: number; radius?: number; lineWidth?: number; } export type ScheduleRing = { color: string; startArc: number; durationArc: number; } export type BgRing = { color: string; } let arrowImg; let startTime; let dotScale = 0.8; let dotAlpha = 0.8; let direction = 1; let frameAnimation: any = null; let laterTime; export default function Rings(props: { common: RingCommon; currentDot?: CurrentDot; realRing?: RealRing; targetRing?: TargetRing; scheduleRing?: ScheduleRing; breathAnimation?: boolean; bgRing: BgRing; canvasId?: string; ctx?: any; setCtx?: any; canvas?: any; setCanvas?: any; dotList?: Array; stageList?: Array; scale?: number; showCurrentDotAnimation?: boolean; }) { const r = props.common.radius const strokeWidth = props.common.lineWidth; // const color = props.color || 'orange' const canvasRef = useRef(null); const canvasId = props.canvasId ? 'canvas_' + props.canvasId : 'progress-canvas'; const dpr = Taro.getSystemInfoSync().pixelRatio; // 获取设备的像素比 const radius = r; // 圆形进度条的半径 const lineWidth = strokeWidth; // 圆形进度条的线宽 const time = useSelector((state: any) => state.time); const user = useSelector((state: any) => state.user); const [scale, setScale] = useState(props.scale ?? 1.0) const scaleRef = useRef(1); const alphaRef = useRef(1); const directionRef = useRef(1); // 1 for scaling down, -1 for scaling up const animationFrameRef = useRef(null); const animationDuration = 150; // 动画时长(毫秒 const animateScale = (newScale) => { // const startTime = performance.now(); const animate = () => { const elapsed = new Date().getTime() - startTime.getTime(); const progress = Math.min(elapsed / animationDuration, 1); const currentScale = scale + (newScale - scale) * progress; setScale(currentScale); if (progress < 1) { requestAnimationFrame(animate); } else { setScale(newScale); } }; requestAnimationFrame(animate); }; useEffect(() => { // drawCircle() if (props.scale && props.scale != scale) { // setScale(props.scale ?? 1.0) startTime = new Date() animateScale(props.scale) } }, [props.scale]) const animate2 = () => { if (!props.showCurrentDotAnimation) { cancelAnimationFrame(animationFrameRef.current as any) animationFrameRef.current = null return; } // 更新 scale 和 alpha // scaleRef.current += directionRef.current * 0.01; // alphaRef.current += directionRef.current * 0.01; dotScale += direction * 0.005; dotAlpha += direction * 0.005; // 反转方向 if (dotScale <= 0.7 || dotScale >= 1) { direction *= -1; } // 绘制圆点 if (props.ctx) { drawContent(props.ctx) } else { drawCircle() } // 循环动画 animationFrameRef.current = requestAnimationFrame(animate2); }; useEffect(() => { // if (props.showCurrentDotAnimation) { // console.log('oooooooooooooooooooooooo') // setTimeout(() => { // console.log('sssssssssddddddd') // animate2() // }, 2000) // } // else { // if (laterTime) // clearTimeout(laterTime) // if (animationFrameRef.current) { // cancelAnimationFrame(animationFrameRef.current as any) // animationFrameRef.current = null // } // dotScale = 1; // dotAlpha = 1; // } }, [ props.showCurrentDotAnimation ]) useReady(() => { drawCircle() }) useEffect(() => { if (props.ctx) { drawContent(props.ctx) } else { drawCircle() } }, [time.status, time.scenario, user.isLogin, props.targetRing, props.currentDot, props.realRing, props.currentDot?.color, props.canvasId]); var retryCount = 0; function drawCircle() { const query = Taro.createSelectorQuery(); query.select(`#${canvasId}`).fields({ node: true, size: true }); query.exec((res) => { if (res[0] == null) { retryCount++; if (retryCount > 5) { return; } drawCircle() // console.log(canvasId) return; } const _canvas = res[0].node; _canvas.width = res[0].width * dpr; _canvas.height = res[0].height * dpr; const ctx = _canvas.getContext('2d'); global.canvas2 = _canvas if (props.setCtx) { props.setCtx(ctx) props.setCanvas(_canvas) drawContent(ctx) } else { drawContent(ctx) } // setCanvas(_canvas) // setContext(ctx) // const ctx = Taro.createCanvasContext(canvasId); // drawContent(ctx) }); } function drawContent(ctx) { if (props.canvas) { props.canvas.width = ((radius * 2 + lineWidth)) * dpr; props.canvas.height = ((radius * 2 + lineWidth)) * dpr; } const center = radius + lineWidth / 2; // 圆心坐标 ctx.clearRect(0, 0, radius * 2, radius * 2); // 清除画布 // 设置画布尺寸 ctx.scale(dpr, dpr) ctx.translate(center, 2 * center) ctx.scale(scale, scale); ctx.translate(-center, -2 * center); // 绘制背景圆 ctx.beginPath(); ctx.arc(center, center, radius, 0, 2 * Math.PI); ctx.lineWidth = lineWidth; ctx.strokeStyle = props.bgRing.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); // 绘制schedule进度环 if (props.scheduleRing) { ctx.beginPath(); ctx.arc(center, center, radius, props.scheduleRing!.startArc, props.scheduleRing!.startArc + props.scheduleRing!.durationArc); ctx.lineWidth = lineWidth + 4; ctx.strokeStyle = MainColorType.bg; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); ctx.beginPath(); ctx.arc(center, center, radius, props.scheduleRing!.startArc, props.scheduleRing!.startArc + props.scheduleRing!.durationArc); ctx.lineWidth = lineWidth; ctx.strokeStyle = props.scheduleRing!.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); } // 绘制target进度环 if (props.targetRing) { // ctx.beginPath(); // ctx.arc(center, center, props.targetRing!.radius ? props.targetRing!.radius : radius, props.targetRing!.startArc, // props.targetRing!.startArc + props.targetRing!.durationArc); // ctx.lineWidth = props.targetRing!.lineWidth ? props.targetRing!.lineWidth + 4 : lineWidth + 4; // ctx.strokeStyle = MainColorType.bg; // ctx.lineCap = 'round'; // 设置为圆角 // ctx.stroke(); ctx.beginPath(); ctx.arc(center, center, props.targetRing!.radius ? props.targetRing!.radius : radius, props.targetRing!.startArc, props.targetRing!.startArc + props.targetRing!.durationArc); ctx.lineWidth = props.targetRing!.lineWidth ? props.targetRing!.lineWidth : lineWidth; ctx.strokeStyle = props.targetRing!.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); } //绘制real进度环 if (props.realRing) { if (props.realRing.durationArc < 0.01) props.realRing.durationArc = 0.01; // if (!props.realRing.hideBg) { // ctx.beginPath(); // ctx.arc(center, center, props.realRing!.radius ? props.realRing!.radius : radius, props.realRing!.startArc, // props.realRing!.startArc + props.realRing!.durationArc); // ctx.lineWidth = props.realRing!.lineWidth ? props.realRing!.lineWidth + 4 : lineWidth + 4; // ctx.strokeStyle = MainColorType.bg; // ctx.lineCap = 'round'; // 设置为圆角 // ctx.stroke(); // } ctx.beginPath(); ctx.arc(center, center, props.realRing!.radius ? props.realRing!.radius : radius, props.realRing!.startArc, props.realRing!.startArc + props.realRing!.durationArc); ctx.lineWidth = props.realRing!.lineWidth ? props.realRing!.lineWidth : lineWidth; ctx.strokeStyle = props.realRing!.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); } if (props.stageList) { props.stageList.map(item => { if (item.durationArc < 0.01) item.durationArc = 0.01; ctx.beginPath(); ctx.arc(center, center, radius, item.startArc, item.startArc + item.durationArc); ctx.lineWidth = lineWidth; ctx.strokeStyle = item.color; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); }) } //绘制current_dot点 if (props.currentDot) { 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 = center + r * Math.cos(radians); const yPrime = center + r * Math.sin(radians); ctx.beginPath(); var dotLineWidth = 2 if (lineWidth == 28) { dotLineWidth = 4 } ctx.arc(xPrime, yPrime, lineWidth / 2.0 + dotLineWidth / 2, 0, 2 * Math.PI); ctx.lineWidth = dotLineWidth; ctx.fillStyle = props.currentDot.borderColor ctx.fill() ctx.strokeStyle = props.currentDot.borderColor//'#1C1C1C'; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); if (props.currentDot.color != '#ffffffff') { ctx.beginPath(); // ctx.translate(xPrime, yPrime) ctx.arc(xPrime, yPrime, lineWidth / 2 * dotScale, 0, 2 * Math.PI, false); ctx.globalAlpha = dotAlpha//alphaRef.current // ctx.scale(scaleRef.current,scaleRef.current) // ctx.translate(-xPrime, -yPrime) ctx.fillStyle = props.currentDot.color; ctx.fill(); } // if (arrowImg) { // //绘制终点图标 // ctx.save() // ctx.beginPath() // ctx.translate(xPrime, yPrime) // ctx.rotate(arc) // ctx.translate(-xPrime, -yPrime) // ctx.drawImage(arrowImg, xPrime - lineWidth / 2, yPrime - lineWidth / 2, lineWidth, lineWidth) // ctx.restore() // ctx.closePath() // } // else { // let tempImage = global.canvas2.createImage() // tempImage.src = require(props.currentDot.whiteIcon ? '@/assets/images/dot_arrow_white.png' : '@/assets/images/dot_arrow.png')//'./watch_line.png'//'..//assets/images/watch_line.png' // tempImage.onload = () => { // arrowImg = tempImage // ctx.save() // ctx.beginPath() // ctx.translate(xPrime, yPrime) // ctx.rotate(arc) // ctx.translate(-xPrime, -yPrime) // ctx.drawImage(arrowImg, xPrime - lineWidth / 2, yPrime - lineWidth / 2, lineWidth, lineWidth) // ctx.restore() // ctx.closePath() // } // } // ctx.beginPath(); // ctx.arc(center, center, radius, arc, // arc + 0.001); // ctx.lineWidth = lineWidth+6; // ctx.strokeStyle = props.currentDot!.borderColor; // ctx.lineCap = 'round'; // 设置为圆角 // ctx.stroke(); // ctx.save() // ctx.beginPath(); // ctx.arc(center, center, radius, arc, // arc + 0.001); // ctx.lineWidth = lineWidth; // ctx.strokeStyle = props.currentDot!.color; // ctx.lineCap = 'round'; // 设置为圆角 // ctx.stroke(); // ctx.restore() } if (props.dotList) { props.dotList.map(item => { var time = item.timestamp ? new Date(item.timestamp) : new Date(); var seconds = time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds(); var arc = seconds / 86400 * 2 * Math.PI - Math.PI / 2.0; ctx.beginPath(); ctx.arc(center, center, radius, arc, arc + 0.001); ctx.lineWidth = lineWidth + 6; ctx.strokeStyle = item.borderColor; ctx.lineCap = 'round'; // 设置为圆角 ctx.stroke(); ctx.save() ctx.beginPath(); ctx.arc(center, center, radius, arc, arc + 0.001); ctx.lineWidth = lineWidth; ctx.strokeStyle = item.color; ctx.lineCap = 'round'; // 设置为圆角 // ctx.globalAlpha = global.breathAlpha ctx.stroke(); ctx.restore() }) } } return }