使用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畫一條指針,是否可行還有待驗證。

相關文章
相關標籤/搜索