编程式控制完全指南 - dispatchAction
📋 概述
dispatchAction是ECharts提供的编程式API,允许开发者通过代码主动触发图表行为,而不是依赖用户交互。它是实现图表联动、自动播放、动态高亮等高级功能的核心。
核心价值
- 自动化展示:无需用户操作即可展示特定状态
- 图表联动:多个图表之间同步交互状态
- 动态反馈:根据数据变化自动更新视觉状态
- 自定义交互:突破默认交互限制,实现复杂逻辑
🎯 核心概念
1. 什么是dispatchAction?
javascript
// 传统方式:用户点击才会高亮
// ↓
// dispatchAction:代码主动触发高亮
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: 5
});1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2. Action类型分类
| 类别 | Action类型 | 用途 |
|---|---|---|
| 高亮选择 | highlight | 高亮数据项 |
downplay | 取消高亮 | |
| 选中状态 | select | 选中数据项 |
unselect | 取消选中 | |
| 图例控制 | legendSelect | 选中图例 |
legendUnSelect | 取消选中图例 | |
legendToggleSelect | 切换图例状态 | |
| 数据窗口 | dataZoom | 缩放数据范围 |
restore | 重置图表 | |
| 提示框 | showTip | 显示tooltip |
hideTip | 隐藏tooltip | |
| 时间轴 | timelineChange | 切换时间轴 |
timelinePlayChange | 控制播放 | |
| 地图 | geoRoam | 地图漫游 |
mapSelect | 选中地图区域 |
🔧 使用场景
场景1:自动轮播高亮
javascript
class AutoHighlight {
constructor(chart, option) {
this.chart = chart;
this.option = option;
this.currentIndex = 0;
this.interval = null;
this.start();
}
start() {
const dataLen = this.option.series[0].data.length;
// 清除之前的定时器
if (this.interval) {
clearInterval(this.interval);
}
this.interval = setInterval(() => {
// 取消之前的高亮
this.chart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: this.currentIndex
});
// 计算下一个索引
this.currentIndex = (this.currentIndex + 1) % dataLen;
// 高亮当前项
this.chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: this.currentIndex
});
// 显示tooltip
this.chart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: this.currentIndex
});
}, 2000);
}
stop() {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
}
}
// 使用
const autoHighlight = new AutoHighlight(chart, option);
// 鼠标悬停时暂停
chart.on('mouseover', () => autoHighlight.stop());
// 鼠标离开时继续
chart.on('mouseout', () => autoHighlight.start());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
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
场景2:多图表联动
javascript
// 三个图表联动(柱状图、折线图、饼图)
const charts = [chart1, chart2, chart3];
charts.forEach((chart, chartIdx) => {
chart.on('mouseover', (params) => {
if (params.componentType === 'series') {
// 同步其他图表
charts.forEach((otherChart, otherIdx) => {
if (chartIdx !== otherIdx) {
// 在其他图表中高亮对应项
otherChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: params.dataIndex
});
// 显示tooltip
otherChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: params.dataIndex
});
}
});
}
});
chart.on('mouseout', (params) => {
charts.forEach((otherChart, otherIdx) => {
if (chartIdx !== otherIdx) {
otherChart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: params.dataIndex
});
otherChart.dispatchAction({
type: 'hideTip'
});
}
});
});
});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
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
场景3:数据缩放同步
javascript
// 主从图表联动缩放
masterChart.on('dataZoom', (params) => {
const start = params.batch ? params.batch[0].start : params.start;
const end = params.batch ? params.batch[0].end : params.end;
slaveChart.dispatchAction({
type: 'dataZoom',
start: start,
end: end
});
});1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
📝 Action详解
1. highlight / downplay(高亮/取消高亮)
javascript
// 高亮单个数据项
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0, // 系列索引
dataIndex: 5 // 数据项索引
});
// 高亮指定名称的数据
chart.dispatchAction({
type: 'highlight',
seriesName: '销售额',
name: '三月'
});
// 高亮整个系列
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0
});
// 批量高亮
chart.dispatchAction({
type: 'highlight',
batch: [
{ seriesIndex: 0, dataIndex: 0 },
{ seriesIndex: 0, dataIndex: 1 },
{ seriesIndex: 1, dataIndex: 2 }
]
});
// 取消高亮
chart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: 5
});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
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
2. select / unselect(选中/取消选中)
javascript
// 选中数据项(适用于饼图等)
chart.dispatchAction({
type: 'select',
seriesIndex: 0,
dataIndex: 3
});
// 取消选中
chart.dispatchAction({
type: 'unselect',
seriesIndex: 0,
dataIndex: 3
});
// 饼图选中示例
option = {
series: [{
type: 'pie',
data: [
{name: 'A', value: 100},
{name: 'B', value: 200},
{name: 'C', value: 300}
],
selectedMode: 'single' // 启用选中模式
}]
};
// 程序化选中
chart.dispatchAction({
type: 'select',
seriesIndex: 0,
name: 'B'
});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
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
3. legendSelect / legendUnSelect(图例控制)
javascript
// 选中图例
chart.dispatchAction({
type: 'legendSelect',
name: '邮件营销' // 图例名称
});
// 取消选中图例
chart.dispatchAction({
type: 'legendUnSelect',
name: '邮件营销'
});
// 切换图例状态
chart.dispatchAction({
type: 'legendToggleSelect',
name: '邮件营销'
});
// 全选所有图例
chart.dispatchAction({
type: 'legendAllSelect'
});
// 全不选
chart.dispatchAction({
type: 'legendInverseSelect'
});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
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
4. dataZoom(数据缩放)
javascript
// 设置缩放范围(百分比)
chart.dispatchAction({
type: 'dataZoom',
start: 10, // 起始位置 10%
end: 60 // 结束位置 60%
});
// 批量设置多个dataZoom
chart.dispatchAction({
type: 'dataZoom',
batch: [
{ dataZoomIndex: 0, start: 10, end: 60 },
{ dataZoomIndex: 1, start: 20, end: 80 }
]
});
// 按值缩放
chart.dispatchAction({
type: 'dataZoom',
startValue: 100,
endValue: 500
});
// 在现有基础上缩放
chart.dispatchAction({
type: 'dataZoom',
step: 'middle' // 'start' | 'middle' | 'end'
});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
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
5. showTip / hideTip(提示框控制)
javascript
// 显示tooltip
chart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: 5,
position: [100, 100] // 可选:指定位置
});
// 按坐标显示
chart.dispatchAction({
type: 'showTip',
x: 150,
y: 200
});
// 隐藏tooltip
chart.dispatchAction({
type: 'hideTip'
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
6. restore(重置)
javascript
// 重置图表到初始状态
chart.dispatchAction({
type: 'restore'
});1
2
3
4
2
3
4
7. timelineChange(时间轴控制)
javascript
// 切换到指定时间点
chart.dispatchAction({
type: 'timelineChange',
currentIndex: 5
});
// 播放/暂停
chart.dispatchAction({
type: 'timelinePlayChange',
play: true // true播放,false暂停
});1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
8. geoRoam(地图漫游)
javascript
// 地图缩放和平移
chart.dispatchAction({
type: 'geoRoam',
zoom: 1.5, // 缩放比例
originX: 500, // 原点X
originY: 300 // 原点Y
});
// 重置地图
chart.dispatchAction({
type: 'geoRoam',
zoom: 1,
originX: 0,
originY: 0
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
💡 实战案例
案例1:销售数据自动演示
javascript
class SalesPresentation {
constructor(chart, option) {
this.chart = chart;
this.option = option;
this.months = ['一月', '二月', '三月', '四月', '五月', '六月',
'七月', '八月', '九月', '十月', '十一月', '十二月'];
this.currentIndex = 0;
this.timer = null;
}
start() {
this.playMonthByMonth();
}
playMonthByMonth() {
let step = 0;
this.timer = setInterval(() => {
if (step >= this.months.length) {
clearInterval(this.timer);
return;
}
// 高亮当前月份
this.chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
name: this.months[step]
});
// 显示tooltip
this.chart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
name: this.months[step]
});
// 如果是最后一个月,显示总结
if (step === this.months.length - 1) {
setTimeout(() => {
this.showSummary();
}, 2000);
}
step++;
}, 1500);
}
showSummary() {
// 取消所有高亮
this.chart.dispatchAction({
type: 'downplay',
seriesIndex: 0
});
// 显示全局tooltip
this.chart.dispatchAction({
type: 'showTip',
x: this.chart.getWidth() / 2,
y: this.chart.getHeight() / 2
});
}
stop() {
if (this.timer) {
clearInterval(this.timer);
}
}
}
// 使用
const presentation = new SalesPresentation(chart, option);
presentation.start();
// 添加控制按钮
document.getElementById('pause').onclick = () => presentation.stop();
document.getElementById('resume').onclick = () => presentation.start();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
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
案例2:股票K线技术指标联动
javascript
// K线图与成交量图联动
klineChart.on('mouseover', (params) => {
if (params.componentType === 'series') {
// 在成交量图中高亮对应日期
volumeChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: params.dataIndex
});
volumeChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: params.dataIndex
});
}
});
volumeChart.on('mouseover', (params) => {
if (params.componentType === 'series') {
// 在K线图中高亮对应日期
klineChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: params.dataIndex
});
klineChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: params.dataIndex
});
}
});
// 鼠标离开时取消高亮
[klineChart, volumeChart].forEach(chart => {
chart.on('mouseout', (params) => {
[klineChart, volumeChart].forEach(otherChart => {
otherChart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: params.dataIndex
});
otherChart.dispatchAction({
type: 'hideTip'
});
});
});
});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
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
案例3:实时监控告警系统
javascript
class MonitoringDashboard {
constructor(charts) {
this.charts = charts;
this.alertThreshold = 90; // 告警阈值
this.warningThreshold = 70; // 警告阈值
}
updateData(newData) {
// 更新图表数据
this.charts.forEach((chart, index) => {
const value = newData[index];
// 更新数据
chart.setOption({
series: [{
data: this.addData(chart, value)
}]
});
// 检查阈值并触发告警
if (value > this.alertThreshold) {
this.triggerAlert(chart, index, 'critical');
} else if (value > this.warningThreshold) {
this.triggerAlert(chart, index, 'warning');
}
});
}
triggerAlert(chart, index, level) {
// 高亮异常数据点
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: -1 // 最后一个数据点
});
// 显示告警tooltip
const lastDataIndex = chart.getOption().series[0].data.length - 1;
chart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: lastDataIndex
});
// 添加视觉标记
if (level === 'critical') {
// 闪烁效果
this.blinkEffect(chart, '#ff0000');
} else {
this.blinkEffect(chart, '#ffa500');
}
}
blinkEffect(chart, color) {
let toggle = true;
const interval = setInterval(() => {
chart.dispatchAction({
type: toggle ? 'highlight' : 'downplay',
seriesIndex: 0,
dataIndex: -1
});
toggle = !toggle;
}, 500);
// 5秒后停止闪烁
setTimeout(() => {
clearInterval(interval);
chart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: -1
});
}, 5000);
}
addData(chart, value) {
const data = chart.getOption().series[0].data;
data.push(value);
// 保持最近100个数据点
if (data.length > 100) {
data.shift();
}
return data;
}
}
// 使用
const dashboard = new MonitoringDashboard([chart1, chart2, chart3]);
// 模拟实时数据
setInterval(() => {
const newData = [
Math.random() * 100,
Math.random() * 100,
Math.random() * 100
];
dashboard.updateData(newData);
}, 2000);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
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
案例4:地理信息钻取
javascript
class GeoDrillDown {
constructor(mapChart, detailChart) {
this.mapChart = mapChart;
this.detailChart = detailChart;
this.currentLevel = 'china'; // china -> province -> city
this.currentRegion = null;
this.init();
}
init() {
// 监听地图区域点击
this.mapChart.on('click', (params) => {
if (params.componentType === 'series') {
this.drillDown(params.name);
}
});
// 监听返回按钮
document.getElementById('back').onclick = () => {
this.drillUp();
};
}
drillDown(regionName) {
this.currentRegion = regionName;
// 高亮选中区域
this.mapChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
name: regionName
});
// 下钻到详情
this.loadDetailData(regionName);
// 显示返回按钮
document.getElementById('back').style.display = 'block';
}
drillUp() {
// 取消所有高亮
this.mapChart.dispatchAction({
type: 'downplay',
seriesIndex: 0
});
// 重置地图
this.mapChart.dispatchAction({
type: 'geoRoam',
zoom: 1,
originX: 0,
originY: 0
});
// 隐藏返回按钮
document.getElementById('back').style.display = 'none';
this.currentRegion = null;
}
loadDetailData(regionName) {
// 加载该区域的详细数据
fetch(`/api/region/${regionName}`)
.then(res => res.json())
.then(data => {
// 更新详情图表
this.detailChart.setOption({
series: [{
data: data.detailData
}]
});
// 自动高亮详情中的前3项
data.detailData.slice(0, 3).forEach((item, index) => {
setTimeout(() => {
this.detailChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: index
});
}, index * 500);
});
});
}
}
// 使用
const drillDown = new GeoDrillDown(mapChart, detailChart);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
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
⚠️ 常见问题
问题1:action不生效
症状:调用dispatchAction后没有反应
原因:
- 索引或名称错误
- 图表尚未初始化完成
- 组件不支持该action
解决:
javascript
// ❌ 错误:索引超出范围
chart.dispatchAction({
type: 'highlight',
seriesIndex: 10, // 只有2个系列
dataIndex: 100 // 只有50个数据点
});
// ✅ 正确:先验证索引
const option = chart.getOption();
if (seriesIndex < option.series.length &&
dataIndex < option.series[seriesIndex].data.length) {
chart.dispatchAction({
type: 'highlight',
seriesIndex: seriesIndex,
dataIndex: dataIndex
});
}
// ✅ 确保在渲染完成后执行
chart.on('finished', () => {
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: 0
});
});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
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
问题2:多个action冲突
症状:连续调用多个action,效果不符合预期
解决:使用延迟执行
javascript
// ❌ 错误:立即连续调用
chart.dispatchAction({ type: 'downplay', seriesIndex: 0 });
chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: 5 });
// 可能第二个action会被第一个覆盖
// ✅ 正确:添加延迟
chart.dispatchAction({ type: 'downplay', seriesIndex: 0 });
setTimeout(() => {
chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: 5 });
}, 50);1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
问题3:内存泄漏
症状:页面长时间运行后变慢
原因:定时器未清理
解决:
javascript
class AutoPlay {
constructor(chart) {
this.chart = chart;
this.timer = null;
}
start() {
this.timer = setInterval(() => {
// ... 自动播放逻辑
}, 2000);
}
// ✅ 提供销毁方法
destroy() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
}
}
// 使用
const autoPlay = new AutoPlay(chart);
// 页面卸载时清理
window.addEventListener('beforeunload', () => {
autoPlay.destroy();
});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
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
🎯 最佳实践
1. 封装常用操作
javascript
class ChartHelper {
static highlightSeries(chart, seriesIndex, dataIndex) {
chart.dispatchAction({
type: 'highlight',
seriesIndex,
dataIndex
});
chart.dispatchAction({
type: 'showTip',
seriesIndex,
dataIndex
});
}
static clearHighlight(chart, seriesIndex, dataIndex) {
chart.dispatchAction({
type: 'downplay',
seriesIndex,
dataIndex
});
chart.dispatchAction({
type: 'hideTip'
});
}
static setZoomRange(chart, start, end) {
chart.dispatchAction({
type: 'dataZoom',
start,
end
});
}
}
// 使用
ChartHelper.highlightSeries(chart, 0, 5);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
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
2. 创建可复用的自动播放组件
javascript
class AutoSlider {
constructor(chart, options = {}) {
this.chart = chart;
this.interval = options.interval || 3000;
this.loop = options.loop !== false;
this.onHighlight = options.onHighlight || (() => {});
this.timer = null;
this.currentIndex = 0;
}
start(dataLength) {
this.stop();
this.currentIndex = 0;
this.timer = setInterval(() => {
// 取消上一个
this.chart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: this.currentIndex
});
// 移动到下一个
this.currentIndex = (this.currentIndex + 1) % dataLength;
// 高亮当前
this.chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: this.currentIndex
});
// 回调
this.onHighlight(this.currentIndex);
// 如果不循环且到达末尾
if (!this.loop && this.currentIndex === dataLength - 1) {
this.stop();
}
}, this.interval);
}
stop() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
}
pause() {
this.stop();
}
resume() {
const dataLength = this.chart.getOption().series[0].data.length;
this.start(dataLength);
}
}
// 使用
const slider = new AutoSlider(chart, {
interval: 2000,
loop: true,
onHighlight: (index) => {
console.log('当前高亮:', index);
}
});
slider.start(option.series[0].data.length);
// 交互时暂停
chart.on('mouseover', () => slider.pause());
chart.on('mouseout', () => slider.resume());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
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
3. 性能优化
javascript
// 批量执行action
chart.dispatchAction({
type: 'highlight',
batch: [
{ seriesIndex: 0, dataIndex: 0 },
{ seriesIndex: 0, dataIndex: 1 },
{ seriesIndex: 0, dataIndex: 2 }
]
});
// 节流高频调用
function throttle(func, delay) {
let timer = null;
return function(...args) {
if (timer) return;
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
};
}
const throttledAction = throttle(() => {
chart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: currentIndex
});
}, 200);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
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
📊 性能指标
Action执行性能
| Action类型 | 执行时间 | 影响范围 | 建议频率 |
|---|---|---|---|
| highlight/downplay | 5-15ms | 单个元素 | ≤60fps |
| showTip/hideTip | 10-30ms | tooltip | ≤30fps |
| dataZoom | 50-200ms | 整个图表 | ≤10fps |
| legendSelect | 20-50ms | 系列可见性 | ≤20fps |
| restore | 100-500ms | 完整重绘 | 按需使用 |
优化技巧
javascript
// 1. 批量处理
const actions = [
{ type: 'downplay', seriesIndex: 0 },
{ type: 'highlight', seriesIndex: 0, dataIndex: 5 }
];
actions.forEach(action => chart.dispatchAction(action));
// 2. 避免频繁调用
let pendingAction = null;
requestAnimationFrame(() => {
if (pendingAction) {
chart.dispatchAction(pendingAction);
pendingAction = null;
}
});
// 3. 使用节流
const throttledHighlight = _.throttle((index) => {
chart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: index
});
}, 100);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
🔗 相关链接
📚 学习路线
💎 总结
dispatchAction核心价值:
- ✅ 编程式控制图表行为,不依赖用户交互
- ✅ 实现图表联动、自动播放等高级功能
- ✅ 支持高亮、选中、缩放、提示框等多种操作
- ✅ 提供细粒度的控制能力
关键使用原则:
- 精确索引:确保seriesIndex和dataIndex有效
- 时序控制:连续调用时使用延迟避免冲突
- 资源管理:及时清理定时器和事件监听
- 性能优化:批量执行、节流、避免高频调用
典型应用场景:
- 数据大屏自动轮播
- 多图表联动交互
- 实时监控告警系统
- 地理信息钻取分析
掌握dispatchAction,让你的图表具备更强大的交互能力!🚀
