template>
<div class="circle-wrapper">
<canvas id="canvas"></canvas>
</div>
</template>
<script>
export default {
mounted() {
this.percent = this.options.percent;
this.radius = this.options.radius;
this.width = this.options.width;
this.height = this.options.height;
this.externalHeight = parseInt(this.width / 9) || 0;
this.initCircle();
},
data() {
return {
pointColor: "rgba(255,144,55,1)", // 中心红点
percent: 0,
radius: 0,
width: 0,
height: 0,
externalHeight: 0,
};
},
props: {
options: {
type: Object,
default: {
percent: 0,
radius: 0,
width: 0,
height: 0,
},
},
startGradient: {
type: Boolean,
default: false,
}, // 开启渐变进度条
hasProgress: {
type: Boolean,
default: true,
}, // 开启进度条
traceColor: {
type: String,
default: "rgba(255,255,255,0.1)",
}, // 外部整个无轨道的颜色
coverColor1: {
type: String,
default: "rgba(255,255,255,0.5)",
}, //轨道渐变的颜色1
coverColor2: {
type: String,
default: "rgba(255,255,255,0.5)",
},
coverColor3: {
type: String,
default: "rgba(255,255,255,1)",
},
stopBgCircle: {
type: String,
default: "rgba(255,255,255)",
},
hasProgress: {
type: Boolean,
default: true,
}, // 开启进度条
hasPoint: {
type: Boolean,
default: true,
}, // 是否有中心小红点
hasCircle: {
type: Boolean,
default: true,
},
hasOutCircle: {
type: Boolean,
default: true,
}, //是否有外部圆
hasGradientCircle: {
type: Boolean,
default: true,
}, //是否有轨道渐变圆
runtime: "", //轨迹运动总时间
},
methods: {
draw(percent, sR0) {
if (this.percent < 0 || this.percent > 100) {
return;
}
if (sR0 < Math.PI / 2 || sR0 >= (3 / 2) * Math.PI) {
return;
}
let canvas = document.getElementById("canvas");
let cxt = canvas.getContext("2d");
canvas.style.width = this.width + "px";
//解决canvas 锯齿问题
let dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
// 渐变进度条颜色
canvas.width = this.width * dpr;
canvas.height = (this.height + this.externalHeight) * dpr;
//
cxt.scale(dpr, dpr);
let gradient = cxt.createLinearGradient(0, 0, 170, 0);
gradient.addColorStop(0, this.coverColor1);
gradient.addColorStop(0.3, this.coverColor2);
gradient.addColorStop(1, this.coverColor3);
let cW = this.width,
cH = this.height * 2,
PI = Math.PI,
sR = sR0 || (1 / 2) * PI;
let finalRadian = sR + ((PI + (PI - sR) * 2) * this.percent) / 100;
let stepBase = 50;
if (this.percent < 10) {
stepBase = 1000;
} else if (this.percent >= 10 && this.percent < 20) {
stepBase = 500;
}
let step = (PI + (PI - sR) * 2) / stepBase; // 走的步骤
let text = 0;
let that = this;
let birthday = new Date();
let timer = setInterval(function () {
cxt.clearRect(0, 0, cW, cH);
let endRadian = sR + text * step;
// 轨道trace
that.drawCanvas(cW / 2, cH / 2, that.radius, sR, sR + (PI + (PI - sR) * 2), that.traceColor, 9);
if (that.percent) {
// 进度条 progess
if (that.hasProgress) {
that.drawCanvas(cW / 2, cH / 2, that.radius, sR, endRadian, gradient, 9);
}
let angle = 2 * PI - endRadian,
xPos = Math.cos(angle) * that.radius + cW / 2,
yPos = -Math.sin(angle) * that.radius + cH / 2;
if (that.hasCircle) {
// 外部小白圆
that.drawCanvas(xPos, yPos, 3, 0, 2 * PI, that.stopBgCircle, 0);
}
if (that.hasPoint) {
// 中心红点
that.drawCanvas(xPos, yPos, 1, 0, 2 * PI, that.pointColor, 1, "fill");
}
if (that.hasOutCircle) {
// 最外部圆
that.drawCanvas(xPos, yPos, 9, 0, 2 * PI, that.coverColor2, 9);
}
// 圆形渐变
if (that.hasGradientCircle) {
let radialGrad = cxt.createRadialGradient(300, 300, 0, 300, 300, 500);
radialGrad.addColorStop(0, "rgba(255,255,255,0.3)");
radialGrad.addColorStop(0.3, "rgba(255,227,72,0.2)");
radialGrad.addColorStop(1, "rgba(255,227,72,0.1)");
// 最外部黄色
that.drawCanvas(xPos, yPos, 14, 0, 2 * PI, radialGrad, 13);
}
} else {
clearInterval(timer);
}
if (endRadian.toFixed(2) >= finalRadian.toFixed(2)) {
clearInterval(timer);
}
text = text + 1;
}, 20);
},
drawCanvas(x, y, r, sRadian, eRadian, color, lineWidth, circleType) {
let cxt = canvas.getContext("2d");
cxt.beginPath();
if (circleType == "fill") {
cxt.fillStyle = color;
cxt.arc(x, y, r, sRadian, eRadian);
cxt.fill();
} else {
cxt.lineCap = "round";
cxt.strokeStyle = color;
cxt.lineWidth = lineWidth;
cxt.arc(x, y, r, sRadian, eRadian);
cxt.stroke();
}
},
initCircle() {
this.draw(this.percent, Math.PI); // 半圆PI 全圆 (1 / 2) * PI
},
},
};
</script>
<style lang="scss">
.circle-wrapper {
width: 100%;
canvas {
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%, 0);
}
}
</style>