| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- 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<CurrentDot>;
- stageList?: Array<RealRing>;
- 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<number | null>(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 <Canvas canvasId={canvasId} id={canvasId} className="canvas" type="2d" style={{ width: (radius * 2 + lineWidth), height: (radius * 2 + lineWidth), zIndex: 0 }} ref={canvasRef} />
- }
|