123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- <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>
|