123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- class Gauge {
- constructor({
- canvasId,
- startAngle = 3 / 4 * Math.PI, // 135
- endAngle = 1 / 4 * Math.PI, // 45
- width = 200,
- min = 0,
- max = 100,
- value = 0,
- unit = '%',
- showTick = false,
- valueColor = '#555',
- progressColor = '#f58220',
- trackColor = '#F1F1F1',
- lineWidth = 10
- }) {
- this.ctx = uni.createCanvasContext(canvasId)
- this.startAngle = startAngle
- this.endAngle = endAngle
- this.width = width
- this.min = min
- this.max = max
- this.value = value
- this.unit = unit
- this.showTick = showTick
- this.valueColor = valueColor
- this.progressColor = progressColor
- this.trackColor = trackColor
- // track width
- this.lineWidth = lineWidth
- this.radius = this.width / 2
- this.process = min || -1
- this.tickLength = this.max - this.min
- // track radius
- this.trackRadius = this.radius - this.lineWidth / 2
- // one tick rad
- this.tickRad = (2 * Math.PI - this.startAngle + this.endAngle) / this.tickLength
- this.start()
- }
- draw() {
- // 将坐标中心点移动到圆心位置
- this.ctx.translate(this.radius, this.radius)
- this.drawTrack()
- this.drawValueText()
- this.drawProgress()
- if (this.showTick) {
- this.drawTick()
- this.drawTickText()
- }
- this.ctx.draw()
- }
- // 轨迹圆环
- drawTrack() {
- this.ctx.save()
- this.ctx.lineWidth = this.lineWidth
- // this.ctx.lineCap = 'round'
- this.ctx.strokeStyle = this.trackColor
- this.ctx.arc(0, 0, this.trackRadius, this.startAngle, this.endAngle)
- this.ctx.stroke()
- this.ctx.restore()
- }
- // 当前值显示
- drawValueText() {
- this.ctx.save()
- this.ctx.fillStyle = this.valueColor
- this.ctx.font = "34px serif"
- this.ctx.textAlign = 'center'
- this.ctx.textBaseline = 'middle'
- this.ctx.fillText(`${this.value}${this.unit}`, 0, 0)
- this.ctx.restore()
- }
- // 进度圆环
- drawProgress() {
- this.ctx.save()
- const valueRad = this.getValueRad()
- this.ctx.beginPath()
- this.ctx.lineWidth = this.lineWidth
- this.ctx.strokeStyle = typeof this.progressColor === 'string' ? this.progressColor : this.getGradient(this.progressColor)
- // this.ctx.lineCap = 'round' // 会导致进度条加长
- this.ctx.lineJoin = 'round'
- // 终点角度是动态的
- this.ctx.arc(0, 0, this.trackRadius, this.startAngle, valueRad)
- this.ctx.stroke()
- this.ctx.restore()
- }
- // 刻度线
- drawTick() {
- // 不可是使用旋转,否则文字也会旋转
- let deg = this.startAngle
- for (let i = this.min; i <= this.max; i++) {
- this.ctx.save()
- this.ctx.lineWidth = 1
- this.ctx.strokeStyle = '#999'
- this.ctx.beginPath()
- // 刻度起点
- let x0 = (this.radius - this.lineWidth - 2) * Math.cos(deg)
- let y0 = (this.radius - this.lineWidth - 2) * Math.sin(deg)
- // 刻度终点
- var x1 = (this.radius - this.lineWidth - 8) * Math.cos(deg)
- var y1 = (this.radius - this.lineWidth - 8) * Math.sin(deg)
- this.ctx.moveTo(x0, y0)
- this.ctx.lineTo(x1, y1)
- deg += this.tickRad
- this.ctx.stroke()
- this.ctx.restore()
- }
- }
- // 刻度值
- drawTickText() {
- let deg = this.startAngle
- for (let i = this.min; i <= this.max; i++) {
- let x = (this.radius - this.lineWidth - 20) * Math.cos(deg)
- let y = (this.radius - this.lineWidth - 20) * Math.sin(deg)
- deg += this.tickRad
- this.ctx.save()
- this.ctx.font = '12px serif'
- this.ctx.fillStyle = '#999'
- this.ctx.textAlign = 'center'
- // 不设置会与tick错位
- this.ctx.textBaseline = 'middle'
- this.ctx.fillText(i, x, y)
- this.ctx.restore()
- }
- }
- // 当前值的弧度
- getValueRad() {
- // 超出
- if (this.value > this.max) {
- return (this.max - this.min) * this.tickRad + this.startAngle
- }
- return (this.process - this.min) * this.tickRad + this.startAngle
- }
- start() {
- let update = () => {
- this.process = this.process + (this.max - this.min) / 100
- if (this.process > this.value) {
- cancelAnimationFrame(update)
- } else {
- this.draw()
- requestAnimationFrame(update)
- }
- }
- requestAnimationFrame(update)
- }
- // 渐变
- getGradient(colorList) {
- let grd = this.ctx.createLinearGradient(0, 0, this.trackRadius, 0)
- colorList.forEach((color, index) => {
- grd.addColorStop(index / (colorList.length - 1), color)
- })
- return grd
- }
- }
- // https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
- (function () {
- var lastTime = 0;
- var vendors = ['webkit', 'moz'];
- for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
- window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
- window.cancelAnimationFrame =
- window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
- }
- if (!window.requestAnimationFrame)
- window.requestAnimationFrame = function (callback, element) {
- var currTime = new Date().getTime();
- var timeToCall = Math.max(0, 16 - (currTime - lastTime));
- var id = window.setTimeout(function () { callback(currTime + timeToCall); },
- timeToCall);
- lastTime = currTime + timeToCall;
- return id;
- };
- if (!window.cancelAnimationFrame)
- window.cancelAnimationFrame = function (id) {
- clearTimeout(id);
- };
- }());
- export default Gauge
|