You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
7.5 KiB
Vue

1 year ago
<template>
<view class="tm-propressRound d-inline-block">
<view class="tm-propressRound-text" :style="{
width:size+'px',
height:size+'px'
}">
<slot name="default" :value="value">
<text class="text-black" :class="[black?'text-white':'']">{{value}}%</text>
</slot>
</view>
<view class="tm-propressRound-rk">
<!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
<canvas :canvas-id="cid" :id="cid"
:style="{
width:size+'px',
height:size+'px'
}"
type="2d"
></canvas>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN || MP-ALIPAY -->
<canvas :canvas-id="cid" :id="cid"
:style="{
width:size+'px',
height:size+'px'
}"
></canvas>
<!-- #endif -->
</view>
</view>
</template>
<script>
/**
* 环形进度条
* @property {Number} value = [] 默认0推荐使用v-model赋值value.sync等同
* @property {Number} size = [] 默认100圆环大小
* @property {Number} line-width = [] 默认6圆环线条宽
* @property {Array} color = [] 默认['#FF9800','#E91E63','#FF5722']激活颜色
* @property {String} bgcolor = [] 默认'#EEEEEE'背景颜色
* @property {Boolea} semicircle = [] 默认 false是否半圆
* @property {Function} input 变化时的值
* @property {Function} change 变化时的值
* @example <tm-propressRound v-model="checked"></tm-propressRound>
*/
export default {
name:"tm-propressRound",
model:{
prop:"value",
event:"input"
},
props:{
black:{
type:Boolean,
default:false
},
size:{
type:Number,
default:100
},
lineWidth:{
type:Number,
default:10
},
value:{
type:Number,
default:0
},
color:{
type:Array,
default:()=>{
return ['rgb(255,152,0)','rgb(233,30,99)','rgb(255,87,34)']
}
},
bgcolor:{
type:String,
default:'rgb(238,238,238)'
},
semicircle:{
type:Boolean|String,
default:false
}
},
data() {
return {
ctx:null,
timid:null,
jishu:0,
cid:'fdd_psd',
is2d:false
};
},
computed:{
},
created() {
// #ifdef H5 || APP-VUE || APP-PLUS
this.cid = uni.$tm.guid();
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY
this.is2d=true;
// #endif
},
mounted() {
this.$nextTick(function(){
this.inits();
})
},
destroyed() {
clearInterval(this.timid)
},
watch:{
value:function(newval,oldval){
if(newval < 0){
this.$emit("input",0)
this.$emit("update:value",0)
this.$emit("change",0)
return;
}else if(newval >100){
this.$emit("input",100)
this.$emit("update:value",100)
this.$emit("change",100)
return;
}
this.$emit("input",newval)
this.$emit("update:value",newval)
this.$emit("change",newval)
let blv = newval - oldval;
if(newval>=100){
blv = 100 - oldval;
}
if(blv >= 0 ){
this.startHuiZhi(blv,oldval,true)
}else{
if(newval<=0){
blv = oldval;
}
this.startHuiZhi(Math.abs(blv),oldval,false)
}
}
},
methods: {
inits(){
let t = this;
if(this.is2d){
const query = wx.createSelectorQuery().in(this)
query.select('#'+this.cid)
.node((res) => {
const canvas = res.node
const ctx = canvas.getContext('2d')
const dpr = uni.getSystemInfoSync().pixelRatio
canvas.width = res.node._width * dpr
canvas.height = res.node._height * dpr
ctx.scale(dpr, dpr)
t.ctx = ctx;
t.creatShape();
this.startHuiZhi(this.value,0,true)
})
.exec()
}else{
this.ctx = uni.createCanvasContext(this.cid,this)
this.creatShape();
this.startHuiZhi(this.value,0,true)
}
},
startHuiZhi(val,oldv,type){
clearInterval(this.timid);
let i = 0;
let t = this;
// #ifdef H5
this.timid = setInterval(()=>{
i += 1;
if(i>=val){
clearInterval(t.timid);
return;
}
if(type){
t.huizhired(oldv+i,type);
}else{
t.huizhired(oldv-i,type);
}
},5)
// #endif
// #ifndef H5
if(type){
t.huizhired(val+oldv,type);
}else{
t.huizhired(oldv-val,type);
}
// #endif
},
// 重新绘制。
creatShape() {
if(!this.ctx) return;
let ctx= this.ctx;
let x,y,r ;
x = y = this.size / 2;
r = (this.size - this.lineWidth*2) / 2
if(this.is2d){
ctx.beginPath()
ctx.lineCap='round';
ctx.lineWidth=this.lineWidth-1;
ctx.strokeStyle=this.bgcolor;
if(this.semicircle){
ctx.arc(x, y, r, Math.PI, 0)
}else{
ctx.arc(x, y, r, -90, 2 * Math.PI)
}
ctx.stroke()
}else{
ctx.beginPath()
ctx.setLineCap('round')
ctx.setLineWidth(this.lineWidth-1)
ctx.setStrokeStyle(this.bgcolor)
if(this.semicircle){
ctx.arc(x, y, r, Math.PI, 0)
}else{
ctx.arc(x, y, r, -90, 2 * Math.PI)
}
ctx.stroke()
ctx.draw(true)
}
},
huizhired(end=0,type){
if(!this.ctx) return;
let ctx = this.ctx;
if(end>=100) end = 100;
if(end<=0) end = 0;
let bl = end * 3.6;
bl = bl-90
let x,y,r ;
x = y = this.size / 2;
r = (this.size - this.lineWidth*2) / 2
if(this.is2d){
ctx.beginPath()
ctx.lineCap='round';
ctx.lineWidth=type?this.lineWidth-1:this.lineWidth+1;
ctx.strokeStyle=this.bgcolor
if(this.semicircle){
ctx.arc(x, y, r, Math.PI, 0)
}else{
ctx.arc(x, y, r, -90, 2 * Math.PI)
}
ctx.stroke()
ctx.beginPath()
ctx.lineCap='round';
ctx.lineWidth=this.lineWidth
var grd=ctx.createLinearGradient(x,0,0,2*x);
let colorl = this.color.length;
if(colorl==1){
grd.addColorStop(1,this.color[0]);
}else if(colorl>1){
for(let i=0;i<colorl;i++){
grd.addColorStop(i/(colorl-1),this.color[i]);
}
}
ctx.strokeStyle=grd
if(this.semicircle){
let val = this.value;
val = val <=0?0:val;
val = val>=100?100:val;
bl = -(Math.PI-this.value/100 * Math.PI)
ctx.arc(x, y, r, Math.PI, bl)
}else{
ctx.arc(x, y, r, -90 * (Math.PI / 180), bl * (Math.PI / 180))
}
ctx.stroke()
}else{
ctx.beginPath()
ctx.setLineCap('round')
ctx.setLineWidth(type?this.lineWidth-1:this.lineWidth+1)
ctx.setStrokeStyle(this.bgcolor)
if(this.semicircle){
ctx.arc(x, y, r, Math.PI, 0)
}else{
ctx.arc(x, y, r, -90, 2 * Math.PI)
}
ctx.stroke()
ctx.draw(true)
ctx.beginPath()
ctx.setLineCap('round')
ctx.setLineWidth(this.lineWidth)
var grd=ctx.createLinearGradient(x,0,0,2*x);
let colorl = this.color.length;
if(colorl==1){
grd.addColorStop(1,this.color[0]);
}else if(colorl>1){
for(let i=0;i<colorl;i++){
grd.addColorStop(i/(colorl-1),this.color[i]);
}
}
ctx.setStrokeStyle(grd)
if(this.semicircle){
let val = this.value;
val = val <=0?Math.PI:val;
val = val>=100?100:val;
bl = -(Math.PI-this.value/100 * Math.PI)
bl = Math.abs(bl)>=Math.PI?Math.PI:bl;
ctx.arc(x, y, r, Math.PI, bl)
}else{
ctx.arc(x, y, r, -90 * (Math.PI / 180), bl * (Math.PI / 180))
}
ctx.stroke()
ctx.draw(true)
}
},
},
}
</script>
<style lang="scss" scoped>
.tm-propressRound{
position: relative;
.tm-propressRound-text{
position: absolute;
display: flex;
justify-content: center;
align-items: center;
align-content: center;
}
}
</style>