|
@@ -1,254 +1,154 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="canvas_button">
|
|
<div class="canvas_button">
|
|
|
- <canvas id="canvasProcess" height="180" width="180"></canvas>
|
|
|
|
|
|
|
+ <canvas ref="canvasRef" id="canvasProcess" height="180" width="180"></canvas>
|
|
|
<div class="canvas_cr"></div>
|
|
<div class="canvas_cr"></div>
|
|
|
- <img src="../../../assets/icon/scan_button_bg.png" v-if="showButton">
|
|
|
|
|
|
|
+ <!-- <img src="@/assets/icon/scan_button_bg.png" v-if="showButton"> -->
|
|
|
|
|
+ <!-- 2. 使用 :src 绑定导入的变量 -->
|
|
|
|
|
+ <img :src="scanButtonBg" v-if="showButton">
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
-<script>
|
|
|
|
|
-
|
|
|
|
|
-export default {
|
|
|
|
|
- name: 'scanButton',
|
|
|
|
|
-
|
|
|
|
|
- props: {
|
|
|
|
|
- process: {
|
|
|
|
|
- type: Number,
|
|
|
|
|
- default: 10
|
|
|
|
|
- },
|
|
|
|
|
- quekao: {
|
|
|
|
|
- type: Number,
|
|
|
|
|
- default: 20
|
|
|
|
|
- },
|
|
|
|
|
- yichang: {
|
|
|
|
|
- type: Number,
|
|
|
|
|
- default: 40
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- watch: {
|
|
|
|
|
- yichang(){
|
|
|
|
|
- // console.log("异常数值变化了",this.yichang);
|
|
|
|
|
- // console.log("打印进度值",this.process,this.quekao,this.yichang);
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- data () {
|
|
|
|
|
- return {
|
|
|
|
|
- canvas: null,
|
|
|
|
|
- scale: 1,
|
|
|
|
|
- circle:0,
|
|
|
|
|
- id: '',
|
|
|
|
|
-
|
|
|
|
|
- animationSpeed:1,
|
|
|
|
|
- showButton:true
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- mounted() {
|
|
|
|
|
- // this.canvas = document.getElementById('canvasScanButton')
|
|
|
|
|
- this.DrawCanvas();//画布开始
|
|
|
|
|
- // this.animations()
|
|
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
|
|
|
|
+import scanButtonBg from '@/assets/icon/scan_button_bg.png';
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ process: {
|
|
|
|
|
+ type: Number,
|
|
|
|
|
+ default: 10
|
|
|
},
|
|
},
|
|
|
- beforeDestroy () {
|
|
|
|
|
- cancelAnimationFrame(this.id);//取消注册请求动画id 通过取消动画帧请求,可以停止正在进行的动画,防止不必要的计算和渲染,从而节省资源和提高性能。
|
|
|
|
|
|
|
+ quekao: {
|
|
|
|
|
+ type: Number,
|
|
|
|
|
+ default: 20
|
|
|
},
|
|
},
|
|
|
- methods: {
|
|
|
|
|
-
|
|
|
|
|
- handleAnimation: function(anim) {
|
|
|
|
|
- this.anim = anim;
|
|
|
|
|
- this.anim.setSpeed(this.animationSpeed);
|
|
|
|
|
- // 可以在这里添加更多的动画控制逻辑
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- //画一个环行进度条圆圈
|
|
|
|
|
- DrawCanvas()
|
|
|
|
|
- {
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- this.canvas=document.getElementById('canvasProcess');
|
|
|
|
|
- if(this.canvas==null)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- let ctx=this.canvas.getContext('2d');
|
|
|
|
|
- //创建一个圆锥渐变对象
|
|
|
|
|
- let g = ctx.createConicGradient(0, 55, 55);
|
|
|
|
|
- //添加颜色停止点
|
|
|
|
|
- g.addColorStop(0,'blue')
|
|
|
|
|
- g.addColorStop(1,'white')
|
|
|
|
|
- ctx.clearRect(0,0,this.canvas.width,this.canvas.height);//清除指定矩形区域内的所有像素
|
|
|
|
|
- ctx.save();//保存当前绘图状态
|
|
|
|
|
- ctx.translate(this.canvas.width / 2, this.canvas.height / 2);//将原点移动到画布的中心
|
|
|
|
|
-
|
|
|
|
|
- //抖动
|
|
|
|
|
- // this.scale = this.scale + 0.002
|
|
|
|
|
- // ctx.scale(this.scale, this.scale)
|
|
|
|
|
- // if (this.scale >= 1.05) {
|
|
|
|
|
- // this.scale = 0.9998
|
|
|
|
|
- // }
|
|
|
|
|
- // // 圆底
|
|
|
|
|
- ctx.translate(-this.canvas.width / 2, -this.canvas.height / 2)//将原点移动到画布的中心
|
|
|
|
|
- ctx.beginPath();//开始路径
|
|
|
|
|
- ctx.save();//保存当前绘图状态
|
|
|
|
|
- ctx.arc(90,90,75,0,2 * Math.PI);//绘制一个圆形,圆心在90,90原点上 半径为80像素
|
|
|
|
|
- ctx.shadowColor = "#4D2EFA";//描边颜色
|
|
|
|
|
- ctx.shadowBlur = 10;//描边粗细
|
|
|
|
|
- ctx.fillStyle = '#ffffff';//底部背景色
|
|
|
|
|
- ctx.fill();//填充
|
|
|
|
|
- ctx.restore();//恢复之前保存的绘图状态
|
|
|
|
|
- ctx.closePath();//闭合路径
|
|
|
|
|
-
|
|
|
|
|
- // 绘制进度环轨道
|
|
|
|
|
- ctx.beginPath();//开始路径
|
|
|
|
|
- ctx.lineWidth = 10;//进度环宽度
|
|
|
|
|
- ctx.strokeStyle = '#EAF0FF';//进度环轨道颜色值
|
|
|
|
|
- ctx.arc(90,90,75,0,2*Math.PI);//绘制进度环圆形 圆心在90 90上半径为75像素
|
|
|
|
|
- ctx.stroke();//描边
|
|
|
|
|
- ctx.closePath();//闭合路径
|
|
|
|
|
-
|
|
|
|
|
- // 进度环
|
|
|
|
|
- //绿色进度环
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.lineWidth = 10;//进度条宽度
|
|
|
|
|
- ctx.strokeStyle = '#2BC644';//进度条颜色值
|
|
|
|
|
- ctx.arc(90,90,75, -90 * Math.PI / 180,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180);//绘制进度条弧度 圆心在90 90 半径为75像素
|
|
|
|
|
- ctx.stroke()
|
|
|
|
|
- ctx.closePath();//闭合路径
|
|
|
|
|
-
|
|
|
|
|
- //异常进度环
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.strokeStyle = '#F56C6C';//异常进度条颜色值
|
|
|
|
|
- ctx.arc(90,90,75,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180,((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
|
|
|
|
|
- ctx.stroke()
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
-
|
|
|
|
|
- //缺考进度环
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.strokeStyle = '#FB9F34'//缺考颜色值
|
|
|
|
|
- ctx.arc(90,90,75,
|
|
|
|
|
- ((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180,
|
|
|
|
|
- ((this.quekao.toFixed(0) / 100)*360 + (this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
|
|
|
|
|
- ctx.stroke();
|
|
|
|
|
- ctx.closePath();
|
|
|
|
|
-
|
|
|
|
|
- // 扫描文字
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.font = "20px bold"
|
|
|
|
|
- ctx.textAlign = 'center'
|
|
|
|
|
- ctx.fillStyle = '#333333';//文字颜色值
|
|
|
|
|
- ctx.fillText('开始扫描',90,120);//扫描的位置
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- // 扫描百分比
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.font = "32px bold";
|
|
|
|
|
- ctx.textAlign = 'center'
|
|
|
|
|
- ctx.fillStyle = '#2E64FA';//扫描百分比颜色值
|
|
|
|
|
- ctx.fillText(this.FormatProcess(this.process) + '%',90,90)
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- ctx.restore()
|
|
|
|
|
- // console.log("打印进度值",this.process,this.quekao,this.yichang);
|
|
|
|
|
- // 请求下一帧
|
|
|
|
|
- this.id = requestAnimationFrame(this.DrawCanvas);
|
|
|
|
|
-
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- // 格式化进度显示:如果小数部分为0则不显示,否则显示一位小数
|
|
|
|
|
- FormatProcess(process)
|
|
|
|
|
- {
|
|
|
|
|
- // 1. 检查是否为有效数字
|
|
|
|
|
- if (process === null || process === undefined || isNaN(process) || !isFinite(process)) {
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 2. 确保是数字类型(防止字符串等意外类型)
|
|
|
|
|
- const num = Number(process);
|
|
|
|
|
-
|
|
|
|
|
- // 3. 再次校验转换后的结果
|
|
|
|
|
- if (isNaN(num)) {
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 4. 格式化逻辑
|
|
|
|
|
- if (num % 1 === 0) {
|
|
|
|
|
- // 如果是整数,直接返回整数
|
|
|
|
|
- return num;
|
|
|
|
|
- } else {
|
|
|
|
|
- // 如果有小数部分,保留两位小数(根据原代码逻辑是 toFixed(2))
|
|
|
|
|
- // 注意:toFixed 返回的是字符串,如果需要数字可以加 +parseFloat(),但通常用于展示字符串即可
|
|
|
|
|
- return parseFloat(num.toFixed(2));
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- animations () {
|
|
|
|
|
- this.canvas=document.getElementById('canvasProcess');
|
|
|
|
|
- let ctx = this.canvas.getContext('2d')
|
|
|
|
|
- //创建一个圆锥渐变对象
|
|
|
|
|
- let g = ctx.createConicGradient(0, 90, 90);
|
|
|
|
|
- //添加颜色停止点
|
|
|
|
|
- g.addColorStop(0,'blue')
|
|
|
|
|
- g.addColorStop(1,'white')
|
|
|
|
|
- ctx.clearRect(0,0,this.canvas.width,this.canvas.height);//清除指定矩形区域内的所有像素
|
|
|
|
|
- ctx.save();//保存当前绘图状态
|
|
|
|
|
- ctx.translate(this.canvas.width / 2, this.canvas.height / 2);//将原点移动到画布的中心
|
|
|
|
|
|
|
+ yichang: {
|
|
|
|
|
+ type: Number,
|
|
|
|
|
+ default: 40
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const canvasRef = ref(null);
|
|
|
|
|
+const animationId = ref(null);
|
|
|
|
|
+const showButton = ref(true);
|
|
|
|
|
+const animationSpeed = ref(1);
|
|
|
|
|
+const anim = ref(null);
|
|
|
|
|
+
|
|
|
|
|
+// 格式化进度显示
|
|
|
|
|
+const FormatProcess = (process) => {
|
|
|
|
|
+ if (process === null || process === undefined || isNaN(process) || !isFinite(process)) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ const num = Number(process);
|
|
|
|
|
+ if (isNaN(num)) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (num % 1 === 0) {
|
|
|
|
|
+ return num;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return parseFloat(num.toFixed(2));
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
- //抖动
|
|
|
|
|
- // this.scale = this.scale + 0.002
|
|
|
|
|
- // ctx.scale(this.scale, this.scale)
|
|
|
|
|
- // if (this.scale >= 1.05) {
|
|
|
|
|
- // this.scale = 0.9998
|
|
|
|
|
- // }
|
|
|
|
|
- // 圆底
|
|
|
|
|
- ctx.translate(-this.canvas.width / 2, -this.canvas.height / 2)
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.save()
|
|
|
|
|
- ctx.arc(125,125,100,0,360 * Math.PI / 180)
|
|
|
|
|
- ctx.shadowColor = "#4D2EFA";
|
|
|
|
|
- ctx.shadowBlur = 15;
|
|
|
|
|
- ctx.fillStyle = '#ffffff';//底部背景色
|
|
|
|
|
- ctx.fill()
|
|
|
|
|
- ctx.restore()
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- // 进度环底边
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.lineWidth = 20
|
|
|
|
|
- ctx.strokeStyle = '#D1E0FF';//进度环轨道颜色值
|
|
|
|
|
- ctx.arc(125,125,85,0,360*Math.PI/180)
|
|
|
|
|
- ctx.stroke()
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- // 进度环
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.lineWidth = 20
|
|
|
|
|
- ctx.strokeStyle = '#2BC644';//进度条颜色值
|
|
|
|
|
- ctx.arc(125,125,85,-90 * Math.PI / 180,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180)
|
|
|
|
|
- ctx.stroke()
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.strokeStyle = 'red'
|
|
|
|
|
- ctx.arc(125,125,85,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180,((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
|
|
|
|
|
- ctx.stroke()
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.strokeStyle = '#FB9334'//缺考颜色值
|
|
|
|
|
- ctx.arc(125,125,85,
|
|
|
|
|
- ((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180,
|
|
|
|
|
- ((this.quekao.toFixed(0) / 100)*360 + (this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
|
|
|
|
|
- ctx.stroke()
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- // 扫描文字
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.font = "20px bold"
|
|
|
|
|
- ctx.textAlign = 'center'
|
|
|
|
|
- ctx.fillStyle = '#333333';//文字颜色值
|
|
|
|
|
- ctx.fillText('开始扫描',125,155);//扫描的位置
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- // 扫描百分比
|
|
|
|
|
- ctx.beginPath()
|
|
|
|
|
- ctx.font = "32px bold";
|
|
|
|
|
- ctx.textAlign = 'center'
|
|
|
|
|
- ctx.fillStyle = '#2E64FA';//扫描百分比颜色值
|
|
|
|
|
- ctx.fillText(this.process.toFixed(0) + '%',125,125)
|
|
|
|
|
- ctx.closePath()
|
|
|
|
|
- ctx.restore()
|
|
|
|
|
- this.id = requestAnimationFrame(this.animations)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const handleAnimation = (animObj) => {
|
|
|
|
|
+ anim.value = animObj;
|
|
|
|
|
+ if (anim.value) {
|
|
|
|
|
+ anim.value.setSpeed(animationSpeed.value);
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const DrawCanvas = () => {
|
|
|
|
|
+ const canvas = canvasRef.value;
|
|
|
|
|
+ if (!canvas) return;
|
|
|
|
|
+
|
|
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
|
|
+
|
|
|
|
|
+ // 清除画布
|
|
|
|
|
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
+
|
|
|
|
|
+ ctx.save();
|
|
|
|
|
+ ctx.translate(canvas.width / 2, canvas.height / 2);
|
|
|
|
|
+ ctx.translate(-canvas.width / 2, -canvas.height / 2);
|
|
|
|
|
+
|
|
|
|
|
+ // 圆底
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.save();
|
|
|
|
|
+ ctx.arc(90, 90, 75, 0, 2 * Math.PI);
|
|
|
|
|
+ ctx.shadowColor = "#4D2EFA";
|
|
|
|
|
+ ctx.shadowBlur = 10;
|
|
|
|
|
+ ctx.fillStyle = '#ffffff';
|
|
|
|
|
+ ctx.fill();
|
|
|
|
|
+ ctx.restore();
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制进度环轨道
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.lineWidth = 10;
|
|
|
|
|
+ ctx.strokeStyle = '#EAF0FF';
|
|
|
|
|
+ ctx.arc(90, 90, 75, 0, 2 * Math.PI);
|
|
|
|
|
+ ctx.stroke();
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ // 绿色进度环
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.lineWidth = 10;
|
|
|
|
|
+ ctx.strokeStyle = '#2BC644';
|
|
|
|
|
+ const startAngle = -90 * Math.PI / 180;
|
|
|
|
|
+ const processEndAngle = ((props.process.toFixed(0) / 100) * 360 - 90) * Math.PI / 180;
|
|
|
|
|
+ ctx.arc(90, 90, 75, startAngle, processEndAngle);
|
|
|
|
|
+ ctx.stroke();
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ // 异常进度环
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.strokeStyle = '#F56C6C';
|
|
|
|
|
+ const yichangEndAngle = ((props.yichang.toFixed(0) / 100) * 360 + ((props.process.toFixed(0) / 100) * 360 - 90)) * Math.PI / 180;
|
|
|
|
|
+ ctx.arc(90, 90, 75, processEndAngle, yichangEndAngle);
|
|
|
|
|
+ ctx.stroke();
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ // 缺考进度环
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.strokeStyle = '#FB9F34';
|
|
|
|
|
+ const quekaoEndAngle = ((props.quekao.toFixed(0) / 100) * 360 + (props.yichang.toFixed(0) / 100) * 360 + ((props.process.toFixed(0) / 100) * 360 - 90)) * Math.PI / 180;
|
|
|
|
|
+ ctx.arc(90, 90, 75, yichangEndAngle, quekaoEndAngle);
|
|
|
|
|
+ ctx.stroke();
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ // 扫描文字
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.font = "20px bold";
|
|
|
|
|
+ ctx.textAlign = 'center';
|
|
|
|
|
+ ctx.fillStyle = '#333333';
|
|
|
|
|
+ ctx.fillText('开始扫描', 90, 120);
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ // 扫描百分比
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.font = "32px bold";
|
|
|
|
|
+ ctx.textAlign = 'center';
|
|
|
|
|
+ ctx.fillStyle = '#2E64FA';
|
|
|
|
|
+ ctx.fillText(FormatProcess(props.process) + '%', 90, 90);
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+
|
|
|
|
|
+ ctx.restore();
|
|
|
|
|
+
|
|
|
|
|
+ // 请求下一帧
|
|
|
|
|
+ animationId.value = requestAnimationFrame(DrawCanvas);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ DrawCanvas();
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
|
+ if (animationId.value) {
|
|
|
|
|
+ cancelAnimationFrame(animationId.value);
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+watch(() => props.yichang, () => {
|
|
|
|
|
+ // console.log("异常数值变化了", props.yichang);
|
|
|
|
|
+ // console.log("打印进度值", props.process, props.quekao, props.yichang);
|
|
|
|
|
+});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|