| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- 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<any>(null)
- const [canvas, setCanvas] = useState<any>(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 <Canvas canvasId={canvasId} id={canvasId} className="canvas" type="2d"
- style={{ width: canvasWidth, height: canvasHeight, zIndex: 0 }}
- ref={canvasRef}
- />
- }
|