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.
228 lines
6.4 KiB
228 lines
6.4 KiB
1 year ago
|
<template>
|
||
|
<div
|
||
|
class="el-progress"
|
||
|
:class="[
|
||
|
'el-progress--' + type,
|
||
|
status ? 'is-' + status : '',
|
||
|
{
|
||
|
'el-progress--without-text': !showText,
|
||
|
'el-progress--text-inside': textInside,
|
||
|
}
|
||
|
]"
|
||
|
role="progressbar"
|
||
|
:aria-valuenow="percentage"
|
||
|
aria-valuemin="0"
|
||
|
aria-valuemax="100"
|
||
|
>
|
||
|
<div class="el-progress-bar" v-if="type === 'line'">
|
||
|
<div class="el-progress-bar__outer" :style="{height: strokeWidth + 'px'}">
|
||
|
<div class="el-progress-bar__inner" :style="barStyle">
|
||
|
<div class="el-progress-bar__innerText" v-if="showText && textInside">{{content}}</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="el-progress-circle" :style="{height: width + 'px', width: width + 'px'}" v-else>
|
||
|
<svg viewBox="0 0 100 100">
|
||
|
<path
|
||
|
class="el-progress-circle__track"
|
||
|
:d="trackPath"
|
||
|
stroke="#e5e9f2"
|
||
|
:stroke-width="relativeStrokeWidth"
|
||
|
fill="none"
|
||
|
:style="trailPathStyle"></path>
|
||
|
<path
|
||
|
class="el-progress-circle__path"
|
||
|
:d="trackPath"
|
||
|
:stroke="stroke"
|
||
|
fill="none"
|
||
|
:stroke-linecap="strokeLinecap"
|
||
|
:stroke-width="percentage ? relativeStrokeWidth : 0"
|
||
|
:style="circlePathStyle"></path>
|
||
|
</svg>
|
||
|
</div>
|
||
|
<div
|
||
|
class="el-progress__text"
|
||
|
v-if="showText && !textInside"
|
||
|
:style="{fontSize: progressTextSize + 'px'}"
|
||
|
>
|
||
|
<template v-if="!status">{{content}}</template>
|
||
|
<i v-else :class="iconClass"></i>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
<script>
|
||
|
export default {
|
||
|
name: 'ElProgress',
|
||
|
props: {
|
||
|
type: {
|
||
|
type: String,
|
||
|
default: 'line',
|
||
|
validator: val => ['line', 'circle', 'dashboard'].indexOf(val) > -1
|
||
|
},
|
||
|
percentage: {
|
||
|
type: Number,
|
||
|
default: 0,
|
||
|
required: true,
|
||
|
validator: val => val >= 0 && val <= 100
|
||
|
},
|
||
|
status: {
|
||
|
type: String,
|
||
|
validator: val => ['success', 'exception', 'warning'].indexOf(val) > -1
|
||
|
},
|
||
|
strokeWidth: {
|
||
|
type: Number,
|
||
|
default: 6
|
||
|
},
|
||
|
strokeLinecap: {
|
||
|
type: String,
|
||
|
default: 'round'
|
||
|
},
|
||
|
textInside: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
width: {
|
||
|
type: Number,
|
||
|
default: 126
|
||
|
},
|
||
|
showText: {
|
||
|
type: Boolean,
|
||
|
default: true
|
||
|
},
|
||
|
color: {
|
||
|
type: [String, Array, Function],
|
||
|
default: ''
|
||
|
},
|
||
|
format: Function
|
||
|
},
|
||
|
computed: {
|
||
|
barStyle() {
|
||
|
const style = {};
|
||
|
style.width = this.percentage + '%';
|
||
|
style.backgroundColor = this.getCurrentColor(this.percentage);
|
||
|
return style;
|
||
|
},
|
||
|
relativeStrokeWidth() {
|
||
|
return (this.strokeWidth / this.width * 100).toFixed(1);
|
||
|
},
|
||
|
radius() {
|
||
|
if (this.type === 'circle' || this.type === 'dashboard') {
|
||
|
return parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10);
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
},
|
||
|
trackPath() {
|
||
|
const radius = this.radius;
|
||
|
const isDashboard = this.type === 'dashboard';
|
||
|
return `
|
||
|
M 50 50
|
||
|
m 0 ${isDashboard ? '' : '-'}${radius}
|
||
|
a ${radius} ${radius} 0 1 1 0 ${isDashboard ? '-' : ''}${radius * 2}
|
||
|
a ${radius} ${radius} 0 1 1 0 ${isDashboard ? '' : '-'}${radius * 2}
|
||
|
`;
|
||
|
},
|
||
|
perimeter() {
|
||
|
return 2 * Math.PI * this.radius;
|
||
|
},
|
||
|
rate() {
|
||
|
return this.type === 'dashboard' ? 0.75 : 1;
|
||
|
},
|
||
|
strokeDashoffset() {
|
||
|
const offset = -1 * this.perimeter * (1 - this.rate) / 2;
|
||
|
return `${offset}px`;
|
||
|
},
|
||
|
trailPathStyle() {
|
||
|
return {
|
||
|
strokeDasharray: `${(this.perimeter * this.rate)}px, ${this.perimeter}px`,
|
||
|
strokeDashoffset: this.strokeDashoffset
|
||
|
};
|
||
|
},
|
||
|
circlePathStyle() {
|
||
|
return {
|
||
|
strokeDasharray: `${this.perimeter * this.rate * (this.percentage / 100) }px, ${this.perimeter}px`,
|
||
|
strokeDashoffset: this.strokeDashoffset,
|
||
|
transition: 'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease'
|
||
|
};
|
||
|
},
|
||
|
stroke() {
|
||
|
let ret;
|
||
|
if (this.color) {
|
||
|
ret = this.getCurrentColor(this.percentage);
|
||
|
} else {
|
||
|
switch (this.status) {
|
||
|
case 'success':
|
||
|
ret = '#13ce66';
|
||
|
break;
|
||
|
case 'exception':
|
||
|
ret = '#ff4949';
|
||
|
break;
|
||
|
case 'warning':
|
||
|
ret = '#e6a23c';
|
||
|
break;
|
||
|
default:
|
||
|
ret = '#20a0ff';
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
},
|
||
|
iconClass() {
|
||
|
if (this.status === 'warning') {
|
||
|
return 'el-icon-warning';
|
||
|
}
|
||
|
if (this.type === 'line') {
|
||
|
return this.status === 'success' ? 'el-icon-circle-check' : 'el-icon-circle-close';
|
||
|
} else {
|
||
|
return this.status === 'success' ? 'el-icon-check' : 'el-icon-close';
|
||
|
}
|
||
|
},
|
||
|
progressTextSize() {
|
||
|
return this.type === 'line'
|
||
|
? 12 + this.strokeWidth * 0.4
|
||
|
: this.width * 0.111111 + 2 ;
|
||
|
},
|
||
|
content() {
|
||
|
if (typeof this.format === 'function') {
|
||
|
return this.format(this.percentage) || '';
|
||
|
} else {
|
||
|
return `${this.percentage}%`;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
methods: {
|
||
|
getCurrentColor(percentage) {
|
||
|
if (typeof this.color === 'function') {
|
||
|
return this.color(percentage);
|
||
|
} else if (typeof this.color === 'string') {
|
||
|
return this.color;
|
||
|
} else {
|
||
|
return this.getLevelColor(percentage);
|
||
|
}
|
||
|
},
|
||
|
getLevelColor(percentage) {
|
||
|
const colorArray = this.getColorArray().sort((a, b) => a.percentage - b.percentage);
|
||
|
|
||
|
for (let i = 0; i < colorArray.length; i++) {
|
||
|
if (colorArray[i].percentage > percentage) {
|
||
|
return colorArray[i].color;
|
||
|
}
|
||
|
}
|
||
|
return colorArray[colorArray.length - 1].color;
|
||
|
},
|
||
|
getColorArray() {
|
||
|
const color = this.color;
|
||
|
const span = 100 / color.length;
|
||
|
return color.map((seriesColor, index) => {
|
||
|
if (typeof seriesColor === 'string') {
|
||
|
return {
|
||
|
color: seriesColor,
|
||
|
percentage: (index + 1) * span
|
||
|
};
|
||
|
}
|
||
|
return seriesColor;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
</script>
|