普兆健康管家前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

287 lines
7.2 KiB

<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>