<template>
	<view class="gauge-box" :style="{'background-color': bgColor}">
		<canvas :canvas-id="config.id" :style="{'width' : _width + 'px','height' : _width + 'px'}"></canvas>
	</view>
</template>

<script>
	const mainDefault = {
		bgColor: 'rgba(30,130,250,1)',
		startAngle: 0.75,
		endAngle: 0.25,
		width: uni.upx2px(350),
		padding: 10,
		min: 0,
		max: 100,
		value: 0,
		unit: '℃',
		name: 'CK01排风温度显示',
		detail: {},
		axisTick: []
	};
	const detailDefault = { //标题、数值、单位设置
		title: { //name字体位置设置
			offsetCenter: [0, uni.upx2px(160)], //距离圆心直径偏移
			color: '#A9CCFD',
			fontSize: uni.upx2px(28),
			fontWeight: 'normal',
			textAlign: 'center'
		},
		value: {
			color: '#FFFFFF',
			fontSize: uni.upx2px(48),
			fontWeight: 'bolder',
			offsetCenter: [-10, uni.upx2px(15)], //距离圆心直径偏移
			textAlign: 'center'
		},
		unit: {
			color: '#FFFFFF',
			fontSize: uni.upx2px(48),
			fontWeight: 'normal',
			offsetCenter: [0, uni.upx2px(15)], //距离圆心直径偏移
			textAlign: 'center'
		}
	};
	const axisTickDefault = { //轴刻度线
		width: uni.upx2px(25), //轴长
		number: 6, //轴数量（相当于几等分）
		color: '#33ff33,#ff9933', //轴颜色(第一个值--指针之前的颜色，之后的颜色)
		subNumber: 10, //一个大刻度分成几个小刻度
		subWidth: uni.upx2px(25),
		subHeight: 1,
		padding: uni.upx2px(10) //刻度距离边距
	};
	const axisTickDefaultSmall = { //轴刻度线(里圈)
		width: uni.upx2px(10), //轴长
		number: 6, //轴数量（相当于几等分）
		color: '#33ff33,#ff9933', //轴颜色(第一个值--指针之前的颜色，之后的颜色)
		subNumber: 10, //大刻度之间分成几个小刻度
		subWidth: uni.upx2px(6),
		subHeight: 1,
		padding: uni.upx2px(25) //刻度距离边距
	};
	export default {
		data: function() {
			return {
				gaugeOption: {}
			}
		},
		props: {
			config: {
				type: Object,
				default: () => {
					return {};
				}
			},
			bgColor: {
				type: String,
				default: 'linear-gradient(180deg, #2A8FFB 0%, #0467FB 100%)',

			}
		},
		computed: {
			_width: function() {
				return this.config.width || mainDefault.width
			},
			_status: function() {
				return String(this.config.status) !== 'false' ? true : false;
			},
			_dStatus: function() {
				return String(this.config.status) === 'true' || this.config.status === 1 ? 1 : 0;
			}
		},
		watch: {
			config: {
				handler(newVal, oldVal) {
					this.initCharts();
				},
				deep: true
			}
		},
		mounted: function() {
			this.initCharts();
		},
		methods: {
			initCharts: function() {
				// 自动填充数据
				var gaugeOption = this.fillInData();
				var uChartsGauge = null;
				uChartsGauge = uni.createCanvasContext(gaugeOption.id, this);
				uChartsGauge.fillStyle = gaugeOption.bgColor;
				uChartsGauge.fillRect(0, 0, gaugeOption.width, gaugeOption.width);
				uChartsGauge.save();
				this.drawGauge(gaugeOption, uChartsGauge);
			},
			drawGauge: function(options, ctx) {
				var centerPosition = {
					x: options.width / 2,
					y: options.width / 2
				};
				// 总角度数（为什么要加1）假装下图是个圆  0.75PI ~ 0.25PI 实际间隔1.5PI 
				//   1.5PI
				//     ——
			 // 1.0PI	|	   |  0PI
				//     ——
				//   0.5PI
				var totalAngle = options.startAngle - options.endAngle + 1;
				// 计算半径
				var radius = Math.min(centerPosition.x, centerPosition.y);

				//画刻度线
				for (let idx = 0, len = options.axisTick.length; idx < len; idx++) {
					var gaugeOption = options.axisTick[idx];
					radius -= (gaugeOption.padding + gaugeOption.width / 2);
					var criticalPoint = Math.floor(options.value / (options.max / gaugeOption.number)); //大刻度临界点
					var subCriticalPoint = Math.floor(options.value / (options.max / gaugeOption.subNumber /
						gaugeOption.number)); //小刻度临界点
					if (options.value * 1 === 0) {
						criticalPoint = -1; //防止0的时候被上颜色
						subCriticalPoint = -1;
					}
					var colors = gaugeOption.color.split(',');
					colors[1] = colors[1] || colors[0];
					var splitAngle = totalAngle / gaugeOption.number;
					var childAngle = totalAngle / gaugeOption.number / gaugeOption.subNumber;
					var startX = -radius - gaugeOption.width * 0.5;
					var endX = -radius - gaugeOption.width * 0.5 + gaugeOption.width;
					var childEndX = -radius - gaugeOption.width * 0.5 + gaugeOption.subWidth;

					// 画大刻度
					let maxScaleData = {
						...centerPosition,
						startX,
						endX,
						splitAngle,
						criticalPoint,
						colors,
						startAngle: options.startAngle,
						width: gaugeOption.subHeight,
						number: gaugeOption.number,
					}
					this.drawScale(ctx, maxScaleData);

					// 画小刻度
					let minScaleData = {
						...centerPosition,
						startX,
						colors,
						criticalPoint: subCriticalPoint,
						endX: childEndX,
						splitAngle: childAngle,
						startAngle: options.startAngle,
						width: gaugeOption.subHeight,
						number: gaugeOption.number * gaugeOption.subNumber,
					}
					this.drawScale(ctx, minScaleData);
				}
				// 标题
				var titleObj = {
					...options.detail.title,
					...centerPosition,
					name: options.name
				}
				this.drawText(ctx, titleObj);

				// 数值
				var _fillText = (options.value * 1) === 0 ? 0 : (options.value * 1).toFixed(1);
				var valueObj = {
					...options.detail.value,
					...centerPosition,
					name: _fillText
				}
				this.drawText(ctx, valueObj);

				// 单位
				if (String(options.unit) !== 'false') {
					let unitObj = {
						...options.detail.unit,
						...centerPosition,
						name: options.unit
					}
					var valueLength = (options.value * 1).toFixed(1).length;
					var _oftX = ((valueLength - 1.5) / 2) * valueObj.fontSize; //需要保证单位在数值后面
					unitObj.offsetCenter[0] += _oftX;
					this.drawText(ctx, unitObj);
				}

				ctx.draw();
			},
			// 画字
			drawText: function(ctx, data) {
				let {
					fontSize,
					fontWeight,
					color,
					textAlign,
					offsetCenter,
					x,
					y,
					name
				} = data;
				// 画标题
				ctx.beginPath();
				// 设置字体
				ctx.font = fontWeight + " " + fontSize + "px MicrosoftYaHei";
				// 设置颜色
				ctx.fillStyle = color;
				// 设置水平对齐方式
				ctx.textAlign = textAlign;
				// 设置中心点
				ctx.translate(x, y);
				// 绘制文字（参数：要写的字，x坐标，y坐标）
				ctx.fillText(name, ...offsetCenter);
				ctx.closePath();
				ctx.stroke();
				ctx.restore();
				ctx.save();
			},
			// 画刻度
			drawScale: function(ctx, data) {
				let {
					number,
					criticalPoint,
					startX,
					endX,
					splitAngle,
					width,
					x,
					y,
					startAngle,
					colors
				} = data;
				// 设置中心点
				ctx.translate(x, y);
				ctx.rotate((startAngle - 1) * Math.PI);
				for (let i = 0; i <= number; i++) {
					ctx.beginPath();
					ctx.setStrokeStyle(i <= criticalPoint ? colors[0] : colors[1]);
					ctx.setLineWidth(width);
					ctx.moveTo(startX, 0);
					ctx.lineTo(endX, 0);
					ctx.stroke();
					ctx.rotate(splitAngle * Math.PI);
				}
				// 清除状态
				ctx.restore();
				ctx.save();
			},
			fillInData: function() {
				var gaugeOption = this.deepClone(mainDefault, this.config);
				for (var _k in detailDefault) {
					gaugeOption.detail[_k] = this.deepClone(detailDefault[_k], gaugeOption.detail[_k])
				}
				if (gaugeOption.axisTickLength === undefined || gaugeOption.axisTickLength === null) {
					if (!(gaugeOption.axisTick instanceof Array)) {
						gaugeOption.axisTick = [gaugeOption.axisTick]
					}
				} else {
					gaugeOption.axisTick = gaugeOption.axisTick || [];
				}
				var axisTickLength = gaugeOption.axisTickLength || gaugeOption.axisTick.length || 1;
				var axisTick = [].concat(gaugeOption.axisTick);
				for (var idx = 0, len = axisTickLength; idx < len; idx++) {
					var defaultData = idx == 0 ? axisTickDefault : axisTickDefaultSmall;
					axisTick[idx] = axisTick[idx] || {};
					if (idx > 0 && !axisTick[idx].padding) {
						axisTick[idx].padding = +axisTick[idx - 1].width;
					}
					axisTick[idx] = this.deepClone(defaultData, axisTick[idx]);
				}
				gaugeOption.axisTick = axisTick
				return gaugeOption;
			},
			deepClone: function(source, target) { //待优化代码
				var _obj = {};
				source = source || {};
				target = target || {};
				Object.assign(_obj, source, target);
				return JSON.parse(JSON.stringify(_obj));
			}
		}
	};
</script>

<style>
	.gauge-box {
		position: relative;
		width: 360rpx;
		height: 180rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		text-align: center;
	}

	.gauge-box canvas {
		width: 100%;
		margin: 0 auto;
		height: auto;
		display: block;
	}
</style>
