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
