使用Echarts3实现渐变仪表盘需求

Echarts 仪表盘实践

项目过程当中遇到一个这样的需求:javascript

图片描述

这明显是一个仪表盘类型的图表,打开echarts的官方文档,能够看到有一个默认的实现,以下:java

图片描述

使用了默认的参数echarts

option = {
    tooltip : {
        formatter: "{a} <br/>{b} : {c}%"
    },
    toolbox: {
        feature: {
            restore: {},
            saveAsImage: {}
        }
    },
    series: [
        {
            name: '业务指标',
            type: 'gauge',
            detail: {formatter:'{value}%'},
            data: [{value: 50, name: '完成率'}]
        }
    ]
};

分析需求后,咱们从如下几个方面入手spa

轴线类别

从第一张图咱们能够看出,需求中的轴线不是连续的,而是被分割成了一个个的长条形状。3d

从官方示例来看,轴线被白色的刻度分红了不少小段,若是刻度的宽度变大,刻度变密集的话是能够达到咱们想要的效果的指针

option = {
    ...
    series: [
        {
            name: '业务指标',
            type: 'gauge',
            // 去掉多余的分段
            splitNumber: 1,
            axisLine: {
                lineStyle: {
                    width: 20
                }
            },
            splitLine: {
                show: false
            },
            axisTick: {
                // 刻度长度与轴线宽度一致,达到分隔的效果
                length: 20,
                // 增长刻度密度
                splitNumber: 100,
                lineStyle: {
                    // 增长刻度宽度
                    width: 3
                }
            },
            detail: {formatter:'{value}%'},
            data: [{value: 50, name: '完成率'}]
        }
    ]
};

通过这样修改的话,确实初步达到了咱们要的效果。rest

图片描述

可是仔细看的话,会发现一个问题,指针的指向是空白处。缘由就是空白的地方是刻度,而有颜色的地方是轴线。
这样的话最终指针指向的数据是不许确的,并且这个方案还有一个问题就是渐变颜色的处理。code

[[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']]

官方提供的接口是分段颜色,想要作成渐变还不是很好处理。orm

接下来呢,考虑第二种实现方式blog

首先,轴线确定是连续的,那我先把轴线隐藏掉,而后刻度加粗,拉长

option = {
    ...
    series: [
        {
            name: '业务指标',
            type: 'gauge',
            splitNumber: 1,
            axisLine: {
                lineStyle: {
                    width: 20,
                    // 透明度设置为0
                    opacity: 0
                }
            },
            splitLine: {
                show: false
            },
            axisTick: {
                length: 20,
                splitNumber: 100,
                lineStyle: {
                    width: 3,
                    // 给点颜色
                    color: '#555'
                }
            },
            detail: {formatter:'{value}%'},
            data: [{value: 50, name: '完成率'}]
        }
    ]
};

图片描述

能够看到效果有了,并且指针位置正确。

渐变颜色

需求中轴线的颜色是渐变的,可是文档中给定的接口是分段式的颜色,没有办法使用,再者轴线透明度已经被设置为0了。

因此只能从刻度的颜色入手。

官方文档中,刻度的颜色是以下这样的:

// 线性渐变,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,至关于在图形包围盒中的百分比,若是 globalCoord 为 `true`,则该四个值是绝对的像素位置
color: {
    type: 'linear',
    x: 0,
    y: 0,
    x2: 0,
    y2: 1,
    colorStops: [{
        offset: 0, color: 'red' // 0% 处的颜色
    }, {
        offset: 1, color: 'blue' // 100% 处的颜色
    }],
    globalCoord: false // 缺省为 false
}
// 径向渐变,前三个参数分别是圆心 x, y 和半径,取值同线性渐变
color: {
    type: 'radial',
    x: 0.5,
    y: 0.5,
    r: 0.5,
    colorStops: [{
        offset: 0, color: 'red' // 0% 处的颜色
    }, {
        offset: 1, color: 'blue' // 100% 处的颜色
    }],
    globalCoord: false // 缺省为 false
}
// 纹理填充
color: {
    image: imageDom, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
    repeat: 'repeat' // 是否平铺, 能够是 'repeat-x', 'repeat-y', 'no-repeat'
}

默认支持两种渐变,线性和径向渐变,从效果上看都不符合咱们的要求:线性是直线方向的渐变,而径向渐变是由内而外的。即便能够勉强实现,效果确定很差。
因此能够尝试一下使用图片纹理。

首先用PS画一个和画布同样大小的渐图案

图片描述

在配置中使用image选项

option = {
    ...
    series:[{
        ...
        axisTick: {
            length: 20,
            splitNumber: 100,
            lineStyle: {
                color: {
                    image: document.getElementById('linear-pic'),
                    repeat: 'no-repeat'
                },
                width: 3
            }
        }
    }]

这样项目中的需求就能够完美解决了

图片描述

颜色分段

颜色渐变完成了,看一下效果的话,会发现有一个明显的问题。需求中指针指向的位置以前的刻度是有渐变颜色的,后面一段则都是灰色。
而咱们如今仪表盘不管指向哪里,刻度都是有颜色的。

在解决这个问题的过程当中,想了不少方案,使用遮罩、修改渐变图片等等,都不能很好的解决问题。最后忽然想起来一个配置项中可使用多个仪表盘的,
我只要在数据前半段使用带渐变色的仪表盘,后半段所有用灰色的仪表盘补充,这样就能够解决问题。

这里还须要注意如下两点:

  1. 因为仪表盘的值是动态的,因此每一个仪表盘的开始结束位置、刻度的个数都要根据值来计算
  2. 因为有两个仪表盘,最好把内容部分所有都写在一个上,另一个确保只有轴线部分,避免出现重叠等问题

代码以下:

calculateOption: function (params) {
    var offsetAngle = -35;
    var totalAngle = 250;
    var split = 75;
    var series = [];
    var asisWidth = 11;
    var fontSize = 30;

    // Defaults
    params = $.extend({
        min: 0,
        max: 100,
        value: 0,
        name: 'DOWNLOAD SPEED',
        type: 'gauge',
        data: [{
            value: 0,
            name: ''
        }]
    }, params);

    var startAngle = totalAngle + offsetAngle;
    var endAngle = startAngle - Math.floor((parseInt(params.value, 10) / (params.max - params.min)) * totalAngle);

    series.push({
        name: params.name,
        type: params.type,
        startAngle: startAngle,
        endAngle: endAngle,
        splitNumber: 1,
        // 轴线样式
        axisLine: {
            show: false,
            lineStyle: {
                width: asisWidth,
                opacity: 0
            }
        },
        // 分段样式
        splitLine: { show: false },
        // 刻度样式
        axisTick: {
            length: asisWidth,
            splitNumber: Math.floor((params.value / (params.max - params.min)) * split),
            lineStyle: {
                color: {
                    image: $('#xx')[0],
                    repeat: 'no-repeat'
                },
                width: 2
            }
        },
        axisLabel: { show: false },
        pointer: { show: false },
        // 指针样式
        itemStyle: {},
        title: {
            fontSize: 8,
            offsetCenter: [0, '-35%'],
            color: '#999'
        },
        detail: {
            color: '#36444b',
            fontSize: fontSize,
            offsetCenter: [0, '20%'],
            formatter: function (val) {
                return val.toFixed(2) + '\n{unit|Mbps}'
            },
            rich: {
                unit: {
                    fontSize: 10,
                    color: '#999',
                    lineHeight: 30
                }
            }
        },
        data: [{
            value: params.value,
            name: params.name
        }]
    });
    series.push({
        name: '',
        type: params.type,
        startAngle: endAngle,
        endAngle: offsetAngle,
        splitNumber: 1,
        axisLine: {
            show: false,
            lineStyle: {
                width: asisWidth,
                opacity: 0
            }
        },
        splitLine: { show: false },
        axisTick: {
            length: asisWidth,
            splitNumber: split - Math.floor((params.value / (params.max - params.min)) * 80),
            lineStyle: {
                color: '#999',
                width: 2
            }
        },
        axisLabel: { show: false },
        pointer: { show: false },
        // 指针样式
        itemStyle: {},
        title: { show: false },
        detail: { show: false }
    });
    return series;
}

效果以下:

图片描述

指针类型

最后,咱们须要作的就是把指针改成需求中的样子,原本我觉得这个应该是最简单的部分,看完官方文档后发现并无修改指针的接口。

{
    color: 'auto',
    borderColor: '#000',
    borderWidth: 0,
    borderType: 'solid',
    shadowBlur: ...,
    shadowColor: ...,
    shadowOffsetX: 0,
    shadowOffsetY: 0,
    opacity: ...
}

如上,指针配置项应该是没有办法实现相似刻度的样子。

目前还在实验中,考虑使用markline画一条指针,是否可行还有待验证。

相关文章
相关标签/搜索