<template>
|
|
<view class="progress_box">
|
|
<div class="bg-outer"></div>
|
|
<canvas class="progress progress-outer" canvas-id="cpouterline" type="2d"></canvas>
|
|
<div class="bg-inner"></div>
|
|
<canvas class="progress progress-inner" canvas-id="cpinnerline" type="2d"></canvas>
|
|
<div class="bg-score bg-score-min">0分</div>
|
|
<div class="bg-score bg-score-max">100分</div>
|
|
<div class="progress 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>
|
|
|
|
export default {
|
|
props: {
|
|
progress: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
outerCanvas: {},
|
|
innerCanvas: {},
|
|
ratio: 1,
|
|
dpr: 1,
|
|
}
|
|
},
|
|
mounted() {
|
|
this.init()
|
|
},
|
|
methods: {
|
|
init() {
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress-outer')
|
|
.fields({
|
|
node: true,
|
|
size: true
|
|
})
|
|
.exec(async (res) => {
|
|
|
|
// Canvas 画布的实际绘制宽高
|
|
const width = res[0].width
|
|
|
|
const dpr = wx.getWindowInfo().pixelRatio
|
|
|
|
let Ratio = width / 446
|
|
|
|
this.outerCanvas = res[0]
|
|
this.ratio = Ratio
|
|
this.dpr = dpr
|
|
|
|
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress-inner')
|
|
.fields({
|
|
node: true,
|
|
size: true
|
|
})
|
|
.exec(async (res) => {
|
|
this.innerCanvas = res[0]
|
|
|
|
this.drawOuterLine(this.progress)
|
|
this.drawInnerLine(this.progress)
|
|
})
|
|
|
|
})
|
|
},
|
|
drawOuterLine(step) {
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress-outer')
|
|
.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 / 446
|
|
|
|
// 渲染上下文
|
|
const ctx = canvas.getContext('2d')
|
|
|
|
ctx.scale(dpr, dpr)
|
|
ctx.clearRect(0, 0, width, height)
|
|
|
|
let r = 210 * Ratio
|
|
let x = this.outerCanvas.width / 2
|
|
let y = this.outerCanvas.height - this.innerCanvas.height / 2
|
|
|
|
let lineWidth = 10 * Ratio;
|
|
let lineHeight = 26 * Ratio;
|
|
let startAngle = 0
|
|
|
|
// 进度条的渐变(中心x坐标-半径-边宽,中心Y坐标,中心x坐标+半径+边宽,中心Y坐标)
|
|
let gradient = ctx.createLinearGradient(x - r, y, x + r, y);
|
|
gradient.addColorStop('0', '#7451DE');
|
|
gradient.addColorStop('1.0', '#B1A4FF');
|
|
|
|
ctx.strokeStyle = '#E5E5E5';
|
|
ctx.save()
|
|
|
|
for (let i = 0; i < 11; i++) {
|
|
ctx.beginPath();
|
|
|
|
if (i % 5) {
|
|
lineWidth = 6 * Ratio;
|
|
lineHeight = 15 * Ratio;
|
|
} else {
|
|
lineWidth = 10 * Ratio;
|
|
lineHeight = 18 * Ratio;
|
|
}
|
|
|
|
if (step >= i * 10) {
|
|
ctx.strokeStyle = gradient;
|
|
} else {
|
|
ctx.restore();
|
|
}
|
|
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.lineCap = 'round';
|
|
|
|
let angle = startAngle - Math.PI * i / 10
|
|
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();
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
drawInnerLine(step) {
|
|
uni.createSelectorQuery().in(this)
|
|
.select('.progress-inner')
|
|
.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 / 356
|
|
|
|
// 渲染上下文
|
|
const ctx = canvas.getContext('2d')
|
|
|
|
ctx.scale(dpr, dpr)
|
|
ctx.clearRect(0, 0, width, height)
|
|
|
|
let r = 140 * Ratio
|
|
let x = this.innerCanvas.width / 2
|
|
let y = this.innerCanvas.height / 2
|
|
|
|
let lineWidth = 5 * Ratio;
|
|
let lineHeight = 28 * Ratio;
|
|
|
|
// 进度条的渐变(中心x坐标-半径-边宽,中心Y坐标,中心x坐标+半径+边宽,中心Y坐标)
|
|
let gradient = ctx.createLinearGradient(x - r, y, x + r, y);
|
|
gradient.addColorStop('0', '#E81717');
|
|
gradient.addColorStop('0.5', '#ECBD00');
|
|
gradient.addColorStop('1.0', '#0DB556');
|
|
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.strokeStyle = '#989898';
|
|
ctx.save()
|
|
|
|
let angle = 0
|
|
let i = 0
|
|
while (angle > - Math.PI) {
|
|
ctx.beginPath();
|
|
|
|
if (i % 2) {
|
|
angle -= Math.PI / 50
|
|
i++
|
|
continue
|
|
}
|
|
|
|
if (step * Math.PI / 100 >= -angle) {
|
|
ctx.strokeStyle = gradient;
|
|
} else {
|
|
ctx.restore();
|
|
}
|
|
|
|
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();
|
|
|
|
angle -= Math.PI / 100
|
|
i++
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
$size: 356rpx;
|
|
|
|
.progress_box {
|
|
position: relative;
|
|
width: 100vw;
|
|
height: 402rpx;
|
|
}
|
|
.progress {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
|
|
&-outer {
|
|
width: 446rpx;
|
|
height: 100%;
|
|
}
|
|
|
|
&-inner {
|
|
width: $size;
|
|
height: $size;
|
|
bottom: 0;
|
|
}
|
|
|
|
&-info {
|
|
position: absolute;
|
|
left: 50%;
|
|
bottom: calc(#{$size} / 2);
|
|
transform: translate(-50%, calc(50% + 5rpx));
|
|
}
|
|
|
|
&-score {
|
|
font-size: 48rpx;
|
|
font-weight: 600;
|
|
font-family: PingFang SC;
|
|
color: #000000;
|
|
}
|
|
&-unit {
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
font-family: PingFang SC;
|
|
color: #000000;
|
|
margin-left: 8rpx;
|
|
}
|
|
&-desc {
|
|
font-size: 26rpx;
|
|
font-weight: 400;
|
|
font-family: PingFang SC;
|
|
color: #989898;
|
|
text-align: center;
|
|
}
|
|
|
|
}
|
|
|
|
.bg {
|
|
&-outer {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
bottom: 0;
|
|
width: $size;
|
|
height: $size;
|
|
border-radius: 50%;
|
|
box-shadow: inset 4px 4px 16px #8D96B466,
|
|
4px 4px 16px 0 rgba(141, 150, 180, 0.3),
|
|
// 2px 2px 2px 0 #8D96B466,
|
|
-2px -2px 8px 0 #FFFFFF,
|
|
-1px -1px 14px 0 #FFFFFF;
|
|
}
|
|
&-inner {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
bottom: 28rpx;
|
|
width: 300rpx;
|
|
height: 300rpx;
|
|
background-color: #EEF0F6;
|
|
border-radius: 50%;
|
|
box-shadow: 6px 6px 6px 0 #0000000F,
|
|
-4px -4px 13px 0 #FFFFFF,
|
|
4px 4px 7px 0 #00000012,
|
|
}
|
|
&-score {
|
|
color: #989898;
|
|
font-size: 26rpx;
|
|
font-weight: 400;
|
|
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
|
|
&-min {
|
|
transform: translate(-303rpx, 0);
|
|
}
|
|
|
|
&-max {
|
|
transform: translate(263rpx, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
</style>
|