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