前言
本示例使用的echarts版本为3.8.0
,和北京市的地图geojson(地图数据可自行下载github.com/zhangqian00…),使用最基础的模板实现,有需要的朋友可根据需求自由修改。
不要仅仅是学到铺设柱状图,换成折线图、饼图、散点图思路都是差不多的。
Html结构
引入echarts.js,和北京市地图数据,并准备一个有宽高的DOM容器:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/3.8.0/echarts.js"></script>
<script src="./echarts/beijing.js"></script>
</head>
<body>
<div id="map" style="width: 100%; height: 800px;"></div>
<script src='./js/index.js'></script>
</body>
</html>
初始化echarts实例,造些所需数据
// 实例
const myChart = echarts.init(document.getElementById('map'));
// 市区中心坐标
const geoCoordMap = {
"东城区": [116.418757, 39.937544],
"西城区": [116.366794, 39.910309],
"朝阳区": [116.486409, 39.991489],
"丰台区": [116.286968, 39.863642],
"石景山区": [116.170445, 39.974601],
"海淀区": [116.280316, 40.039074],
"门头沟区": [115.905381, 40.009183],
"房山区": [115.701157, 39.735535],
"通州区": [116.758603, 39.802486],
"顺义区": [116.753525, 40.128936],
"昌平区": [116.235906, 40.318085],
"大兴区": [116.338033, 39.658908],
"怀柔区": [116.607122, 40.524272],
"平谷区": [117.112335, 40.244783],
"密云区": [116.943352, 40.477362],
"延庆区": [115.985006, 40.465325]
};
const rawData = [
// ["东城区",10,20,30],
// ["西城区",10,20,30],
["朝阳区",10,20,30],
["丰台区",10,20,30],
["石景山区",10,20,30],
["海淀区",10,20,30],
["门头沟区",10,20,30],
["房山区",10,20,30],
["通州区",10,20,30],
["顺义区",10,20,30],
["昌平区",10,20,30],
["大兴区",10,20,30],
["怀柔区",10,20,30],
["平谷区",10,20,30],
["密云区",10,20,30],
["延庆区",10,20,30]
];
geoCoordMap
是北京市几个区的大致中心位置,柱状图的铺设位置就是根据这些区域坐标设置的。
rawData
是区域的业务数据,一般是由后端接口返回的。这里东城区、和西城区因为距离太近,所以不渲染这两个区。
地图配置
const option = {
// 地图背景颜色
backgroundColor: new echarts.graphic.RadialGradient(0.5, 0.5, 0.4, [{
offset: 0,
color: '#4b5769'
}, {
offset: 1,
color: '#404a59'
}]),
geo: {
map: '北京',
roam: true, // 是否开启鼠标缩放和平移漫游
zoom: 1.155, // 地图初始大小
center: [116.366794, 40.400309], // 初始中心位置
label: { // 区域文字
emphasis: { // 区域激活时配置
show: false
}
},
itemStyle: { // 地区块儿颜色
normal: { // 普通状态
areaColor: '#55C3FC',
borderColor: '#fff'
},
emphasis: { // 激活状态
areaColor: '#21AEF8'
}
}
},
series: []
};
// 应用配置
myChart.setOption(option);
此时基础的地图效果就出来了:
下一步就是,在各区域上铺设柱状图。
配置柱状图,并铺设到每个区域上
声明柱状图配置项
const areaOption = {
xAxis: [],
yAxis: [],
tooltip: {
trigger: 'axis'
},
grid: [],
series: []
};
遍历区域数据,并铺设柱状图
// 遍历
echarts.util.each(rawData, function(dataItem, idx) {
// 获取坐标
var geoCoord = geoCoordMap[dataItem[0]];
// 转换坐标系上的点到像素坐标值
var coord = myChart.convertToPixel('geo', geoCoord);
idx += ''; // 转成字符串
// X轴配置
areaOption.xAxis.push({
id: idx, // 组件id,在配置中引用标识
gridIndex: idx, // x轴所在的grid的索引
type: 'category', // 坐标轴类型
name: dataItem[0], // 坐标轴名称
nameLocation: 'middle', // 坐标轴名称显示位置
nameGap: 3, // 坐标轴名称与轴线之间的距离
splitLine: { // 坐标轴在 grid 区域中的分隔线
show: false
},
axisTick: { // 坐标轴刻度
show: false
},
axisLabel: { // 坐标轴刻度标签
show: false
},
axisLine: { // 坐标轴轴线
onZero: false,
lineStyle: {
color: '#666'
}
},
data: ["数据A","数据B","数据C"], // 类目数据
z: 100
});
// Y轴配置
areaOption.yAxis.push({
id: idx, // 组件id,在配置中引用标识
gridIndex: idx, // x轴所在的grid的索引
splitLine: { // 坐标轴在 grid 区域中的分隔线
show: false
},
axisTick: { // 坐标轴刻度
show: false
},
axisLabel: { // 坐标轴刻度标签
show: false
},
axisLine: { // 坐标轴轴线
show: false,
lineStyle: {
color: '#1C70B6'
}
},
z: 100
});
// 坐标系配置
areaOption.grid.push({
id: idx, // 组件id,在配置中引用标识
width: 30, // 组件的宽度
height: 40, // 组件的高度
left: coord[0] - 15, // 离容器左侧的距离
top: coord[1] - 15, // 离容器上侧的距离
z: 100
});
// 图标系列配置
areaOption.series.push({
id: idx, // 组件id,在配置中引用标识
type: 'bar', // 柱状图
xAxisId: idx, // 使用的x轴的id
yAxisId: idx, // 使用的y轴的id
barGap: 0, // 柱间距离
barCategoryGap: 0, // 同一系列的柱间距离
data: [30,50,20], // 柱子数据
z: 100,
itemStyle: { // 柱子样式
normal: {
color: function(params){
// 柱状图每根柱子颜色
var colorList = ['#F75D5D','#59ED4F','#4C91E7'];
return colorList[params.dataIndex];
}
}
}
});
});
// 应用配置
myChart.setOption(areaOption);
这时柱状图效果也出来了:
但是还有一个问题,如果地图不能拖拽和缩放,此时的效果就已经满足需求了,但是如果配置了拖拽和缩放,当缩放或拖拽时,柱状图与地图将发生分离。
这是因为地图和柱状图本来就不是同一个图层,只是柱状图使用了根据地图的坐标系转换的坐标而铺设的。
完善拖拽和缩放时的效果(完整代码)
const myChart = echarts.init(document.getElementById('map'));
// 市区坐标
const geoCoordMap = {
"东城区": [116.418757, 39.937544],
"西城区": [116.366794, 39.910309],
"朝阳区": [116.486409, 39.991489],
"丰台区": [116.286968, 39.863642],
"石景山区": [116.170445, 39.974601],
"海淀区": [116.280316, 40.039074],
"门头沟区": [115.905381, 40.009183],
"房山区": [115.701157, 39.735535],
"通州区": [116.758603, 39.802486],
"顺义区": [116.753525, 40.128936],
"昌平区": [116.235906, 40.318085],
"大兴区": [116.338033, 39.658908],
"怀柔区": [116.607122, 40.524272],
"平谷区": [117.112335, 40.244783],
"密云区": [116.943352, 40.477362],
"延庆区": [115.985006, 40.465325]
};
const rawData = [
// ["东城区",10,20,30],
// ["西城区",10,20,30],
["朝阳区",10,20,30],
["丰台区",10,20,30],
["石景山区",10,20,30],
["海淀区",10,20,30],
["门头沟区",10,20,30],
["房山区",10,20,30],
["通州区",10,20,30],
["顺义区",10,20,30],
["昌平区",10,20,30],
["大兴区",10,20,30],
["怀柔区",10,20,30],
["平谷区",10,20,30],
["密云区",10,20,30],
["延庆区",10,20,30]
];
const option = {
// 地图背景颜色
backgroundColor: new echarts.graphic.RadialGradient(0.5, 0.5, 0.4, [{
offset: 0,
color: '#4b5769'
}, {
offset: 1,
color: '#404a59'
}]),
geo: {
map: '北京',
roam: true, // 是否开启鼠标缩放和平移漫游
zoom: 1.155, // 地图初始大小
center: [116.366794, 40.400309], // 初始中心位置
label: { // 区域文字
emphasis: { // 区域激活时配置
show: false
}
},
itemStyle: { // 地区块儿颜色
normal: { // 普通状态
areaColor: '#55C3FC',
borderColor: '#fff'
},
emphasis: { // 激活状态
areaColor: '#21AEF8'
}
}
},
series: []
};
myChart.setOption(option);
// 渲染各区域上的柱状图
renderEachArea()
// 监听geo变化,并使用防抖
myChart.on('geoRoam', _.debounce(renderEachArea,0));
// 封装方法--渲染各区域上的柱状图
function renderEachArea() {
const areaOption = {
xAxis: [],
yAxis: [],
tooltip: {
trigger: 'axis'
},
grid: [],
series: []
};
echarts.util.each(rawData, function(dataItem, idx) {
// 获取坐标
var geoCoord = geoCoordMap[dataItem[0]];
// 转换坐标系上的点到像素坐标值
var coord = myChart.convertToPixel('geo', geoCoord);
idx += '';
// X轴配置
areaOption.xAxis.push({
id: idx, // 组件id,在配置中引用标识
gridIndex: idx, // x轴所在的grid的索引
type: 'category', // 坐标轴类型
name: dataItem[0], // 坐标轴名称
nameLocation: 'middle', // 坐标轴名称显示位置
nameGap: 3, // 坐标轴名称与轴线之间的距离
splitLine: { // 坐标轴在 grid 区域中的分隔线
show: false
},
axisTick: { // 坐标轴刻度
show: false
},
axisLabel: { // 坐标轴刻度标签
show: false
},
axisLine: { // 坐标轴轴线
onZero: false,
lineStyle: {
color: '#666'
}
},
data: ["数据A","数据B","数据C"], // 类目数据
z: 100
});
// Y轴配置
areaOption.yAxis.push({
id: idx, // 组件id,在配置中引用标识
gridIndex: idx, // x轴所在的grid的索引
splitLine: { // 坐标轴在 grid 区域中的分隔线
show: false
},
axisTick: { // 坐标轴刻度
show: false
},
axisLabel: { // 坐标轴刻度标签
show: false
},
axisLine: { // 坐标轴轴线
show: false,
lineStyle: {
color: '#1C70B6'
}
},
z: 100
});
// 坐标系配置
areaOption.grid.push({
id: idx, // 组件id,在配置中引用标识
width: 30, // 组件的宽度
height: 40, // 组件的高度
left: coord[0] - 15, // 离容器左侧的距离
top: coord[1] - 15, // 离容器上侧的距离
z: 100
});
// 图标系列配置
areaOption.series.push({
id: idx, // 组件id,在配置中引用标识
type: 'bar', // 柱状图
xAxisId: idx, // 使用的x轴的id
yAxisId: idx, // 使用的y轴的id
barGap: 0, // 柱间距离
barCategoryGap: 0, // 同一系列的柱间距离
data: [30,50,20], // 柱子数据
z: 100,
itemStyle: { // 柱子样式
normal: {
color: function(params){
// 柱状图每根柱子颜色
var colorList = ['#F75D5D','#59ED4F','#4C91E7'];
return colorList[params.dataIndex];
}
}
}
});
});
// 应用配置
myChart.setOption(areaOption);
}
监听geo变化,并将铺设柱状图操作封装成方法,以便在监听函数的回调中调用。
此处考虑性能问题,加了防抖函数,使用的lodash.js。
根据此案例可以自行试验下,在地图上铺设折线图、饼状图等其他类型图标,可以做到举一反三才是真的学到了!