PS:使用的是React框架
要实现的效果如下:
需要一张地图,对地图进行下钻操作,地图的区域需要颜色标记
两种标记方式(气泡和圆点),且颜色需要不一样
右边要有柱状图显示人数
开始之前我们需要准备一个获得地图json数据的网站
地图选择器: https://datav.aliyun.com/tools/atlas/
需要哪部分的数据,点击这个按钮复制到你的编辑器上就可以了。
准备工作做完,我们就开始进入正题了:首先我们要一个“地图画布”,有了画布才能折腾数据。
画一个地图
引入echarts和相关的json文件
import Echarts from 'echarts';
import jiangxi from '../../../config/mapJSON/jiangxi.json';
import jiujiang from '../../../config/mapJSON/jiujiang.json';
准备一个div存放地图,记得写div的高度和宽度。
整体的框架(我们先把option放一放,先别急,现在你的页面一定是空的)
let myChart = Echarts.init(document.getElementById('map'))
let name = 'jiangxi' //地图名是jiangxi
let data = jiangxi //地图的数据来自之前引入的json文件
Echarts.registerMap(name, data) //此步不可省略,要想展示一个地图,先需要注册,巨坑(官方根本无文档,全靠瞎猜)
let option = {} //此处先省略,不放入任何数据
myChart.setOption(option, true);
现在为option添砖加瓦,此时你的页面会有一个小地图了
let option = {
backgroundColor: '#fff',
title: {
top: 20,
text: '用户注册区域展示',
subtext: '',
x: 'center',
textStyle: {
color: '#000'
}
},
geo: {
type: 'map',
map: name, //'jiangxi'
roam: true,
geoIndex: 1,
zoom: 1.1, //地图的比例
label: {
normal: {
show: true,
textStyle: {
color: '#000000' //字体颜色
}
},
emphasis: {
textStyle: {
color: '#000000' //选中后的字体颜色
}
}
},
itemStyle: {
normal: {
areaColor: '#EEEEEE',
borderColor: '#8b8b8b',
},
emphasis: {
areaColor: '#ffffff',
}
},
},
}
现在想在地图上绑定我的数据,应该怎么做呢?
//获得数据这一步我就不写了,用下面的死数据
let cityData = [{name:'南昌市',value:47},{name:'九江市',value:22},{name:'新余市',value:4}]
//在geo多配置一行data数据
geo:{
...
data:cityData
}
设置地图色块
此时虽然数据绑定成功了,但是地图上依旧什么色块都没有。我们继续下一步,设置option中的visualMap参数和series参数。
visualMap用来设置地图的色块,series参数用于标记地图。
visualMap: {
show: true,
//设置最大值和最小值
min: 0,
max: 50,
//设置位置
left: '4%',
top: '40%',
text: ['高', '低'], // 文本,默认为数值文本
calculable: true,
seriesIndex: [0], //作用在哪个series上
inRange: {
color: ['#ffcbc5', '#ffd661'] //粉黄
}
},
series:[
{
name: "市报名人数",
type: "map",
geoIndex: 0,
data: cityData,
},
]
设置圆点标记
下图是圆点需要的数组,为这个数组命名为areaData
给series新增一个圆点标记
{
name: '区县报名人数',
type: 'effectScatter',
coordinateSystem: 'geo',
showEffectOn: 'render',
rippleEffect: {
period: 15,
scale: 4,
brushType: 'fill'
},
hoverAnimation: true,
itemStyle: {
normal: {
color: '#fffd21', //设置圆点的颜色
shadowBlur: 10,
shadowColor: '#333'
}
},
symbolSize: function (params) {
console.log('paramsparams', params[2])
if (params[2] > 30)
return params[2] / 5
else
return 3
}, //圆点的大小可以自行设置,这里不赘述
data: areaData,
},
设置气泡标记
气泡和圆点的原理是相同的,他们的数据要求是需要经纬度以及数据,你无法知道经纬度的时候可以从提前下载好的json数据中取。然后继续在series中添加气泡标记。
let geoCoordMap = jiangxi.features.map(item => {
return {
name: item.properties.name,
value: item.properties.center
}
});
let convertData = function (data) {
let res = [];
for (let i = 0; i < data.length; i++) {
if (geoCoordMap.filter(item => item.name === data[i].name).length)
res.push({
name: data[i].name,
value: geoCoordMap.filter(item => item.name === data[i].name)[0].value.concat(data[i].value)
})
}
return res;
}
{
name: 'Top 5',
type: 'scatter',
coordinateSystem: 'geo',
symbol: 'pin',
symbolSize: 40,
label: {
normal: {
show: true,
textStyle: {
color: '#fff',
fontSize: 9,
fontWeight: 'bold'
},
formatter(value) {
return value.data.value[2]
}
}
},
itemStyle: {
normal: {
color: '#F62157', //标志颜色
}
},
//使用之前的函数处理数据,为之前的cityData添加经纬度,当然也可以让初始数据像之前的areaData一样就有经纬度
data: convertData(cityData),
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
hoverAnimation: true,
zlevel: 1
},
现在的效果:
设置右侧的柱状图
为option添加xAxis和yAxis(一定要有,否则在series中新增type为bar的标记时会报错)
柱状图中的数据需要特殊处理
let barData = cityData.map((item) => {
return [item.value, item.name]
})
//option中的grid表示bar的位置
grid: {
left: '70%',
right: '10%',
// top: '30%',
// bottom:'40%'
},
xAxis: {
type: 'value',
// scale: true,
position: 'top',
min: 0,
boundaryGap: false,
splitLine: {
show: false
},
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
margin: 1,
textStyle: {
color: '#aaa'
}
},
},
yAxis: {
type: 'category',
inverse: true, //改变数据顺序
nameGap: 16,
axisLine: {
show: true,
lineStyle: {
color: '#ddd'
}
},
axisTick: {
show: false,
lineStyle: {
color: '#ddd'
}
},
axisLabel: {
interval: 0,
show: true,
textStyle: {
color: '#000000'
}
},
},
地图下钻操作※
你需要知道:
- 点击地图怎么做到
- 怎么通过点击地图进行下钻
- 下钻后地图上的标记数据如何改变(气泡、圆点、柱状图)
你还记得我们给地图的命名吗——myChart,实现点击就要为它添加点击事件,打印看看这里的e是何方神圣。
myChart.on('click', (e) => {
console.log('click', e)
})
想一想,我们需要根据点击城市名的不同下钻到不同的城市。那么需要的就是点击这块区域的name了。
还记得我们是怎么使用地图的吗?注册地图时,有一个地图名和地图名对应的json,由于我们获得的name是中文,无法和json数据对应,选择switch语句进行调整地图名,下面的thisMap相当于最开始初始化地图时的name,thisData相当于最开始初始化地图时的data。
//得到加载地图时的地图名
switch (e.name) {
case '九江市':
thisMap = 'jiujiang';
break
case '南昌市':
thisMap = 'nanchang';
break
case '抚州市':
thisMap = 'fuzhou';
break
case '赣州市':
thisMap = 'ganzhou';
break
case '吉安市':
thisMap = 'jian';
break
case '景德镇市':
thisMap = 'jingdezhen';
break
case '萍乡市':
thisMap = 'pingxiang';
break
case '上饶市':
thisMap = 'shangrao';
break
case '新余市':
thisMap = 'xinyu';
break
case '宜春市':
thisMap = 'yichun';
break
case '鹰潭市':
thisMap = 'yingtan';
break
}
//得到加载地图时的地图json
let area = {
'九江市': require('../../../config/mapJSON/jiujiang.json'),
'南昌市': require('../../../config/mapJSON/nanchang.json'),
'抚州市': require('../../../config/mapJSON/fuzhou.json'),
'赣州市': require('../../../config/mapJSON/ganzhou.json'),
'吉安市': require('../../../config/mapJSON/jian.json'),
'景德镇市': require('../../../config/mapJSON/jingdezhen.json'),
'萍乡市': require('../../../config/mapJSON/pingxiang.json'),
'上饶市': require('../../../config/mapJSON/shangrao.json'),
'新余市': require('../../../config/mapJSON/xinyu.json'),
'宜春市': require('../../../config/mapJSON/yichun.json'),
'鹰潭市': require('../../../config/mapJSON/yingtan.json')
}
thisData = area[e.name]
如何动态的把thisMap和thisData传递给Echarts,告诉Echarts我需要换一个地图进行注册呢?可以写一个函数loadMap(可以还有别的方法,不赘述)。先打个框架。
let loadMap = (name,data) =>{
//现在是否是下钻状态=>通过name是否为'jiangxi'判断
//如果是下钻:过滤areaData,barData中的其他区域数据,
//如果不是下钻状态:之前在jiangxi时的数据全部存入state,现在取出并赋值还原。
let option = {}
}
总结
最后重新整理一下整体框架
showMap(cityData, areaData){
//cityData,areaData 这里的数据需要你自己获得
let myChart = Echarts.init(document.getElementById('map'))
//默认地图:江西省
let thisMap = 'jiangxi'
let thisData = jiangxi
let loadMap = (name, data) => {
//地图名转回中文,为了方便过滤数据
if (name !== 'jiangxi') {
let key = ''
switch (name) {
case 'jiujiang' :
key = '九江市';
break
//... 不赘述
}
//在areaData中找到对应市的区和县
let array = areaData.filter(item => item.city === key)
let cd = array.map(item => {
return {
name: item.name,
value: item.value[2]
}
})
barData = array.map(item => {
return [item.value[2], item.name]
})
areaData = []
cityData = cd
} else {
areaData = this.state.areaData
cityData = this.state.cityData
barData = cityData.map((item) => {
return [item.value, item.name]
})
}
Echarts.registerMap(name, data) //注册地图
let option = {}
myChart.setOption(option, true);
}
loadMap(thisMap, thisData)
myChart.on('click', (e) => {
switch (e.name) {
case '九江市':
thisMap = 'jiujiang';
break
//...不赘述
}
thisData = area[e.name]
//下钻
if (thisData) {
loadMap(thisMap, thisData)
} else {
//不继续下钻返回上一层
loadMap('jiangxi', jiangxi)
}
})
}