爱招飞帮助手册 爱招飞帮助手册
首页
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 功能用法
    • 专用模板
    • 开发流程
    • 函数程序
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 系统工具
    • 系统管理
    • 数据库工具
    • 专用模板
    • 外部功能
    • 开发流程
    • 函数代码
  • 开发手册
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 功能用法
    • 专用模板
    • 开发流程
    • 函数程序
  • 开发手册
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 功能用法
    • 专用模板
    • 开发流程
    • 函数程序
  • 开发手册
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
    • 报表设计
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
    • RestAPI
    • WebSocket
  • 学习手册

    • 安装配置
    • 快速上手
    • 程序架构
    • 界面介绍
    • 功能介绍
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
    • 预设资料
    • RestAPI说明
    • WebSocket说明
    • MQTT说明
    • Python说明
    • 自定程序
    • 运行卫士
    • 自动化作业
    • 函数程序
    • 控件使用
  • 开发手册
  • FastERP
  • FastWeb
  • Smart
  • PinToo
  • Flying
  • TARS
  • 通用功能

    • Report
    • Script
    • Echarts
    • Chart
    • DB Install
    • HiDesk
    • HiNAT
    • FastBPM
    • ReportBuilder
首页
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 功能用法
    • 专用模板
    • 开发流程
    • 函数程序
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 系统工具
    • 系统管理
    • 数据库工具
    • 专用模板
    • 外部功能
    • 开发流程
    • 函数代码
  • 开发手册
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 功能用法
    • 专用模板
    • 开发流程
    • 函数程序
  • 开发手册
  • 学习手册

    • 基本入门
    • 功能介绍
    • 控件说明
    • 功能用法
    • 专用模板
    • 开发流程
    • 函数程序
  • 开发手册
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
    • 报表设计
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
    • RestAPI
    • WebSocket
  • 学习手册

    • 安装配置
    • 快速上手
    • 程序架构
    • 界面介绍
    • 功能介绍
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
  • 学习手册

    • 安装配置
    • 快速上手
    • 界面介绍
    • 功能介绍
    • 预设资料
    • RestAPI说明
    • WebSocket说明
    • MQTT说明
    • Python说明
    • 自定程序
    • 运行卫士
    • 自动化作业
    • 函数程序
    • 控件使用
  • 开发手册
  • FastERP
  • FastWeb
  • Smart
  • PinToo
  • Flying
  • TARS
  • 通用功能

    • Report
    • Script
    • Echarts
    • Chart
    • DB Install
    • HiDesk
    • HiNAT
    • FastBPM
    • ReportBuilder
  • Report

  • Script

  • EChart

    • ECharts使用说明

      • ECharts特性
      • ECharts安装
      • ECharts配置语法
      • 在FastWeb中引入ECharts
      • ECharts基础概念概览
      • 个性化图表的样式
      • ECharts中的样式简介
      • 异步数据加载和更新
      • 使用dataset管理数据
      • 使用transform进行数据转换
      • 在图表中加入交互组件
      • 移动端自适应
      • 数据的视觉映射
      • ECharts中的事件和性为
      • 动态排序柱状图
      • 小例子自己实现拖拽
      • 小例子实现日历图
      • 旭日图
      • 自定义系列
        • 1. renderItem 方法
        • 2. 使坐标轴的范围自适应数据范围
        • 3. 设定 tooltip
        • 4. 超出坐标系范围的截取
        • 5. 关于 dataIndex
        • 6. 事件监听
        • 7. 自定义矢量图形
      • 富文本标签
    • ECharts属性说明

  • Chart

  • DB Install

  • HiDesk

  • HiNAT

  • ReportBuilder

目录

自定义系列

# 自定义系列

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

  Apache EChartsTM 为什么会要支持 自定义系列 呢?

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

例如,下面的例子使用 custom series 扩展出了 x-range 图:

  • 图表来源:https://echarts.apache.org/examples/zh/editor.html?c=custom-profile (opens new window)

  • FastWeb TUgURLFrame示例:

  如需在FastWeb中的TUgURLFrame中实现上述效果,则修改其HTML属性,使用下列内容:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/5.1.2/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 800px;height:500px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
        var option;

        var data = [];
        var dataCount = 10;
        var startTime = +new Date();
        var categories = ['categoryA', 'categoryB', 'categoryC'];
        var types = [
            {name: 'JS Heap', color: '#7b9ce1'},
            {name: 'Documents', color: '#bd6d6c'},
            {name: 'Nodes', color: '#75d874'},
            {name: 'Listeners', color: '#e0bc78'},
            {name: 'GPU Memory', color: '#dc77dc'},
            {name: 'GPU', color: '#72b362'}
        ];

        // Generate mock data
        categories.forEach(function (category, index) {
            var baseTime = startTime;
            for (var i = 0; i < dataCount; i++) {
                var typeItem = types[Math.round(Math.random() * (types.length - 1))];
                var duration = Math.round(Math.random() * 10000);
                data.push({
                    name: typeItem.name,
                    value: [
                        index,
                        baseTime,
                        baseTime += duration,
                        duration
                    ],
                    itemStyle: {
                        normal: {
                            color: typeItem.color
                        }
                    }
                });
                baseTime += Math.round(Math.random() * 2000);
            }
        });

        function renderItem(params, api) {
            var categoryIndex = api.value(0);
            var start = api.coord([api.value(1), categoryIndex]);
            var end = api.coord([api.value(2), categoryIndex]);
            var height = api.size([0, 1])[1] * 0.6;

            var rectShape = echarts.graphic.clipRectByRect({
                x: start[0],
                y: start[1] - height / 2,
                width: end[0] - start[0],
                height: height
            }, {
                x: params.coordSys.x,
                y: params.coordSys.y,
                width: params.coordSys.width,
                height: params.coordSys.height
            });

            return rectShape && {
                type: 'rect',
                transition: ['shape'],
                shape: rectShape,
                style: api.style()
            };
        }


        option = {
            tooltip: {
                formatter: function (params) {
                    return params.marker + params.name + ': ' + params.value[3] + ' ms';
                }
            },
            title: {
                text: 'Profile',
                left: 'center'
            },
            dataZoom: [{
                type: 'slider',
                filterMode: 'weakFilter',
                showDataShadow: false,
                top: 400,
                labelFormatter: ''
            }, {
                type: 'inside',
                filterMode: 'weakFilter'
            }],
            grid: {
                height: 300
            },
            xAxis: {
                min: startTime,
                scale: true,
                axisLabel: {
                    formatter: function (val) {
                        return Math.max(0, val - startTime) + ' ms';
                    }
                }
            },
            yAxis: {
                data: categories
            },
            series: [{
                type: 'custom',
                renderItem: renderItem,
                itemStyle: {
                    opacity: 0.8
                },
                encode: {
                    x: [1, 2],
                    y: 0
                },
                data: data
            }]
        };        

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

更多的例子参见:自定义示例 (opens new window)

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

# 1. renderItem 方法

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

var option = {
    ...,
    series: [{
        type: 'custom',
        renderItem: function (params, api) {
            // ...
        },
        data: data
    }]
}
1
2
3
4
5
6
7
8
9
10

  在渲染阶段,对于 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;

            // shape 属性描述了这个矩形的像素位置和大小。
            // 其中特殊得用到了 echarts.graphic.clipRectByRect,意思是,
            // 如果矩形超出了当前坐标系的包围盒,则剪裁这个矩形。
            // 如果矩形完全被剪掉,会返回 undefined.
            var rectShape = 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
            });

            // 这里返回为这个 dataItem 构建的图形元素定义。
            return rectShape && {
                // 表示这个图形元素是矩形。还可以是 'circle', 'sector', 'polygon' 等等。
                type: 'rect',
                shape: rectShape,
                // 用 api.style(...) 得到默认的样式设置。这个样式设置包含了
                // option 中 itemStyle 的配置和视觉映射得到的颜色。
                style: api.style()
            };
        },
        data: [
            [12, 44, 55, 60], // 这是第一个 dataItem
            [53, 31, 21, 56], // 这是第二个 dataItem
            [71, 33, 10, 20], // 这是第三个 dataItem
            ...
        ]
    }]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

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 中定义的样式信息,以及视觉映射的样式信息。也可以用这种方式覆盖这些样式信息:api.style({fill: 'green', stroke: 'yellow'})。

  书写完 renderItem 方法后,自定义系列的 90% 工作就做完了。剩下的是一些精化工作。

# 2. 使坐标轴的范围自适应数据范围

  在 直角坐标系(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
            ...
        ]
    }]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 3. 设定 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

  上面,一个简单的 custome series 例子完成了。

  下面介绍几个其他细节要点。

# 4. 超出坐标系范围的截取

  与 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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

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

# 5. 关于 dataIndex

  开发者如果使用到的话应注意,renderItem.arguments.params 中的 dataIndex 和 dataIndexInside 是有区别的:

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

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

# 6. 事件监听

chart.setOption({
    // ...
    series: {
        type: 'custom',
        renderItem: function () {
            // ...
            return {
                type: 'group',
                children: [{
                    type: 'circle'
                    // ...
                }, {
                    type: 'circle',
                    name: 'aaa',
                    // 用户指定的信息,可以在 event handler 访问到。
                    info: 12345,
                    // ...
                }]
            };
        }
    }
});
chart.on('click', {element: 'aaa'}, function (params) {
    // 当 name 为 'aaa' 的图形元素被点击时,此回调被触发。
    console.log(params.info);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 7. 自定义矢量图形

  自定义系列能支持使用 SVG PathData (opens new window) 定义矢量路径。从而可以使用矢量图工具中做出的图形。参见:path,以及例子:icons 和 shapes。


更多的自定义系列的例子参见:自定义示例 (opens new window)

旭日图
富文本标签

← 旭日图 富文本标签→

Copyright © 2021-2025 爱招飞IsoFace | ALL Rights Reserved
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式