引言:ECharts地图可视化的魅力与价值
在当今数据驱动的时代,地图可视化已经成为展示地理空间数据的最有效方式之一。ECharts作为百度开源的强大数据可视化库,其地图功能尤其出色,能够将枯燥的地理数据转化为生动、直观的视觉呈现。”地图点亮”效果——即通过颜色渐变、热力图、散点标记等方式突出显示特定城市或区域——是数据可视化中最具视觉冲击力和信息传达效率的技术之一。
地图点亮技术广泛应用于商业分析、智慧城市、疫情防控、旅游规划等多个领域。例如,电商平台可以用它展示各城市销售热度,政府部门可以用它呈现人口流动趋势,医疗机构可以用它标记疫情分布。掌握ECharts地图点亮技术,不仅能够提升数据展示的专业性,更能让数据”说话”,让决策者快速抓住关键信息。
本文将从基础概念入手,深入剖析ECharts地图点亮的核心技术,通过完整的代码示例展示各种高级技巧,并结合实战案例提供最佳实践建议。无论你是数据可视化初学者还是有经验的开发者,都能从中获得实用的技术指导和灵感启发。
ECharts基础概念与环境准备
ECharts简介与核心优势
ECharts(Enterprise Charts)是百度开源的、功能丰富的数据可视化库,基于JavaScript开发,兼容性强,支持多种图表类型。其核心优势包括:
- 丰富的图表类型:支持折线图、柱状图、饼图、散点图、地理坐标系/地图等
- 强大的交互能力:提供数据视图、数据区域缩放、图例切换等交互组件
- 优雅的视觉设计:支持多主题、自定义样式、渐变色、动画效果
- 良好的性能优化:支持大数据量渲染、增量渲染、WebGL加速
- 活跃的社区支持:持续更新,文档完善,案例丰富
环境搭建与引入方式
在使用ECharts之前,需要先将其引入到项目中。主要有以下几种方式:
1. CDN引入(推荐用于快速原型开发)
<!-- 引入ECharts核心库 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<!-- 引入中国地图数据(如果需要显示中国地图) -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/map/js/china.js"></script>
<!-- 引入世界地图数据 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/map/js/world.js"></script>
2. NPM安装(推荐用于现代前端项目)
npm install echarts --save
然后在JavaScript文件中引入:
// 引入ECharts核心模块
import * as echarts from 'echarts';
// 引入中国地图数据
import 'echarts/map/js/china';
3. 下载源码引入
从ECharts官网下载完整包,通过本地文件引入。
基础容器设置
创建一个基本的ECharts地图需要HTML容器和初始化代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>ECharts地图点亮示例</title>
<style>
#main {
width: 100%;
height: 600px;
margin: 0 auto;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<!-- ECharts容器 -->
<div id="main"></div>
<!-- 引入ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/map/js/china.js"></script>
<script>
// 初始化ECharts实例
var myChart = echarts.init(document.getElementById('main'));
// 配置项(后续会详细讲解)
var option = {
// 这里填写配置
};
// 应用配置
myChart.setOption(option);
</script>
</body>
</html>
地图点亮核心技术详解
1. 基础地图渲染
地图点亮的第一步是渲染基础地图。ECharts通过geo组件或直接在series中使用map类型来实现。
// 基础地图配置
var option = {
// 视觉映射组件(用于颜色映射)
visualMap: {
min: 0,
max: 100,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027']
},
textStyle: {
color: '#333'
}
},
// 地理坐标系组件
geo: {
map: 'china', // 使用中国地图
roam: true, // 允许缩放和平移
label: {
show: true, // 显示省份标签
color: '#333'
},
itemStyle: {
areaColor: '#eee', // 默认区域颜色
borderColor: '#999' // 边框颜色
},
emphasis: {
itemStyle: {
areaColor: '#ccc' // 高亮颜色
}
}
},
// 系列列表
series: [
// 这里可以添加各种点亮效果
]
};
2. 颜色渐变点亮(VisualMap)
颜色渐变是最基础的点亮方式,通过visualMap组件将数据值映射到颜色,实现不同城市根据数据大小显示不同颜色。
完整示例:各省GDP数据可视化
// 模拟数据:2023年部分省份GDP(单位:万亿元)
var gdpData = [
{ name: '广东', value: 13.57 },
{ name: '江苏', value: 12.82 },
{ name: '山东', value: 8.74 },
{ name: '浙江', value: 7.77 },
{ name: '河南', value: 6.13 },
{ name: '四川', value: 5.67 },
{ name: '湖北', value: 5.37 },
{ name: '福建', value: 5.31 },
{ name: '湖南', value: 4.87 },
{ name: '安徽', value: 4.50 },
{ name: '上海', value: 4.47 },
{ name: '河北', value: 4.24 },
{ name: '北京', value: 4.03 },
{ name: '陕西', value: 3.28 },
{ name: '江西', value: 3.22 },
{ name: '重庆', value: 2.91 },
{ name: '辽宁', value: 2.89 },
{ name: '云南', value: 2.87 },
{ name: '广西', value: 2.47 },
{ name: '内蒙古', value: 2.32 },
{ name: '山西', value: 2.26 },
{ name: '贵州', value: 2.02 },
{ name: '天津', value: 1.63 },
{ name: '黑龙江', value: 1.59 },
{ name: '吉林', value: 1.31 },
{ name: '甘肃', value: 1.12 },
{ name: '海南', value: 0.71 },
{ name: '宁夏', value: 0.50 },
{ name: '青海', value: 0.35 },
{ name: '西藏', value: 0.22 },
{ name: '新疆', value: 1.77 }
];
// 配置项
var option = {
title: {
text: '2023年中国各省GDP数据可视化',
subtext: '数据来源:国家统计局(模拟数据)',
left: 'center',
textStyle: {
color: '#333',
fontSize: 18
}
},
// 工具提示
tooltip: {
trigger: 'item',
formatter: function(params) {
if (params.data) {
return `${params.name}<br/>GDP: ${params.value} 万亿元`;
}
return params.name;
}
},
// 视觉映射
visualMap: {
min: 0,
max: 14,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695']
},
textStyle: {
color: '#333'
},
bottom: 30,
left: 20
},
// 地理坐标系
geo: {
map: 'china',
roam: true,
label: {
show: true,
color: '#333',
fontSize: 10
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
},
label: {
color: '#000',
fontSize: 12
}
}
},
// 系列
series: [
{
name: 'GDP',
type: 'map',
map: 'china',
geoIndex: 0, // 使用geo组件的配置
data: gdpData,
// 高亮样式
emphasis: {
label: {
show: true
}
}
}
]
};
// 初始化
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
// 响应窗口大小变化
window.addEventListener('resize', function() {
myChart.resize();
});
3. 散点标记点亮(Scatter)
散点标记可以在地图上精确标注城市位置,通过点的大小、颜色来表示数据大小,适合展示具体城市的数值。
完整示例:主要城市空气质量指数(AQI)可视化
// 城市坐标数据(经度,纬度)
var cityCoordinates = {
'北京': [116.405285, 39.904989],
'上海': [121.472644, 31.231706],
'广州': [113.264385, 23.129112],
'深圳': [114.057868, 22.543099],
'成都': [104.066541, 30.572269],
'杭州': [120.15507, 30.274085],
'武汉': [114.305539, 30.592756],
'西安': [108.940155, 34.341568],
'重庆': [106.551557, 29.563011],
'南京': [118.796877, 32.060255],
'天津': [117.200983, 39.084158],
'沈阳': [123.431382, 41.805698],
'郑州': [113.625328, 34.746602],
'长沙': [112.938814, 28.228209],
'青岛': [120.38264, 36.067082],
'宁波': [121.62462, 29.860313],
'厦门': [118.089425, 24.479823],
'大连': [121.614682, 38.914003],
'昆明': [102.712251, 24.846577],
'哈尔滨': [126.642464, 45.756967]
};
// AQI数据(模拟)
var aqiData = [
{ name: '北京', value: 85 },
{ name: '上海', value: 45 },
{ name: '广州', value: 35 },
{ name: '深圳', value: 28 },
{ name: '成都', value: 62 },
{ name: '杭州', value: 38 },
{ name: '武汉', value: 55 },
{ name: '西安', value: 78 },
{ name: '重庆', value: 68 },
{ name: '南京', value: 42 },
{ name: '天津', value: 92 },
{ name: '沈阳', value: 88 },
{ name: '郑州', value: 75 },
{ name: '长沙', value: 48 },
{ name: '青岛', value: 52 },
{ name: '宁波', value: 36 },
{ name: '厦门', value: 25 },
{ name: '大连', value: 65 },
{ name: '昆明', value: 32 },
{ name: '哈尔滨', value: 95 }
];
// 转换为散点数据格式
var scatterData = aqiData.map(item => {
var coord = cityCoordinates[item.name];
return {
name: item.name,
value: [...coord, item.value], // [经度, 纬度, AQI值]
aqi: item.value
};
});
// 配置项
var option = {
title: {
text: '主要城市空气质量指数(AQI)分布',
subtext: '数值越低,空气质量越好',
left: 'center',
textStyle: {
color: '#333'
}
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return `${params.name}<br/>AQI: ${params.data.aqi}`;
}
},
// 视觉映射(用于点的大小)
visualMap: {
min: 20,
max: 100,
dimension: 2, // 使用第三维数据(AQI值)
inRange: {
symbolSize: [8, 25], // 点的大小范围
color: ['#1a9850', '#66bd63', '#a6d96a', '#d9ef8b', '#fee08b', '#fdae61', '#f46d43', '#d73027']
},
text: ['高AQI', '低AQI'],
textStyle: {
color: '#333'
},
bottom: 30,
left: 20
},
// 地理坐标系
geo: {
map: 'china',
roam: true,
label: {
show: false // 不显示省份标签,避免干扰
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
// 系列
series: [
{
name: 'AQI',
type: 'scatter',
coordinateSystem: 'geo',
data: scatterData,
symbol: 'circle',
symbolSize: function(data) {
// 根据AQI值动态调整点的大小
return Math.max(8, data[2] / 4);
},
label: {
show: true,
formatter: '{b}',
position: 'right',
color: '#333',
fontSize: 10
},
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.3)'
},
emphasis: {
scale: true,
label: {
show: true,
fontSize: 12,
fontWeight: 'bold'
}
}
}
]
};
// 初始化
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
4. 热力图点亮(Heatmap)
热力图适合展示数据的密度分布,通过颜色的深浅来表示数值大小,能够直观呈现区域的热度分布。
完整示例:城市人口密度热力图
// 城市坐标数据(经度,纬度,人口密度)
var heatmapData = [
[116.405285, 39.904989, 1300], // 北京
[121.472644, 31.231706, 3800], // 上海
[113.264385, 23.129112, 2400], // 广州
[114.057868, 22.543099, 8800], // 深圳
[104.066541, 30.572269, 1100], // 成都
[120.15507, 30.274085, 1300], // 杭州
[114.305539, 30.592756, 1200], // 武汉
[108.940155, 34.341568, 1000], // 西安
[106.551557, 29.563011, 900], // 重庆
[118.796877, 32.060255, 1200], // 南京
[117.200983, 39.084158, 1300], // 天津
[123.431382, 41.805698, 600], // 沈阳
[113.625328, 34.746602, 1200], // 郑州
[112.938814, 28.228209, 1000], // 长沙
[120.38264, 36.067082, 800], // 青岛
[121.62462, 29.860313, 1300], // 宁波
[118.089425, 24.479823, 1000], // 厦门
[121.614682, 38.914003, 700], // 大连
[102.712251, 24.846577, 800], // 昆明
[126.642464, 45.756967, 500] // 哈尔滨
];
// 配置项
var option = {
title: {
text: '主要城市人口密度热力图',
subtext: '单位:人/平方公里',
left: 'center',
textStyle: {
color: '#333'
}
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return `人口密度: ${params.value[2]} 人/km²`;
}
},
// 视觉映射
visualMap: {
min: 500,
max: 9000,
calculable: true,
inRange: {
color: ['#50a3ba', '#eac736', '#d94e5d']
},
textStyle: {
color: '#333'
},
bottom: 30,
left: 20
},
// 地理坐标系
geo: {
map: 'china',
roam: true,
label: {
show: false
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
// 系列
series: [
{
name: '人口密度',
type: 'heatmap',
coordinateSystem: 'geo',
data: heatmapData,
pointSize: 20, // 每个点的大小
blurSize: 30 // 模糊大小,使热力过渡更自然
}
]
};
// 初始化
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
5. 路径点亮(Lines)
路径效果可以展示城市之间的联系,如人口流动、物流运输、通信往来等,通过线条的动画和颜色来突出显示。
完整示例:城市间航班线路图
// 基础数据
var cities = {
'北京': [116.405285, 39.904989],
'上海': [121.472644, 31.231706],
'广州': [113.264385, 23.129112],
'深圳': [114.057868, 22.543099],
'成都': [104.066541, 30.572269],
'杭州': [120.15507, 30.274085],
'武汉': [114.305539, 30.592756],
'西安': [108.940155, 34.341568],
'重庆': [106.551557, 29.563011],
'南京': [118.796877, 32.060255]
};
// 航线数据(起点, 终点, 班次数量)
var routes = [
{ from: '北京', to: '上海', count: 50 },
{ from: '北京', to: '广州', count: 35 },
{ from: '北京', to: '深圳', count: 30 },
{ from: '北京', to: '成都', count: 25 },
{ from: '上海', to: '广州', count: 40 },
{ from: '上海', to: '深圳', count: 38 },
{ from: '上海', to: '杭州', count: 45 },
{ from: '广州', to: '深圳', count: 55 },
{ from: '广州', to: '成都', count: 20 },
{ from: '成都', to: '西安', count: 28 },
{ from: '武汉', to: '上海', count: 22 },
{ from: '重庆', to: '深圳', count: 18 },
{ from: '南京', to: '北京', count: 25 },
{ from: '杭州', to: '广州', count: 15 }
];
// 构建lines数据
var linesData = routes.map(route => {
return {
fromName: route.from,
toName: route.to,
coords: [cities[route.from], cities[route.to]],
value: route.count
};
});
// 构建点数据(用于显示城市)
var pointsData = Object.keys(cities).map(city => {
return {
name: city,
value: [...cities[city], 1] // 第三个值用于visualMap
};
});
// 配置项
var option = {
title: {
text: '主要城市间航班线路图',
subtext: '线条粗细代表航班班次数量',
left: 'center',
textStyle: {
color: '#333'
}
},
tooltip: {
trigger: 'item',
formatter: function(params) {
if (params.seriesType === 'lines') {
return `${params.data.fromName} → ${params.data.toName}<br/>班次: ${params.data.value}`;
} else {
return params.name;
}
}
},
// 视觉映射(用于线条颜色)
visualMap: {
min: 10,
max: 60,
calculable: true,
inRange: {
color: ['#50a3ba', '#eac736', '#d94e5d']
},
textStyle: {
color: '#333'
},
bottom: 30,
left: 20,
show: false // 隐藏视觉映射条,因为线条已有颜色
},
// 地理坐标系
geo: {
map: 'china',
roam: true,
label: {
show: true,
color: '#333'
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
// 系列
series: [
// 城市点
{
name: '城市',
type: 'scatter',
coordinateSystem: 'geo',
data: pointsData,
symbol: 'circle',
symbolSize: 8,
label: {
show: true,
formatter: '{b}',
position: 'right',
color: '#333',
fontSize: 10
},
itemStyle: {
color: '#2c3e50',
shadowBlur: 5,
shadowColor: 'rgba(0, 0, 0, 0.2)'
}
},
// 航线
{
name: '航线',
type: 'lines',
coordinateSystem: 'geo',
data: linesData,
lineStyle: {
color: function(params) {
// 根据班次数量动态设置颜色
var count = params.data.value;
if (count > 40) return '#d73027';
if (count > 25) return '#fc8d59';
return '#fee08b';
},
width: function(params) {
// 根据班次数量动态设置宽度
return Math.max(1, params.data.value / 10);
},
opacity: 0.8,
curveness: 0.2 // 曲线弯曲度
},
// 动画效果
effect: {
show: true,
period: 6, // 动画周期
trailLength: 0.7,
color: '#fff',
symbolSize: 3
},
emphasis: {
lineStyle: {
width: 3,
opacity: 1
}
}
}
]
};
// 初始化
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
6. 象形图点亮(PictorialBar)
象形图是一种非常有创意的点亮方式,使用自定义的符号(如飞机、汽车、建筑等)来标记城市,增强视觉吸引力。
完整示例:旅游城市热度象形图
// 城市数据(城市名称, 经度, 纬度, 热度值)
var cityData = [
{ name: '北京', coord: [116.405285, 39.904989], value: 95 },
{ name: '上海', coord: [121.472644, 31.231706], value: 88 },
{ name: '广州', coord: [113.264385, 23.129112], value: 75 },
{ name: '深圳', coord: [114.057868, 22.543099], value: 72 },
{ name: '成都', coord: [104.066541, 30.572269], value: 85 },
{ name: '杭州', coord: [120.15507, 30.274085], value: 82 },
{ name: '西安', coord: [108.940155, 34.341568], value: 78 },
{ name: '重庆', coord: [106.551557, 29.563011], value: 76 },
{ name: '南京', coord: [118.796877, 32.060255], value: 70 },
{ name: '厦门', coord: [118.089425, 24.479823], value: 68 }
];
// 配置项
var option = {
title: {
text: '热门旅游城市热度指数',
subtext: '使用象形图标记',
left: 'center',
textStyle: {
color: '#333'
}
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return `${params.name}<br/>热度: ${params.data.value}`;
}
},
// 视觉映射
visualMap: {
min: 60,
max: 100,
calculable: true,
inRange: {
color: ['#74add1', '#4575b4', '#313695']
},
textStyle: {
color: '#333'
},
bottom: 30,
left: 20
},
// 地理坐标系
geo: {
map: 'china',
roam: true,
label: {
show: true,
color: '#333'
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
// 系列
series: [
// 基础散点(用于visualMap映射)
{
name: '热度',
type: 'scatter',
coordinateSystem: 'geo',
data: cityData.map(item => ({
name: item.name,
value: [...item.coord, item.value]
})),
symbolSize: 0, // 不显示
silent: true, // 不响应交互
tooltip: {
show: false
}
},
// 象形图
{
name: '旅游热度',
type: 'pictorialBar',
coordinateSystem: 'geo',
// 转换为pictorialBar需要的数据格式
data: cityData.map(item => ({
name: item.name,
value: item.value,
// 使用自定义符号
symbol: 'path://M512 512m-448 0a448 448 0 1 0 896 0a448 448 0 1 0-896 0', // 圆形路径
symbolSize: function(params) {
// 根据热度值动态调整大小
return [20 + params.value / 3, 20 + params.value / 3];
},
symbolPosition: 'end',
// 位置偏移,使其在地图上正确显示
itemStyle: {
color: function(params) {
var value = params.value;
if (value > 90) return '#d73027';
if (value > 80) return '#fc8d59';
if (value > 70) return '#fee08b';
return '#91cf60';
},
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.3)'
},
label: {
show: true,
position: 'top',
formatter: '{b}',
color: '#333',
fontSize: 10
}
})),
// 需要自定义定位,因为pictorialBar默认不支持geo坐标系
// 这里使用一个技巧:通过markPoint实现
markPoint: {
symbol: 'circle',
symbolSize: 0,
data: cityData.map(item => ({
name: item.name,
coord: item.coord,
value: item.value,
itemStyle: {
color: function(params) {
var value = params.value;
if (value > 90) return '#d73027';
if (value > 80) return '#fc8d59';
if (value > 70) return '#fee08b';
return '#91cf60';
}
}
}))
}
}
]
};
// 由于pictorialBar在geo中使用有限制,这里提供一个更实用的替代方案
// 使用markPoint + 自定义符号
var option2 = {
title: {
text: '热门旅游城市热度指数',
subtext: '使用自定义标记',
left: 'center',
textStyle: {
color: '#333'
}
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return `${params.name}<br/>热度: ${params.value}`;
}
},
visualMap: {
min: 60,
max: 100,
calculable: true,
inRange: {
color: ['#74add1', '#4575b4', '#313695']
},
textStyle: {
color: '#333'
},
bottom: 30,
left: 20
},
geo: {
map: 'china',
roam: true,
label: {
show: true,
color: '#333'
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
series: [
{
name: '热度',
type: 'scatter',
coordinateSystem: 'geo',
data: cityData.map(item => ({
name: item.name,
value: [...item.coord, item.value]
})),
symbol: 'path://M512 512m-448 0a448 448 0 1 0 896 0a448 448 0 1 0-896 0', // 圆形
symbolSize: function(params) {
return 15 + params.value[2] / 4;
},
label: {
show: true,
formatter: '{b}',
position: 'right',
color: '#333',
fontSize: 10
},
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.3)'
},
emphasis: {
scale: true,
label: {
fontSize: 12,
fontWeight: 'bold'
}
}
}
]
};
// 初始化
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option2);
高级技巧与优化策略
1. 动态数据更新与实时点亮
在实际应用中,数据往往是动态变化的。ECharts支持数据的动态更新,通过setOption方法可以更新数据而不影响其他配置。
完整示例:实时数据更新
// 初始数据
var currentData = [
{ name: '北京', value: 85 },
{ name: '上海', value: 45 },
{ name: '广州', value: 35 },
{ name: '深圳', value: 28 }
];
// 初始化图表
var myChart = echarts.init(document.getElementById('main'));
// 初始配置
var option = {
title: {
text: '实时数据监控',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c}'
},
visualMap: {
min: 0,
max: 100,
inRange: {
color: ['#50a3ba', '#eac736', '#d94e5d']
}
},
geo: {
map: 'china',
roam: true,
label: { show: true }
},
series: [{
type: 'map',
map: 'china',
data: currentData
}]
};
myChart.setOption(option);
// 模拟实时数据更新(每3秒更新一次)
setInterval(function() {
// 生成随机新数据
var newData = currentData.map(item => ({
name: item.name,
value: Math.max(0, Math.min(100, item.value + (Math.random() - 0.5) * 20))
}));
// 更新数据
myChart.setOption({
series: [{
data: newData
}]
});
currentData = newData;
}, 3000);
2. 交互增强:点击事件与下钻
通过ECharts的事件监听机制,可以实现点击城市下钻到更详细的地图(如省份下钻到城市)。
完整示例:点击下钻
// 全国数据
var countryData = [
{ name: '广东', value: 13.57 },
{ name: '江苏', value: 12.82 },
{ name: '山东', value: 8.74 },
{ name: '浙江', value: 7.77 },
{ name: '河南', value: 6.13 }
];
// 省份详细数据(示例:广东省)
var guangdongData = [
{ name: '广州', value: 2.88 },
{ name: '深圳', value: 3.46 },
{ name: '佛山', value: 1.08 },
{ name: '东莞', value: 0.97 },
{ name: '珠海', value: 0.35 }
];
var myChart = echarts.init(document.getElementById('main'));
var currentLevel = 'country'; // 当前显示级别
var currentMap = 'china'; // 当前地图
// 初始配置
function getOption(data, mapName, title) {
return {
title: {
text: title,
left: 'center',
textStyle: { color: '#333' }
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c}'
},
visualMap: {
min: 0,
max: mapName === 'china' ? 14 : 4,
inRange: {
color: ['#e0f3f8', '#74add1', '#313695']
}
},
geo: {
map: mapName,
roam: true,
label: { show: true, color: '#333' },
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
series: [{
type: 'map',
map: mapName,
data: data,
emphasis: {
label: { show: true }
}
}]
};
}
// 显示全国地图
myChart.setOption(getOption(countryData, 'china', '2023年各省GDP(点击省份查看详情)'));
// 点击事件
myChart.on('click', function(params) {
if (currentLevel === 'country' && params.name === '广东') {
// 下钻到广东省
currentLevel = 'province';
currentMap = 'guangdong';
// 注意:这里需要先注册广东省地图数据
// 实际项目中需要引入广东地图数据或使用动态加载
// 这里模拟下钻效果
alert('下钻到广东省详情(需要引入广东地图数据)');
// 如果有广东地图数据,可以这样切换:
// myChart.setOption(getOption(guangdongData, 'guangdong', '广东省各城市GDP(点击返回全国)'));
} else if (currentLevel === 'province') {
// 返回全国地图
currentLevel = 'country';
currentMap = 'china';
myChart.setOption(getOption(countryData, 'china', '2023年各省GDP(点击省份查看详情)'));
}
});
// 提示:实际项目中需要引入省份地图数据
// 可以使用ECharts的registerMap方法动态注册地图
// 示例:
// fetch('path/to/guangdong.json').then(response => response.json()).then(data => {
// echarts.registerMap('guangdong', data);
// });
3. 性能优化:大数据量渲染
当需要渲染大量数据点时(如全国所有县城),需要进行性能优化。
完整示例:大数据量优化
// 模拟大量数据点(1000个)
var largeData = [];
for (var i = 0; i < 1000; i++) {
largeData.push({
name: '城市' + i,
value: [
70 + Math.random() * 60, // 经度
20 + Math.random() * 30, // 纬度
Math.random() * 100 // 值
]
});
}
var myChart = echarts.init(document.getElementById('main'));
var option = {
title: {
text: '大数据量渲染优化示例',
left: 'center'
},
tooltip: {
trigger: 'item'
},
visualMap: {
min: 0,
max: 100,
inRange: {
color: ['#50a3ba', '#eac736', '#d94e5d']
},
show: false // 隐藏视觉映射条以提升性能
},
geo: {
map: 'china',
roam: true,
label: { show: false }, // 不显示标签以提升性能
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
data: largeData,
symbol: 'circle',
symbolSize: 5,
// 关键优化:使用large模式
large: true,
largeThreshold: 2000,
// 使用增量渲染
progressive: 400,
progressiveThreshold: 1000,
// 简化样式
itemStyle: {
color: '#d94e5d',
opacity: 0.6
},
// 禁用不必要的交互
silent: true
}
]
};
myChart.setOption(option);
// 性能监控
console.log('数据点数量:', largeData.length);
4. 自定义地图样式
通过itemStyle、emphasis等配置项,可以深度定制地图的视觉效果。
完整示例:自定义地图样式
var option = {
title: {
text: '自定义地图样式',
left: 'center',
textStyle: {
color: '#fff',
fontSize: 24
}
},
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0,0,0,0.8)',
borderColor: '#777',
textStyle: { color: '#fff' }
},
visualMap: {
min: 0,
max: 100,
inRange: {
color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027']
},
textStyle: {
color: '#fff'
},
bottom: 30,
left: 20
},
geo: {
map: 'china',
roam: true,
// 自定义地图样式
itemStyle: {
areaColor: '#1a1a2e', // 深色背景
borderColor: '#16213e',
borderWidth: 1,
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowOffsetX: 0,
shadowOffsetY: 0
},
// 高亮样式
emphasis: {
itemStyle: {
areaColor: '#0f3460',
borderColor: '#e94560',
borderWidth: 2,
shadowBlur: 15,
shadowColor: 'rgba(233, 69, 96, 0.5)'
},
label: {
color: '#fff',
fontSize: 12,
fontWeight: 'bold'
}
},
// 标签样式
label: {
show: true,
color: '#999',
fontSize: 10
}
},
series: [{
type: 'map',
map: 'china',
data: [
{ name: '广东', value: 95 },
{ name: '江苏', value: 88 },
{ name: '山东', value: 75 },
{ name: '浙江', value: 82 },
{ name: '河南', value: 68 }
],
// 系列级样式覆盖
itemStyle: {
areaColor: '#16213e'
},
emphasis: {
itemStyle: {
areaColor: '#e94560'
}
}
}]
};
5. 多系列组合点亮
将多种点亮效果组合使用,可以创建更丰富的可视化效果。
完整示例:组合效果
// 基础数据
var cityData = [
{ name: '北京', coord: [116.405285, 39.904989], value: 95, aqi: 85 },
{ name: '上海', coord: [121.472644, 31.231706], value: 88, aqi: 45 },
{ name: '广州', coord: [113.264385, 23.129112], value: 75, aqi: 35 },
{ name: '深圳', coord: [114.057868, 22.543099], value: 72, aqi: 28 },
{ name: '成都', coord: [104.066541, 30.572269], value: 85, aqi: 62 }
];
// 构建多系列数据
var scatterData = cityData.map(item => ({
name: item.name,
value: [...item.coord, item.value]
}));
var aqiScatter = cityData.map(item => ({
name: item.name,
value: [...item.coord, item.aqi]
}));
var linesData = [];
for (var i = 0; i < cityData.length - 1; i++) {
linesData.push({
fromName: cityData[i].name,
toName: cityData[i + 1].name,
coords: [cityData[i].coord, cityData[i + 1].coord]
});
}
var myChart = echarts.init(document.getElementById('main'));
var option = {
title: {
text: '多系列组合点亮效果',
subtext: '热度 + 空气质量 + 连接线',
left: 'center',
textStyle: { color: '#333' }
},
tooltip: {
trigger: 'item',
formatter: function(params) {
if (params.seriesType === 'lines') {
return `${params.data.fromName} → ${params.data.toName}`;
} else if (params.seriesName === '热度') {
return `${params.name}<br/>热度: ${params.value[2]}`;
} else if (params.seriesName === '空气质量') {
return `${params.name}<br/>AQI: ${params.value[2]}`;
}
}
},
legend: {
orient: 'vertical',
top: 'center',
right: 20,
data: ['热度', '空气质量', '连接线'],
textStyle: { color: '#333' }
},
geo: {
map: 'china',
roam: true,
label: { show: true, color: '#333' },
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
series: [
// 热度(大点)
{
name: '热度',
type: 'scatter',
coordinateSystem: 'geo',
data: scatterData,
symbol: 'circle',
symbolSize: function(params) {
return 10 + params.value[2] / 5;
},
itemStyle: {
color: '#d73027',
shadowBlur: 10,
shadowColor: 'rgba(215, 48, 39, 0.5)'
},
emphasis: {
scale: true
}
},
// 空气质量(小点)
{
name: '空气质量',
type: 'scatter',
coordinateSystem: 'geo',
data: aqiScatter,
symbol: 'circle',
symbolSize: 6,
itemStyle: {
color: '#1a9850',
borderColor: '#fff',
borderWidth: 1
}
},
// 连接线
{
name: '连接线',
type: 'lines',
coordinateSystem: 'geo',
data: linesData,
lineStyle: {
color: '#4575b4',
width: 2,
opacity: 0.6,
curveness: 0.2
},
effect: {
show: true,
period: 4,
trailLength: 0.5,
symbol: 'arrow',
symbolSize: 6
}
}
]
};
myChart.setOption(option);
实战应用案例
案例1:电商销售热力图
场景:展示全国各省份的销售数据,帮助决策者快速识别高潜力市场。
数据结构:
var salesData = [
{ name: '广东', value: 1250 },
{ name: '江苏', value: 980 },
{ name: '浙江', value: 850 },
{ name: '山东', value: 720 },
{ name: '河南', value: 680 },
{ name: '四川', value: 650 },
{ name: '湖北', value: 580 },
{ name: '福建', value: 560 },
{ name: '湖南', value: 520 },
{ name: '安徽', value: 480 }
];
完整实现:
// 电商销售热力图
var salesChart = echarts.init(document.getElementById('sales-map'));
var option = {
title: {
text: '全国销售热力图',
subtext: '单位:万元',
left: 'center',
textStyle: { color: '#2c3e50', fontSize: 20 }
},
tooltip: {
trigger: 'item',
formatter: function(params) {
if (params.data) {
return `${params.name}<br/>销售额: ${params.value}万元<br/>占比: ${((params.value / 7270) * 100).toFixed(1)}%`;
}
return params.name;
},
backgroundColor: 'rgba(255,255,255,0.95)',
borderColor: '#ddd',
textStyle: { color: '#333' },
padding: 12
},
visualMap: {
min: 400,
max: 1300,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['#e0f3f8', '#74add1', '#313695']
},
textStyle: { color: '#2c3e50' },
bottom: 40,
left: 20,
itemWidth: 20,
itemHeight: 100
},
geo: {
map: 'china',
roam: true,
zoom: 1.1,
label: {
show: true,
color: '#2c3e50',
fontSize: 11,
fontWeight: 'bold'
},
itemStyle: {
areaColor: '#ecf0f1',
borderColor: '#bdc3c7',
borderWidth: 1
},
emphasis: {
itemStyle: {
areaColor: '#34495e',
borderColor: '#2c3e50',
borderWidth: 2
},
label: {
color: '#fff',
fontSize: 12
}
}
},
series: [
{
type: 'map',
map: 'china',
geoIndex: 0,
data: salesData,
emphasis: {
label: { show: true }
}
},
// 添加城市标记(Top5)
{
type: 'scatter',
coordinateSystem: 'geo',
data: [
{ name: '广东', value: [113.264385, 23.129112, 1250] },
{ name: '江苏', value: [118.796877, 32.060255, 980] },
{ name: '浙江', value: [120.15507, 30.274085, 850] }
],
symbol: 'circle',
symbolSize: 15,
label: {
show: true,
formatter: '{b}',
position: 'top',
color: '#e74c3c',
fontSize: 12,
fontWeight: 'bold'
},
itemStyle: {
color: '#e74c3c',
shadowBlur: 10,
shadowColor: 'rgba(231, 76, 60, 0.5)'
}
}
]
};
salesChart.setOption(option);
// 添加点击事件:显示详细信息
salesChart.on('click', function(params) {
if (params.data) {
// 这里可以弹出模态框或跳转到详情页
alert(`省份: ${params.name}\n销售额: ${params.value}万元\n\n点击确定查看更多详情...`);
}
});
案例2:疫情防控实时追踪
场景:实时展示疫情分布,支持时间轴播放。
完整实现:
// 疫情数据(模拟)
var epidemicData = {
'2023-01-01': [
{ name: '北京', value: 150 },
{ name: '上海', value: 80 },
{ name: '广东', value: 120 }
],
'2023-01-02': [
{ name: '北京', value: 180 },
{ name: '上海', value: 95 },
{ name: '广东', value: 140 },
{ name: '浙江', value: 50 }
],
'2023-01-03': [
{ name: '北京', value: 200 },
{ name: '上海', value: 110 },
{ name: '广东', value: 160 },
{ name: '浙江', value: 70 },
{ name: '江苏', value: 45 }
]
};
var epidemicChart = echarts.init(document.getElementById('epidemic-map'));
var currentIndex = 0;
var dates = Object.keys(epidemicData);
// 初始配置
var option = {
title: {
text: '疫情实时追踪',
left: 'center',
textStyle: { color: '#c0392b', fontSize: 24 }
},
tooltip: {
trigger: 'item',
formatter: function(params) {
if (params.data) {
return `${params.name}<br/>新增病例: ${params.value}例`;
}
return params.name;
},
backgroundColor: 'rgba(192, 57, 43, 0.9)',
borderColor: '#e74c3c',
textStyle: { color: '#fff' }
},
visualMap: {
min: 0,
max: 250,
text: ['高风险', '低风险'],
realtime: false,
calculable: true,
inRange: {
color: ['#e0f3f8', '#fdae61', '#d73027']
},
textStyle: { color: '#333' },
bottom: 80,
left: 20
},
geo: {
map: 'china',
roam: true,
label: {
show: true,
color: '#333',
fontSize: 10
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
series: [{
type: 'map',
map: 'china',
data: epidemicData[dates[0]],
emphasis: {
label: { show: true }
}
}],
// 时间轴
timeline: {
axisType: 'category',
autoPlay: true,
playInterval: 2000,
data: dates,
left: 50,
right: 50,
bottom: 20,
label: {
color: '#333',
fontSize: 12
},
itemStyle: {
color: '#3498db'
},
controlStyle: {
showNextBtn: true,
showPrevBtn: true,
normal: {
color: '#3498db',
borderColor: '#3498db'
},
emphasis: {
color: '#e74c3c',
borderColor: '#e74c3c'
}
}
}
};
epidemicChart.setOption(option);
// 监听时间轴变化
epidemicChart.on('timelinechanged', function(params) {
currentIndex = params.currentIndex;
var currentDate = dates[currentIndex];
var currentData = epidemicData[currentDate];
epidemicChart.setOption({
series: [{
data: currentData
}],
title: {
text: `疫情实时追踪 - ${currentDate}`,
textStyle: { color: '#c0392b', fontSize: 24 }
}
});
});
// 手动控制播放/暂停
var isPlaying = true;
document.getElementById('play-pause').addEventListener('click', function() {
isPlaying = !isPlaying;
if (isPlaying) {
epidemicChart.dispatchAction({
type: 'timelinePlayChange',
playInterval: 2000
});
this.textContent = '暂停';
} else {
epidemicChart.dispatchAction({
type: 'timelinePlayChange',
playInterval: 0
});
this.textContent = '播放';
}
});
案例3:旅游景点热度分布
场景:展示全国5A级景区的热度分布,支持筛选和交互。
完整实现:
// 景点数据(模拟)
var attractions = [
{ name: '故宫', coord: [116.397, 39.916], city: '北京', type: '历史', value: 98 },
{ name: '长城', coord: [116.024, 40.362], city: '北京', type: '历史', value: 95 },
{ name: '西湖', coord: [120.15, 30.25], city: '杭州', type: '自然', value: 92 },
{ name: '黄山', coord: [118.15, 29.98], city: '黄山', type: '自然', value: 88 },
{ name: '九寨沟', coord: [103.88, 33.25], city: '阿坝', type: '自然', value: 85 },
{ name: '兵马俑', coord: [108.94, 34.34], city: '西安', type: '历史', value: 90 },
{ name: '外滩', coord: [121.49, 31.24], city: '上海', type: '城市', value: 87 },
{ name: '张家界', coord: [110.48, 29.33], city: '张家界', type: '自然', value: 83 },
{ name: '鼓浪屿', coord: [118.08, 24.46], city: '厦门', type: '人文', value: 82 },
{ name: '峨眉山', coord: [103.48, 29.59], city: '乐山', type: '自然', value: 80 }
];
var tourismChart = echarts.init(document.getElementById('tourism-map'));
// 筛选功能
var currentType = '全部';
var typeFilter = document.getElementById('type-filter');
typeFilter.addEventListener('change', function() {
currentType = this.value;
updateChart();
});
function updateChart() {
var filteredData = currentType === '全部'
? attractions
: attractions.filter(item => item.type === currentType);
var scatterData = filteredData.map(item => ({
name: item.name,
value: [...item.coord, item.value],
type: item.type
}));
tourismChart.setOption({
series: [{
data: scatterData
}]
});
}
var option = {
title: {
text: '全国5A级景区热度分布',
subtext: '支持按类型筛选',
left: 'center',
textStyle: { color: '#2c3e50' }
},
tooltip: {
trigger: 'item',
formatter: function(params) {
var data = params.data;
return `${data.name}<br/>城市: ${data.type}<br/>热度: ${data.value[2]}`;
}
},
legend: {
orient: 'vertical',
top: 'center',
right: 20,
data: ['历史', '自然', '城市', '人文'],
textStyle: { color: '#333' }
},
visualMap: {
min: 75,
max: 100,
dimension: 2,
inRange: {
symbolSize: [10, 25],
color: ['#91cf60', '#fc8d59', '#d73027']
},
textStyle: { color: '#333' },
bottom: 30,
left: 20
},
geo: {
map: 'china',
roam: true,
label: {
show: true,
color: '#333',
fontSize: 10
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#999'
},
emphasis: {
itemStyle: {
areaColor: '#e0e0e0'
}
}
},
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
data: scatterData,
symbol: 'circle',
symbolSize: function(params) {
return 10 + params.value[2] / 5;
},
label: {
show: true,
formatter: '{b}',
position: 'right',
color: '#333',
fontSize: 9
},
itemStyle: {
shadowBlur: 8,
shadowColor: 'rgba(0, 0, 0, 0.3)'
},
emphasis: {
scale: true,
label: {
fontSize: 11,
fontWeight: 'bold'
}
}
}
]
};
tourismChart.setOption(option);
最佳实践与常见问题
1. 数据准备与格式化
最佳实践:
- 数据格式统一:确保所有数据点都有
name和value属性 - 坐标精度:使用标准的经纬度坐标(WGS84)
- 数据清洗:处理缺失值和异常值
- 单位统一:保持数据单位一致
// 数据格式化函数
function formatData(rawData) {
return rawData.map(item => ({
name: item.name,
value: [
parseFloat(item.lng),
parseFloat(item.lat),
parseFloat(item.value)
],
// 保留原始数据用于tooltip
rawValue: item.value
}));
}
2. 性能优化清单
| 优化策略 | 实现方式 | 适用场景 |
|---|---|---|
| 数据分页 | 只渲染可视区域数据 | 大数据量(>5000点) |
| 简化样式 | 减少阴影、渐变等复杂效果 | 性能要求高的场景 |
| 关闭动画 | 设置animation: false |
实时数据更新 |
使用large模式 |
设置large: true |
大数据量散点图 |
| 延迟加载 | 异步加载地图数据 | 首屏性能优化 |
3. 常见问题解决方案
问题1:地图不显示
// 解决方案:确保地图数据已注册
if (!echarts.getMap('china')) {
// 动态加载地图数据
fetch('path/to/china.json')
.then(response => response.json())
.then(data => {
echarts.registerMap('china', data);
myChart.setOption(option);
});
}
问题2:中文显示乱码
<!-- 确保HTML文件使用UTF-8编码 -->
<meta charset="UTF-8">
问题3:移动端适配
// 响应式设计
window.addEventListener('resize', function() {
myChart.resize();
});
// 移动端触摸优化
option = {
// 增大触摸区域
series: [{
emphasis: {
scale: true,
label: {
show: true
}
}
}]
};
问题4:数据更新卡顿
// 使用动画配置优化
option = {
animation: false, // 关闭全局动画
series: [{
animation: false,
animationDuration: 0,
animationDurationUpdate: 300,
animationEasing: 'linear'
}]
};
4. 可访问性考虑
- 颜色对比度:确保文字与背景有足够对比度
- 键盘导航:支持Tab键切换图例
- 屏幕阅读器:添加ARIA标签
- 替代文本:为图表提供文本描述
// 添加ARIA支持
option = {
aria: {
enabled: true,
description: '这是一个展示全国各省GDP数据的地图可视化图表'
}
};
总结
ECharts地图点亮技术是数据可视化领域的重要工具,通过颜色渐变、散点标记、热力图、路径动画等多种方式,能够将地理数据转化为直观、生动的视觉呈现。掌握这些技术需要:
- 基础扎实:理解ECharts的核心概念和配置项
- 数据处理:能够清洗、转换和格式化地理数据
- 视觉设计:合理运用颜色、大小、动画等视觉元素
- 交互设计:提供良好的用户体验和数据探索能力
- 性能优化:确保在大数据量下的流畅运行
从简单的颜色映射到复杂的多系列组合,从静态展示到实时动态更新,ECharts提供了丰富的功能来满足各种业务场景的需求。通过本文的详细讲解和完整代码示例,相信你已经掌握了ECharts地图点亮的核心技术和实战技巧。
在实际项目中,建议从简单的需求开始,逐步增加复杂度,同时始终关注用户体验和性能表现。不断实践和探索,你将能够创造出更加精彩的数据可视化作品。
