123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- <template>
- <view
- class="tn-circle-progress-class tn-circle-progress"
- :style="{
- width: widthPx + 'px',
- height: widthPx + 'px'
- }"
- >
-
-
- <canvas
- class="tn-circle-progress__canvas-bg"
- :canvas-id="elBgId"
- :id="elBgId"
- :style="{
- width: widthPx + 'px',
- height: widthPx + 'px'
- }"
- ></canvas>
-
- <canvas
- class="tn-circle-progress__canvas"
- :canvas-id="elId"
- :id="elId"
- :style="{
- width: widthPx + 'px',
- height: widthPx + 'px'
- }"
- ></canvas>
- <view class="tn-circle-progress__content">
- <slot v-if="$slots.default || $slots.$default"></slot>
- <view v-else-if="showPercent" class="tn-circle-progress__content__percent">{{ percent + '%' }}</view>
- </view>
- </view>
- </template>
- <script>
- export default {
- name: 'tn-circle-progress',
- props: {
-
- percent: {
- type: Number,
- default: 0,
- validator: val => {
- return val >= 0 && val <= 100
- }
- },
-
- borderWidth: {
- type: Number,
- default: 14
- },
-
- width: {
- type: Number,
- default: 200
- },
-
- striped: {
- type: Boolean,
- default: false
- },
-
- stripedActive: {
- type: Boolean,
- default: true
- },
-
- activeColor: {
- type: String,
- default: '#01BEFF'
- },
-
- inactiveColor: {
- type: String,
- default: '#f0f0f0'
- },
-
- showPercent: {
- type: Boolean,
- default: false
- },
-
- duration: {
- type: Number,
- default: 1500
- }
- },
- data() {
- return {
-
-
- elBgId: 'tCircleProgressBgId',
- elId: 'tCircleProgressElId',
-
-
- elBgId: this.$t.uuid(),
- elId: this.$t.uuid(),
-
-
- progressContext: null,
-
- widthPx: uni.upx2px(this.width || 200),
-
- borderWidthPx: uni.upx2px(this.borderWidth || 14),
-
- startAngle: -90 * Math.PI / 180,
-
- newPercent: 0,
- oldPercent: 0
- }
- },
- watch: {
- percent(newVal, oldVal = 0) {
- if (newVal > 100) newVal = 100
- if (oldVal < 0) oldVal = 0
-
- this.newPercent = newVal
- this.oldPercent = oldVal
- setTimeout(() => {
-
-
- this.drawCircleByProgress(oldVal)
- }, 50)
- }
- },
- created() {
-
- this.newPercent = this.percent;
- this.oldPercent = 0;
- },
- mounted() {
- setTimeout(() => {
- this.drawProgressBg()
- this.drawCircleByProgress(this.oldPercent)
- }, 50)
- },
- methods: {
-
- drawProgressBg() {
- let ctx = uni.createCanvasContext(this.elBgId, this)
-
- ctx.setLineWidth(this.borderWidthPx)
-
- ctx.setStrokeStyle(this.inactiveColor)
- ctx.beginPath()
- let radius = this.widthPx / 2
- ctx.arc(radius, radius, radius - this.borderWidthPx, 0, 360 * Math.PI / 180, false)
- ctx.stroke()
- ctx.draw()
- },
-
- drawCircleByProgress(progress) {
-
- let ctx = this.progressContext
- if (!ctx) {
- ctx =uni.createCanvasContext(this.elId, this)
- this.progressContext = ctx
- }
- ctx.setLineCap('round')
-
- ctx.setLineWidth(this.borderWidthPx)
- ctx.setStrokeStyle(this.activeColor)
-
- let preSecondTime = Math.floor(this.duration / 100)
-
- let endAngle = ((360 * Math.PI / 180) / 100) * progress + this.startAngle
- let radius = this.widthPx / 2
- ctx.beginPath()
- ctx.arc(radius, radius, radius - this.borderWidthPx, this.startAngle, endAngle, false)
- ctx.stroke()
- ctx.draw()
-
-
- if (this.newPercent > this.oldPercent) {
-
- progress++
-
- if (progress > this.newPercent) return
- } else {
- progress--
- if (progress < this.newPercent) return
- }
- setTimeout(() => {
-
- this.drawCircleByProgress(progress)
- }, preSecondTime)
- }
- }
- }
- </script>
- <style lang="scss" scoped>
-
- .tn-circle-progress {
- position: relative;
- /* #ifndef APP-NVUE */
- display: inline-flex;
- /* #endif */
- align-items: center;
- justify-content: center;
- background-color: transparent;
-
- &__canvas {
- position: absolute;
-
- &-bg {
- position: absolute;
- }
- }
-
- &__content {
- display: flex;
- align-items: center;
- justify-content: center;
-
- &__percent {
- font-size: 28rpx;
- }
- }
- }
- </style>
|