<template>
|
|
<view class="progress_box">
|
|
<canvas class="progress_bg" :canvas-id="`cpbg${code}`" type="2d"></canvas>
|
|
<canvas class="progress_line" :canvas-id="`cpline${code}`" type="2d"></canvas>
|
|
<canvas class="progress_bar" :canvas-id="`cpbar${code}`" type="2d"></canvas>
|
|
<div class="bg-inner"></div>
|
|
<div class="progress-info">
|
|
<div class="flex">
|
|
<div class="progress-score">{{ progress }}</div>
|
|
<div class="progress-unit">分</div>
|
|
</div>
|
|
<div class="progress-desc">健康综合分数</div>
|
|
</div>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
const START = - Math.PI * 3 / 2 + Math.PI * 1 / 6
|
|
const END = Math.PI * 2 / 6
|
|
|
|
export default {
|
|
props: {
|
|
progress: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
code: Math.floor(Math.random() * 100).toString()
|
|
}
|
|
},
|
|
mounted() {
|
|
this.drawProgressbg();
|
|
this.drawLine()
|
|
},
|
|
watch: {
|
|
progress: {
|
|
handler(val) {
|
|
console.log('watch progress', val)
|
|
this.$nextTick(() => {
|
|
this.drawProgress(val)
|
|
})
|
|
},
|
|
},
|
|
},
|
|
methods: {
|
|
drawProgressbg() {
|
|
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress_bg')
|
|
.fields({
|
|
node: true,
|
|
size: true
|
|
})
|
|
.exec(async (res) => {
|
|
console.log('progress_bg', res)
|
|
const canvas = res[0].node
|
|
// Canvas 画布的实际绘制宽高
|
|
const width = res[0].width
|
|
const height = res[0].height
|
|
//根据dpr调整
|
|
const dpr = wx.getWindowInfo().pixelRatio
|
|
canvas.width = width * dpr
|
|
canvas.height = height * dpr
|
|
|
|
let Ratio = width / 244
|
|
|
|
// 渲染上下文
|
|
const ctx = canvas.getContext('2d')
|
|
|
|
ctx.scale(dpr, dpr)
|
|
ctx.clearRect(0, 0, width, height)
|
|
|
|
let w = 12 * Ratio
|
|
ctx.lineWidth = w; // 设置圆环的宽度
|
|
ctx.strokeStyle = '#E1E0E6'; // 设置圆环的颜色
|
|
ctx.lineCap = 'round'; // 设置圆环端点的形状
|
|
ctx.beginPath(); //开始一个新的路径
|
|
let x = width / 2
|
|
let y = height / 2
|
|
let r = 102 * Ratio - w / 2
|
|
ctx.arc(x, y, r, START + Math.PI / 50, END - Math.PI / 50, false);
|
|
//设置一个原点(110,110),半径为100的圆的路径到当前路径
|
|
ctx.stroke(); //对当前路径进行描边
|
|
})
|
|
|
|
},
|
|
// 画刻度
|
|
drawLine() {
|
|
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress_line')
|
|
.fields({
|
|
node: true,
|
|
size: true
|
|
})
|
|
.exec(async (res) => {
|
|
const canvas = res[0].node
|
|
// Canvas 画布的实际绘制宽高
|
|
const width = res[0].width
|
|
const height = res[0].height
|
|
//根据dpr调整
|
|
const dpr = wx.getWindowInfo().pixelRatio
|
|
canvas.width = width * dpr
|
|
canvas.height = height * dpr
|
|
|
|
let Ratio = width / 244
|
|
|
|
// 渲染上下文
|
|
const ctx = canvas.getContext('2d')
|
|
|
|
ctx.scale(dpr, dpr)
|
|
ctx.clearRect(0, 0, width, height)
|
|
|
|
let x = width / 2
|
|
let y = height / 2
|
|
let r = 90 * Ratio
|
|
|
|
let lineWidth = 3 * Ratio;
|
|
let lineHeight = 8 * Ratio;
|
|
let startAngle = Math.PI / 2
|
|
|
|
let textArr = ['', '0', '差', '20', '较差', '40', '中等', '60', '良好', '80', '优秀', '100']
|
|
|
|
for (let i = 0; i < 12; i++) {
|
|
ctx.beginPath();
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.strokeStyle = '#E1E0E6';
|
|
|
|
let angle = startAngle - Math.PI * i / 6
|
|
let x0 = x - r * Math.cos(angle)
|
|
let y0 = y + r * Math.sin(angle)
|
|
|
|
let x1 = x0 + lineHeight * Math.cos(angle)
|
|
let y1 = y0 - lineHeight * Math.sin(angle)
|
|
|
|
ctx.moveTo(x0, y0);
|
|
ctx.lineTo(x1, y1);
|
|
ctx.stroke();
|
|
ctx.closePath();
|
|
|
|
ctx.translate(x1, y1)
|
|
ctx.rotate(Math.PI * 3 / 2 - angle);
|
|
|
|
let text = textArr[i]
|
|
ctx.font = "normal normal normal 7px normal";
|
|
ctx.fillStyle = "#D0CFD3";
|
|
// 计算文本的宽度和高度
|
|
const metrics = ctx.measureText(text);
|
|
const textWidth = metrics.width;
|
|
|
|
ctx.fillText(text, - textWidth / 2 - lineWidth / 2, 6);
|
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
|
|
}
|
|
})
|
|
|
|
},
|
|
drawProgress(step) {
|
|
console.log('drawProgress', step)
|
|
if (!step) {
|
|
return
|
|
}
|
|
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress_bar')
|
|
.fields({
|
|
node: true,
|
|
size: true
|
|
})
|
|
.exec(async (res) => {
|
|
const canvas = res[0].node
|
|
// Canvas 画布的实际绘制宽高
|
|
const width = res[0].width
|
|
const height = res[0].height
|
|
//根据dpr调整
|
|
const dpr = wx.getWindowInfo().pixelRatio
|
|
canvas.width = width * dpr
|
|
canvas.height = height * dpr
|
|
|
|
let Ratio = width / 244
|
|
|
|
// 渲染上下文
|
|
const ctx = canvas.getContext('2d')
|
|
|
|
ctx.scale(dpr, dpr)
|
|
ctx.clearRect(0, 0, width, height)
|
|
|
|
// 进度条的渐变(中心x坐标-半径-边宽,中心Y坐标,中心x坐标+半径+边宽,中心Y坐标)
|
|
let gradient = ctx.createLinearGradient(0, 0, 130, 0);
|
|
|
|
// 参数step 为绘制的百分比
|
|
let end = (step / 100) * (END - START) + START; // 最后的角度
|
|
gradient.addColorStop('0', '#7451DE');
|
|
gradient.addColorStop('1.0', '#B1A4FF');
|
|
let w = 12 * Ratio
|
|
ctx.lineWidth = w; // 设置圆环的宽度
|
|
ctx.strokeStyle = gradient; // 设置圆环的颜色
|
|
ctx.lineCap = 'round'; // 设置圆环端点的形状
|
|
ctx.shadowOffsetX = 8;
|
|
ctx.shadowOffsetY = 8;
|
|
ctx.shadowBlur = 32;
|
|
ctx.shadowColor = "rgba(64, 0, 255, 0.3)";
|
|
|
|
ctx.beginPath();
|
|
let x = width / 2
|
|
let y = height / 2
|
|
let r = 102 * Ratio - w / 2
|
|
ctx.arc(x, y, r, START + Math.PI / 50, end - Math.PI / 50, false);
|
|
ctx.stroke();
|
|
})
|
|
|
|
},
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
$size: 244rpx;
|
|
$innerSize: 130rpx;
|
|
|
|
.progress_box {
|
|
position: relative;
|
|
width: $size;
|
|
height: $size;
|
|
background: #F6F6F9CC;
|
|
border-radius: 50%;
|
|
box-shadow: 0 0 6.7rpx 1rpx #D3D2E599;
|
|
}
|
|
.progress_bg,
|
|
.progress_bar,
|
|
.progress_line,
|
|
.progress_font {
|
|
position: absolute;
|
|
width: $size;
|
|
height: $size;
|
|
}
|
|
|
|
.bg-inner {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: $innerSize;
|
|
height: $innerSize;
|
|
border-radius: 50%;
|
|
background-image: linear-gradient(to bottom, #FFFFFF, #E9E7F4);
|
|
box-shadow: 0 8rpx 8rpx 0 #D3D2E5;
|
|
}
|
|
|
|
.progress {
|
|
&-info {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
&-score {
|
|
font-size: 52rpx;
|
|
font-weight: 600;
|
|
font-family: PingFang SC;
|
|
color: transparent;
|
|
background-image: linear-gradient(to right, #4B348F, #845CFA);
|
|
background-clip: text;
|
|
display: inline-block;
|
|
}
|
|
&-unit {
|
|
font-size: 24rpx;
|
|
font-weight: 600;
|
|
font-family: PingFang SC;
|
|
color: #000000;
|
|
margin-left: 8rpx;
|
|
}
|
|
&-desc {
|
|
font-size: 16rpx;
|
|
font-weight: 400;
|
|
font-family: PingFang SC;
|
|
color: #989898;
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
</style>
|
|
|