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