最近有幸学习了宿爽大神的「浅入浅出 ECharts 源码 - 资深架构师独家揭秘 ECharts 源码架构」,受益良多。
尤其是其中「Message Center」的设计,简直醍醐灌顶~
之前一直苦于图表间的复杂交互的实现(一大堆有交叉的 on、dispatchAction、setOption),感觉脑子特别不够用……做出来的效果总是和自己预想的不一样,然后只能一边改一边试,一遍遍地慢慢改
直到看到宿爽大神讲到「Message Center」,讲到如何为这些交叉的监听解耦,才突然意识到原来有更好的方法。
插一句,顺便再推荐一个 ECharts 核心开发者羡辙大神的分享:
想法&思路
为了验证自己学到的东西,打算做一个简易的 Demo,即 3 个图表交叉作用,点其中任意一个图表,其他两个会变化:
思路大致就是:
主要代码
准备一些示意数据
srcData = [
//['维度1', '维度2', '维度3', '度量'],
['a1', 'b1', 'c1', 1],
['a1', 'b1', 'c2', 1],
['a1', 'b1', 'c3', 1],
['a1', 'b2', 'c1', 1],
['a1', 'b2', 'c2', 1],
['a1', 'b2', 'c3', 1],
['a1', 'b3', 'c1', 1],
['a1', 'b3', 'c2', 1],
['a1', 'b3', 'c3', 1],
['a2', 'b1', 'c1', 2],
['a2', 'b1', 'c2', 2],
['a2', 'b1', 'c3', 2],
['a2', 'b2', 'c1', 2],
['a2', 'b2', 'c2', 2],
['a2', 'b2', 'c3', 2],
['a2', 'b3', 'c1', 2],
['a2', 'b3', 'c2', 2],
['a2', 'b3', 'c3', 2],
['a3', 'b1', 'c1', 3],
['a3', 'b1', 'c2', 3],
['a3', 'b1', 'c3', 3],
['a3', 'b2', 'c1', 3],
['a3', 'b2', 'c2', 3],
['a3', 'b2', 'c3', 3],
['a3', 'b3', 'c1', 3],
['a3', 'b3', 'c2', 3],
['a3', 'b3', 'c3', 3],
];
用到了一年多以前,自己瞎写的二维数组过滤、求和(类似 sum ... group by ...)的函数
var ecCalc = new Object({});
/**聚合计算
* @alias module:ecCalc/groupCalc
* @param {Array} source 输入,二维数组
* @param {boolean} hasColumnName 第一行(source[0])是否是列名
* @param {Array} dimensions 纬度,一维数组,传入列id列表,例如[0,2,3],列表长度至少为1
* @param {Object} measures 度量,json数组,例如[{"id": 2, "method": "count"}, {"id": 3, "method": "count"}],id用于
source[measures[id]],method用于聚合方法
* @return {Array} 输出,二维数组,新列与原列对应关系为dimensions.concat(measures)
*/
ecCalc.groupCalc = function(source, hasColumnName, dimensions, measures) {
...
}
/**条件筛选
* @alias module:ecCalc/filter
* @param {Array} source 输入,二维数组
* @param {boolean} hasColumnName 第一行(source[0])是否是列名
* @param {function} filterCondition 筛选(判断)函数
(@param {Array} source[i]作为输入;
@return {boolean} 输出保留/筛掉的布尔值)
{string} filterCondition 条件表达式,用item代表source[i],
传入例如"(item[0] - item[1] > 0) && (item[0] + item[1] > 0)"的,
结果为boolean的表达式
* @return {Array} 输出,二维数组*/
ecCalc.filter = function(source, hasColumnName, filterCondition) {
...
}
数据过滤、求和的规则配置和通过该规则转换数据的函数。
convertConfig = [
{
dimensions: [0],
methods: [{id: 3, method: "sum"}],
filter: 'true',
},
{
dimensions: [1],
methods: [{id: 3, method: "sum"}],
filter: 'true',
},
{
dimensions: [2],
methods: [{id: 3, method: "sum"}],
filter: 'true',
},
];
function dataConvert(config){
let res = [];
for (let obj of convertConfig){
let tmp = ecCalc.filter(srcData, false, obj.filter);
res.push(ecCalc.groupCalc(tmp, false, obj.dimensions, obj.methods));
}
return res;
};
定义 option(放了 line、bar、pie 三个图)
option = {
title: {
text: '受到宿爽大神视频分享中 Message Center 的启发,图表联动的交叉实现'
},
tooltip:{},
grid: [{
bottom: '55%'
}, {
top: '55%',
right: '55%'
}],
xAxis: [{
type: 'category'
}, {
type: 'category',
gridIndex: 1
}],
yAxis: [{}, {
gridIndex: 1
}],
series: [{
id: 'line',
type: 'line',
label: {
show: true
},
name: convertConfig[0].filter,
data: convertedData[0]
}, {
id: 'bar',
type: 'bar',
xAxisIndex: 1,
yAxisIndex: 1,
label: {
show: true
},
name: convertConfig[1].filter,
data: convertedData[1]
}, {
id: 'pie',
type: 'pie',
center: ['75%', '75%'],
radius: '25%',
label: {
show: true,
formatter: '{b}:{c}',
},name: convertConfig[2].filter,
data: convertedData[2].map(function(item){
return {name:item[0],value:item[1]};
})
}]
};
图表交互的对应(响应)关系
actionConfig = [{
//from: 0,
to: [1, 2]
},{
to: [0, 2]
},{
to: [0, 1]
}];
on(click)、setOption 部分
myChart.on('click', function(params){
let actionSeries = actionConfig[params.seriesIndex].to;
for (let i of actionSeries){
convertConfig[i].filter = convertConfig[params.seriesIndex].filter + ' && item[' + params.seriesIndex + '] == "' + params.name + '"';
}
convertedData = dataConvert(convertConfig);
myChart.setOption({
series:[{
id: 'line',
name: convertConfig[0].filter,
data: convertedData[0]
},{
id: 'bar',
name: convertConfig[1].filter,
data: convertedData[1]
},{
id: 'pie',
name: convertConfig[2].filter,
data: convertedData[2].map(function(item){
return {name:item[0],value:item[1]};
})
}]
});
})
以上就是一个简易、粗糙的例子,估计有不少欠考虑的地方……另外引用之前瞎写的函数时,把部分 var 改成了 let(没改全,有点乱)。算了,主要是验证思路(自我安慰),哈哈哈哈~~
本文分享自 ZXand618的ECharts之旅 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!