这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
需求介绍
之前在大屏展示项目中,涉及到了基于echarts: 5.0.2,实现全国与北京市的迁徙图。
-
如果全国地图没有数据则只展示北京市数据,如果存在优先展示全国数据。
-
迁入迁出标签可点击,年份可切换,需要展示对应数据
-
全国地图可下钻到北京地图,北京地图可返回全国地图
基础准备
-
地图数据和省市数据 目前主流的地图和省市数据有两个,一个是hcharts, 还有一个是datav。我们需要根据需要选择合适的数据和结构。
-
根据地图数据生成地图:
echarts.registerMap('china', china); -
series中添加迁徙路径:
{ name: item[0], type: 'lines', zlevel: 2, symbol: ['none', 'arrow'], symbolSize: 10, effect: { show: true, period: 6, trailLength: 0, symbol: planePath, symbolSize: 15 }, lineStyle: { color: (params) => dealColor(params, item), type: 'dashed', width: 2, opacity: 0.6, curveness: 0.2 }, //这里就是迁徙的数据 data: convertData(item[1]) }, -
series中添加落点的
effectScatter:{ name: item[0], type: 'effectScatter', coordinateSystem: 'geo', zlevel: 2, rippleEffect: { brushType: 'fill' }, label: { show: true, position: 'right', formatter: '{b}', color: 'inherit' }, symbolSize(val) { if (val && val.length) { return val[2] * 280; } }, itemStyle: { color: (params) => dealColor(params, item) }, data: item[1].map((dataItem) => ({ name: dataItem[1].name, value: allCityData[dataItem[1].name] })), } -
使用
setOption更新地图:chinaCanvas.setOption(option); -
每次切换地图的时候需要销毁之前的echarts实例,如果不删除的话,长时间的切换会导致页面越来越卡,虽然在我的代码中只使用了两个元素用来挂在全国地图和北京地图,但是每次都会创建新的echarts实例。这里有两种方法,我试了都可以。但是有人说使用
dispose()方法会有问题,不过我没有遇到。不知道是不是已经解决了。
// 销毁echarts图
destoryCanvas(id) {
const dom = document.getElementById(id);
// dom.removeAttribute('_echarts_instance_');
// dom.innerHtml = '';
const echartsObj = echarts.getInstanceByDom(dom);
if (echartsObj) {
echartsObj.dispose();
}
},
整体设计
逻辑上有下面几点
- 切换年份后,重新请求数据,重新绘制地图
- 切换迁入迁出,更新地图数据
- 点击北京市,进入北京地图,右上角显示返回全国地图按钮
UI还原上最重要的就是地图边框的实现。 首先我采用的方法是将echarts地图设为透明的,鼠标覆盖上去选中的地方会有颜色变换,之后将UI带有边框的背景图放入echarts地图的后面。
- 我的页面有响应式设计,所以要注意背景图和
ehcarts地图的位置要匹配,否则会出现鼠标覆盖上去样式和背景不重合。 - 一开始UI使用的是
hcharts的地图GeoJSON数据,但是我使用的是dataV的数据。这样导致怎么都和UI背景图不重合。
后来记得又看到了一种方法,好像是将另外一个echarts地图作为背景。具体内容记不太清楚了,之后再查一下吧。。。
注意事项
- 地图数据变换时,使用
setOption()修改地图数据,不需要重新绘制地图 - 地图切换时,要记得销毁之前创建的实例,否则长时间操作会导致页面卡顿
代码展示
drawCanvas(moveInOutData) {
this.destoryCanvas('mapCanvas');
const series = [];
echarts.registerMap('china', china);
const chinaCanvas = echarts.init(document.getElementById('mapCanvas'));
const planePath = 'path://M1705.06,1318.313v-89.254l-319.9-221.799l0.073-208.063c0.521-84.662-26.629-121.796-63.961-121.491c-37.332-0.305-64.482,36.829-63.961,121.491l0.073,208.063l-319.9,221.799v89.254l330.343-157.288l12.238,241.308l-134.449,92.931l0.531,42.034l175.125-42.917l175.125,42.917l0.531-42.034l-134.449-92.931l12.238-241.308L1705.06,1318.313z';
// 转换市级数据
function convertData(data) {
const res = [];
for (let i = 0; i < data.length; i += 1) {
const dataItem = data[i];
const fromCoord = allCityData[dataItem[0].name];
const toCoord = allCityData[dataItem[1].name];
if (fromCoord && toCoord) {
res.push({
coords: [fromCoord, toCoord]
});
}
}
return res;
}
const color = this.toolList.map(el => el.color);
function dealColor(params, item) {
if (item[1][params.dataIndex][1].type === '迁入') {
return color[0];
}
return color[1];
}
// 迁入数据
const moveData = moveInOutData.filter(item => item[0].name === '北京' || item[1].name === '北京');
if (moveData && moveData.length) {
[['北京', moveData]].forEach((item, i) => {
series.push(
{
name: item[0],
type: 'lines',
zlevel: 2,
symbol: ['none', 'arrow'],
symbolSize: 10,
effect: {
show: true,
period: 6,
trailLength: 0,
symbol: planePath,
symbolSize: 15
},
lineStyle: {
color: (params) => dealColor(params, item),
type: 'dashed',
width: 2,
opacity: 0.6,
curveness: 0.2
},
data: convertData(item[1])
},
{
// 目的地信息
name: item[0],
type: 'effectScatter',
coordinateSystem: 'geo',
zlevel: 2,
rippleEffect: {
brushType: 'fill'
},
label: {
show: true,
position: 'right',
formatter: '{b}',
color: 'inherit'
},
symbolSize(val) {
if (val && val.length) {
return val[2] * 280;
}
},
itemStyle: {
color: (params) => dealColor(params, item)
},
data: item[1].map((dataItem) => ({
name: dataItem[1].name,
value: allCityData[dataItem[1].name]
})),
}
);
});
}
const option = {
geo: {
map: 'china',
left: 0,
top: 0,
right: 0,
bottom: 0,
zoom: 1,
aspectScale: 1,
label: {
show: false
},
roam: false,
regions: [{
name: '北京',
label: {
show: true,
color: 'rgba(242, 233, 69, 1)'
},
itemStyle: {
borderCap: 'square',
borderWidth: 0,
areaColor: '#2EA1D7',
borderColor: 'rgba(0, 10, 25, 0)',
}
}],
itemStyle: {
borderCap: 'square',
areaColor: 'rgba(7, 86, 157, 0)',
borderColor: 'rgba(0, 10, 25, 0)',
},
emphasis: {
itemStyle: {
borderWidth: 0,
areaColor: '#2EA1D7',
borderColor: 'rgba(7, 86, 157, 1)',
},
label: {
show: true,
}
}
},
series
};
chinaCanvas.setOption(option);
chinaCanvas.on('click', params => {
if (params.name === '北京') {
this.showChinaMap = false;
this.destoryCanvas('mapCanvas');
this.drawBeijingCanvas(moveInOutData);
}
});
this.chinaCanvas = chinaCanvas;
},