背景
最近接了个需求,需要地图上展示国内国外业务的数据信息。项目里用的是ECharts,于是去官网上查了一下例子。认为散点地图类型是最符合样式要求的。
开发
这次算第一次使用ECharts,看文档还是觉得挺头疼的,配置也太多了吧。。 看的眼花缭乱的。 散点地图里提供两种地图样式,一种是世界地图,一种是中国地图。其中世界地图如下图所示,是不展示中国省份的。但是我这个需求想要的结果是世界地图+中国详细省份。

最后效果:

贴代码,代码里解释配置项
import React from 'react';
import echarts from 'echarts';
import nameMap from './nameMap.json';//因为世界地图默认展示的国家名都是英文的,要展示中文的话,我们要加一个中英文名映射文件,作为参数传进去
import world from 'echarts/map/json/world.json';
import china from 'echarts/map/json/china.json';
import worldJson from './world.json';//自定义的地图文件世界地图+中国各省地图(我是把china和world两个json拼接起来就行了)
<!--要想展示出来地图,地图json+ echarts.registerMap(mapName, mapJson)注册地图
echarts的npm包里是带着世界地图和中国地图的
有两种用法
import world from 'echarts/map/json/world.json';
import china from 'echarts/map/json/china.json';
echarts.registerMap('world', world);/* 注册world地图 */
echarts.registerMap('china', china);/* 注册world地图 */
或者
import world from 'echarts/map/js/world.js';
import china from 'echarts/map/js/china.js';
没什么不同的, js文件里是帮我们做了注册json
-->
const dataSource = [ //散点数据 value:[纬度,经度,数据]
{ name: '浙江省', value: [122.6953, 30.8936, 10] },
{ name: '江苏省', value: [117.5977, 34.4531, 0.1] },
{ name: '宁夏', value: [106.9629, 38.9795, 0.2] },
{ name: '天津', value: [117.334, 40.1221, 0.5] },
{ name: '湖北', value: [110.5664, 33.2666, 2.3] },
{ name: '辽宁', value: [123.1348, 42.8027, 1.6] },
{ name: "美国", value: [-93.310319, 36.908779, 0.015] },
{ name: "丹麦", value: [9.1577, 56.1388, 0.275] },
{ name: "瑞士", value: [8.6649, 47.5276, 0.0354] }
]
export default class MapChart extends React.Component {
<!--因为写了多个地图,所以我抽取了一个地图生成方法-->
initChart = (data = {}) => {
this.createChart({
title: '使用echarts--world.json世界地图',
rootDom: document.getElementById('world'),
data: dataSource,
geoMap: 'world',
// geoCenter: [100.4, 35.9],
// zoom: 6,
visualMapRange: [//自定义左下角的可视化范围栏(默认的是平分比例,根据业务需求。因为我们这数据集中在前百分之几,所以需要自定义)
{ min: 0.2, max: 100, color: '#abd3ec', label: '0.2%-100%' },
{ min: 0.07, max: 0.2, color: '#9cc8e5', label: '0.07%-0.2%' },
{ min: 0.04, max: 0.07, color: '#78a8cf', label: '0.04%-0.07%' },
{ min: 0.02, max: 0.04, color: '#4f7fad', label: '0.02%-0.04%' },
{ min: 0, max: 0.02, color: '#2a5782', label: '0%-0.02%' }
]
});
this.createChart({
title: '使用echarts--china.json中国地图',
rootDom: document.getElementById('china'),
data: dataSource,
geoMap: 'china',
// zoom: 1,
visualMapRange: [
{ min: 0.2, max: 100, color: '#abd3ec', label: '0.2%-100%' },
{ min: 0.07, max: 0.2, color: '#9cc8e5', label: '0.07%-0.2%' },
{ min: 0.04, max: 0.07, color: '#78a8cf', label: '0.04%-0.07%' },
{ min: 0.02, max: 0.04, color: '#4f7fad', label: '0.02%-0.04%' },
{ min: 0, max: 0.02, color: '#2a5782', label: '0%-0.02%' }
]
});
this.createChart({
title: '自己合并的json数据,世界地图+中国地图',
rootDom: document.getElementById('chinaAndWorld'),
data: dataSource,
geoMap: 'chinaAndWorld',
geoCenter: [100.4, 35.9],
zoom: 5,
visualMapRange: [
{ min: 0.2, max: 100, color: '#abd3ec', label: '0.2%-100%' },
{ min: 0.07, max: 0.2, color: '#9cc8e5', label: '0.07%-0.2%' },
{ min: 0.04, max: 0.07, color: '#78a8cf', label: '0.04%-0.07%' },
{ min: 0.02, max: 0.04, color: '#4f7fad', label: '0.02%-0.04%' },
{ min: 0, max: 0.02, color: '#2a5782', label: '0%-0.02%' }
]
});
}
createChart = ({ rootDom, data, title, visualMapRange, geoMap, geoCenter, zoom }) => {
var mapChart = echarts.init(rootDom);
echarts.registerMap('chinaAndWorld', worldJson);/* 注册world地图 */
echarts.registerMap('world', world);/* 注册world地图 */
echarts.registerMap('china', china);/* 注册china地图 */
mapChart.setOption({
backgroundColor: '#fff',
title: {
text: title,
left: 'left'
},
//地理坐标系组件用于地图的绘制,支持在地理坐标系上绘制散点图,线集。
//要显示散点图,必须填写这个配置
geo: {
show: true,//是否显示地理坐标系组件
roam: true, //是否允许鼠标滚动放大,缩小
map: geoMap,//这就是注册的地图文件的那个mapName
emphasis: { //高亮状态下的多边形和标签样式。
label: { //文本
// color: '#ADA',
show: true
},
itemStyle: { //区域
areaColor: '#ccc'
}
},
center:geoCenter,//当前视角的中心点,用经纬度表示
zoom: zoom,//起始缩放比例
nameMap: nameMap,//世界各国名中英文对应
},
tooltip: {
show: true,
formatter: function (params) {
return `${params.name} ${params.value[2]}%`
}
},
//是视觉映射组件,用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道)。
visualMap: {
type: 'piecewise', // 定义为连续型 visualMap
min: 0, //最小值
max: 10, //最大值
calculable: true, //是否显示拖拽用的手柄(手柄能拖拽调整选中范围)。
inRange: {
// 从左到右颜色越来越轻
color: visualMapRange.map(item => item.color) //颜色
},
textStyle: {
color: '#fff'
},
pieces: visualMapRange.map(item => ({ min: item.min, max: item.max, label: item.label })),
textStyle: {
color: '#000'
}
},
series: [
{
type: 'effectScatter',//散点地图的type
coordinateSystem: 'geo', //该系列使用的坐标系
mapType: 'world',
data: data,
label: {
formatter: (params) => {
const { data = {} } = params;
return `${data.name} \n ${data.value[2]}%`
},
position: 'insideLeft', //bottom
show: true,
color: '#000',
},
//标记的大小,可以设置数组或者函数返回值的形式,也可以用数组分开表示宽和高,例如 [20, 10] 表示标记宽为20,高为10。
symbolSize: 10,
rippleEffect: { //涟漪特效相关配置。
brushType: 'stroke' //波纹的绘制方式
},
hoverAnimation: true, //鼠标移入放大圆
}
]
})
}
render() {
return (
<div>
<div id="world" style={{ width: '50%', height: 600, display: 'inline-block' }}></div>
<div id="china" style={{ width: '50%', height: 600, display: 'inline-block' }}></div>
<div id="chinaAndWorld" style={{ width: '100%', height: 600, display: 'inline-block' }}></div>
</div>
)
}
}
echarts.baidu.com/asset/map/j… 世界地图文件下载 echarts.baidu.com/asset/map/j… datav.aliyun.com/tools/atlas…
这是echarts自带的地图信息

最后效果

然而,这并不是最后
emmm,在这篇文章还没写完的时候,产品提了个要求,地图上的图标有点太乱了,缩小地图的时候,图表消失,像百度地图那样的视觉体验。最终的实现让我把原来的代码结构都调整了

import React from 'react';
import { observer } from 'mobx-react';
import echarts from 'echarts';
import { debounce } from '$config/util';
import nameMap from './nameMap.json';
import worldJson from './world.json';//自定义的地图文件 世界地图+中国各省地图
const data = [ //散点数据 value:[纬度,经度,数据]
{ name: '浙江省', value: [122.6953, 30.8936, 10] },
{ name: '江苏省', value: [117.5977, 34.4531, 0.1] },
{ name: '宁夏', value: [106.9629, 38.9795, 0.2] },
{ name: '天津', value: [117.334, 40.1221, 0.5] },
{ name: '湖北', value: [110.5664, 33.2666, 2.3] },
{ name: '辽宁', value: [123.1348, 42.8027, 1.6] },
{ name: "美国", value: [-93.310319, 36.908779, 0.015] },
{ name: "丹麦", value: [9.1577, 56.1388, 0.275] },
{ name: "瑞士", value: [8.6649, 47.5276, 0.0354] }
]
const symbolSize = {
small: false,//小号图标
large: true,//大号图标
no: false,//没有图标
};
let mapChart = null;
@observer
export default class MapChart extends React.Component {
constructor(props) {
super(props);
// debounce是防抖方法
this.resizeDebounce = debounce(this.chartsResize, 250);
}
componentDidMount() {
mapChart = this.createMap();
// 监听浏览器resize
window.addEventListener('resize', this.resizeDebounce);
}
componentWillUnmount() {
// 别忘了取消监听
window.removeEventListener('resize', this.resizeDebounce);
}
chartsResize = () => {
if (mapChart) {
mapChart.resize();//实例 的resize
}
}
getOptions = () => {
<!--还是那些配置-->
return {
backgroundColor: '#fff',
title: {
text: '世界+中国地图',
left: 'left',
textStyle: {
fontSize: 16,
fontWeight: 'bold',
marginLeft: 10,
}
},
//地理坐标系组件用于地图的绘制,支持在地理坐标系上绘制散点图,线集。
//要显示散点图,必须填写这个配置
geo: {
show: true,//是否显示地理坐标系组件
roam: true, //是否允许鼠标滚动放大,缩小
map: 'world',
emphasis: { //高亮状态下的多边形和标签样式。
label: { //文本
// color: '#ADA',
show: true
},
itemStyle: { //区域
areaColor: '#ccc'
}
},
center: [100.4, 35.9],//视图中心,展示在中国
zoom: 6,//起始缩放比例
nameMap: nameMap,//世界各国名中英文对应
},
tooltip: {
show: true,
formatter: function (params) {
return `${params.name} ${params.value[2]}%`
}
},
//是视觉映射组件,用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道)。
visualMap: {
type: 'piecewise', // 定义为连续型 visualMap
min: 0, //最小值
max: 10, //最大值
calculable: true, //是否显示拖拽用的手柄(手柄能拖拽调整选中范围)。
textStyle: {
color: '#fff'
},
textStyle: {
color: '#000'
}
},
series: [
{
type: 'effectScatter',
coordinateSystem: 'geo', //该系列使用的坐标系
mapType: 'world',
data: data,
label: {
formatter: (params) => {
const { data = {} } = params;
return `${data.name} \n ${data.value[2]}%`
},
position: 'insideLeft', //bottom
show: true,
color: '#333'
},
//标记的大小,可以设置数组或者函数返回值的形式,也可以用数组分开表示宽和高,例如 [20, 10] 表示标记宽为20,高为10。
symbolSize: 8,
rippleEffect: { //涟漪特效相关配置。
brushType: 'stroke' //波纹的绘制方式
},
hoverAnimation: true, //鼠标移入放大圆
}
]
}
}
createMap = (initOption) => {
const dom = document.getElementById('chart');
const mapChart = echarts.init(dom);
echarts.registerMap('world', worldJson);/* 注册world地图 */
const options = initOption || this.getOptions()
mapChart.setOption(options);
mapChart.on('georoam', () => {// 监听地图缩放事件
const { center, zoom } = mapChart.getOption().geo[0];
// 这个缩放范围是自己定的
if ((zoom > 2 && zoom < 6) || zoom === 2) {
if (!symbolSize.small) {
const option = this.getOptions();
// 重新设置图标大小和 当前的缩放比例 视图中心
option.series[0].symbolSize = 2;
option.series[0].label.fontSize = 8;
option.geo.zoom = zoom;
option.geo.center = center;
this.createMap(option);
symbolSize.small = true;
symbolSize.large = false;
symbolSize.no = false;
}
} else if ((zoom > 0 && zoom < 2) || zoom === 0) {
if (!symbolSize.no) {
const option = this.getOptions();
option.series[0].symbolSize = 0;
option.geo.zoom = zoom;
option.geo.center = center;
this.createMap(option);
symbolSize.small = false;
symbolSize.large = false;
symbolSize.no = true;
}
} else {
if (!symbolSize.large) {
const option = this.getOptions();
option.series[0].symbolSize = 10;
option.series[0].label.fontSize = 14;
option.geo.zoom = zoom;
option.geo.center = center;
this.createMap( option);
symbolSize.small = false;
symbolSize.large = true;
symbolSize.no = false;
}
}
});
return mapChart;
}
render() {
return (
<div id="chart" style={{ width: '50%', height: 600, display: 'inline-block' }}></div>
)
}
}