codecamp

ECharts 自定义系列

什么是 ECharts 自定义系列?


自定义系列(custom series)是一种系列的类型,它能够让用户定制渲染逻辑,在已有的坐标系中创造新的图表;并且增强了极坐标柱状图、自定义维度映射、dataZoom 等 。

自定义系列(custom series)它把绘制图形元素这一步留给开发者去做,从而开发者能在坐标系中自由绘制出自己需要的图表。

ECharts 为什么会支持自定义系列?

由于图表的类型多种多样,要让 ECharts 内置支持所有类型的图表是很难的,有很多小众的需求 ECharts 并不能内置的支持。那么就需要提供一种方式来让开发者自己扩展。另一方面,所提供的扩展方式要尽可能得简单,例如图形元素创建和释放、过渡动画、tooltip、数据区域缩放(dataZoom)、视觉映射(visualMap)等功能,尽量在 ECharts 中内置得处理,使开发者不必纠结于这些细节。综上考虑形成了 自定义系列(custom series)。

例如,下面的例子使用自定义系列( custom series)扩展出了 x-range 图:

ECharts 使用自定义系列扩展 x-range 图

点击编辑实例 》》

下面来介绍开发者怎么使用自定义系列(custom series)。

(一)renderItem 方法


通过书写 renderItem 函数能够让开发者实现自定义的图形元素渲染逻辑,例如:

var option = {
    ...,
    series: [{
        type: 'custom',
        renderItem: function (params, api) {
            // ...
        },
        data: data
    }]
}

在渲染阶段,对于 series.data 中的每个数据项(为方便描述,这里称为 dataItem),会调用此 renderItem 函数。

renderItem 函数的作用:返回一个(或者一组)图形元素定义,图形元素定义了图形元素的类型、位置、尺寸、样式等。

ECharts 会根据这些 图形元素定义 来渲染出图形元素。如下述所示:

var option = {
    ...,
    series: [{
        type: 'custom',
        renderItem: function (params, api) {
            // 对于 data 中的每个 dataItem,都会调用这个 renderItem 函数。
            // (但是注意,并不一定是按照 data 的顺序调用)

            // 这里进行一些处理,例如,坐标转换。
            // 这里使用 api.value(0) 取出当前 dataItem 中第一个维度的数值。
            var categoryIndex = api.value(0);
            // 这里使用 api.coord(...) 将数值在当前坐标系中转换成为屏幕上的点的像素值。
            var startPoint = api.coord([api.value(1), categoryIndex]);
            var endPoint = api.coord([api.value(2), categoryIndex]);
            // 这里使用 api.size(...) 获得 Y 轴上数值范围为 1 的一段所对应的像素长度。
            var height = api.size([0, 1])[1] * 0.6;

            // 这里返回为这个 dataItem 构建的图形元素定义。
            return {
                // 表示这个图形元素是矩形。还可以是 'circle', 'sector', 'polygon' 等等。
                type: 'rect',
                // shape 属性描述了这个矩形的像素位置和大小。
                // 其中特殊得用到了 echarts.graphic.clipRectByRect,意思是,
                // 如果矩形超出了当前坐标系的包围盒,则剪裁这个矩形。
                shape: echarts.graphic.clipRectByRect({
                    // 矩形的位置和大小。
                    x: startPoint[0],
                    y: startPoint[1] - height / 2,
                    width: endPoint[0] - startPoint[0],
                    height: height
                }, {
                    // 当前坐标系的包围盒。
                    x: params.coordSys.x,
                    y: params.coordSys.y,
                    width: params.coordSys.width,
                    height: params.coordSys.height
                }),
                // 用 api.style(...) 得到默认的样式设置。这个样式设置包含了
                // option 中 itemStyle 的配置和视觉映射得到的颜色。
                style: api.style()
            };
        },
        data: [
            [12, 44, 55, 60], // 这是第一个 dataItem
            [53, 31, 21, 56], // 这是第二个 dataItem
            [71, 33, 10, 20], // 这是第三个 dataItem
            ...
        ]
    }]
}

renderItem 函数中包含两个参数:

  • params:包含了当前数据信息(如 seriesIndex、dataIndex 等等)和坐标系的信息(如坐标系包围盒的位置和尺寸)。
  • api:是一些开发者可调用的方法集合(如 api.value()、api.coord())。

renderItem 函数须返回根据此 dataItem 绘制出的图形元素的定义信息,参见 renderItem.return。

一般来说,renderItem 函数的主要逻辑,是将 dataItem 里的值映射到坐标系上的图形元素。这一般需要用到 renderItem.arguments.api 中的两个函数:

  • api.value(...),意思是取出 dataItem 中的数值。例如 api.value(0) 表示取出当前 dataItem 中第一个维度的数值。
  • api.coord(...),意思是进行坐标转换计算。例如 var point = api.coord([api.value(0), api.value(1)]) 表示 dataItem 中的数值转换成坐标系上的点。

有时候还需要用到 api.size(...) 函数,表示得到坐标系上一段数值范围对应的长度。

返回值中样式的设置可以使用 api.style(...) 函数,他能得到 series.itemStyle.normal 中定义的样式信息,以及视觉映射的样式信息。也可以用这种方式覆盖这些样式信息:api.style({fill: 'green', stroke: 'yellow'})。

renderItem 方法写完后,我们就完成了自定义系列 90% 的工作,接下来该对工作进行优化了。

(二)使坐标轴的范围自适应数据范围


直角坐标系(grid)和极坐标系(polar)中的坐标轴的刻度范围需要自适应当前显示出的数据的范围,否则绘制出的图形会超出去。

例如,在直角坐标系(grid)中,开发者如果使用自定义系列的话,就需要设定,data 中的哪些维度会对应到 x 轴上,哪些维度会对应到 y 轴上。

上述内容通过 encode 来设定。例如:

option = {
    series: [{
        type: 'custom',
        renderItem: function () {
            ...
        },
        encode: {
            // data 中『维度1』和『维度2』对应到 X 轴
            x: [1, 2],
            // data 中『维度0』对应到 Y 轴
            y: 0
        },
        data: [
            // 维度0  维度1  维度2  维度3
            [   12,   44,   55,   60   ], // 这是第一个 dataItem
            [   53,   31,   21,   56   ], // 这是第二个 dataItem
            [   71,   33,   10,   20   ], // 这是第三个 dataItem
            ...
        ]
    }]
};

(三)设定 tooltip


当然,使用 tooltip.formatter 可以任意定制 tooltip 中的内容。

但是,还有更简单的方法,即通过 encode 和 dimensions 来设定:

option = {
    series: [{
        type: 'custom',
        renderItem: function () {
            ...
        },
        encode: {
            x: [1, 2],
            y: 0,
            // 表示『维度2』和『维度3』要显示到 tooltip 中。
            tooltip: [2, 3]
        },
        // 表示给『维度2』和『维度3』分别取名为『年龄』和『满意度』,显示到 tooltip 中。
        dimensions: [null, null, '年龄', '满意度'],
        data: [
            // 维度0  维度1  维度2  维度3
            [   12,   44,   55,   60   ], // 这是第一个 dataItem
            [   53,   31,   21,   56   ], // 这是第二个 dataItem
            [   71,   33,   10,   20   ], // 这是第三个 dataItem
            ...
        ]
    }]
};

(四)其他注意事项


(1)与 dataZoom 结合使用的时候,常常使用会设置 dataZoom.filterMode 为 'weakFilter'。这个设置的意思是:当 dataItem 部分超出坐标系边界的时候,dataItem 不会整体被过滤掉。例如:

option = {
    dataZoom: {
        xAxisIndex: 0,
        filterMode: 'weakFilter'
    },
    series: [{
        type: 'custom',
        renderItem: function () {
            ...
        },
        encode: {
            // data 中『维度1』和『维度2』对应到 X 轴
            x: [1, 2],
            y: 0
        },
        data: [
            // 维度0  维度1  维度2  维度3
            [   12,   44,   55,   60   ], // 这是第一个 dataItem
            [   53,   31,   21,   56   ], // 这是第二个 dataItem
            [   71,   33,   10,   20   ], // 这是第三个 dataItem
            ...
        ]
    }]
};

在上述例子中,维度1维度2对应到 X 轴,dataZoom 组件控制 X 轴的缩放。

假如在缩放的过程中,某个 dataItem 的维度1超出了 X 轴的范围,维度2还在 X 轴的范围中,那么只要设置 dataZoom.filterMode = 'weakFilter',这个 dataItem 就不会被过滤掉,从而还能够使用 renderItem 绘制图形(可以使用上面提到过的 echarts.graphic.clipRectByRect 把图形绘制成被坐标系剪裁过的样子)。参见上面提到过的例子:Profile

(2)此外,开发者还应注意,renderItem.arguments.params 中的 dataIndex 和 dataIndexInside 是有区别的:

  • dataIndex 指的 dataItem 在原始数据中的 index。
  • dataIndexInside 指的是 dataItem 在当前数据窗口(参见 dataZoom)中的 index。

renderItem.arguments.api 中使用的参数都是 dataIndexInside 而非 dataIndex,因为从 dataIndex 转换成 dataIndexInside 需要时间开销。

参考阅读


更多的自定义系列的例子参见:custom examples


ECharts中的事件和行为
ECharts 富文本标签
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

ECharts配置项.setOption

ECharts图例组件配置项

ECharts图例组件配置 文本样式

ECharts xAxis配置 直角坐标系x轴

ECharts xAxis配置 x坐标轴名称的文本样式

ECharts xAxis配置 设置x坐标轴轴线

ECharts xAxis配置 x坐标轴刻度设置

ECharts xAxis配置 x坐标轴刻度标签设置

xAxis配置x坐标轴分隔线

xAxis配置坐标轴分隔区域设置

xAxis配置类目数据

ECharts xAxis配置 类目标签的文本样式

ECharts极坐标系的径向轴

如何使用dataZoom组件

ECharts工具栏组件(toolbox)

ECharts工具栏的feature属性

ECharts导出图片的操作

ECharts的数据视图工具

ECharts数据区域缩放工具

ECharts动态类型切换工具

ECharts区域选择组件(brush)

ECharts系列列表:平行坐标系

ECharts系列:主题河流图

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }