普兆健康管家前端代码仓库
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.
 
 
 

336 lines
7.6 KiB

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