领导说"做一个数据大屏,左边地图右边图表,点击地图上的区域,右边图表跟着变"。这就是典型的地图+图表联动场景。但OpenLayers和ECharts是两个独立的库,怎么联动?这篇文章把完整方案写出来了。
一、联动架构
用户点击地图 → 获取区域数据 → 更新ECharts图表
用户hover图表 → 高亮地图区域 → 更新地图视角
二、地图点击 → 图表更新
2.1 基本实现
javascript
import * as echarts from 'echarts'
const chart = echarts.init(document.getElementById('chart'))
// 地图点击事件
map.on('click', (e) => {
const feature = map.forEachFeatureAtPixel(e.pixel, f => f)
if (feature) {
const name = feature.get('name')
const data = feature.get('data')
// 更新图表
chart.setOption({
title: { text: `${name} 数据统计` },
series: [{
data: data.values
}]
})
}
})
2.2 区域高亮
javascript
let highlightFeature = null
map.on('pointermove', (e) => {
const feature = map.forEachFeatureAtPixel(e.pixel, f => f)
// 取消之前的高亮
if (highlightFeature) {
highlightFeature.setStyle(originalStyle)
}
// 高亮当前要素
if (feature) {
highlightFeature = feature
feature.setStyle(highlightStyle)
map.getTargetElement().style.cursor = 'pointer'
} else {
highlightFeature = null
map.getTargetElement().style.cursor = ''
}
})
三、图表 → 地图联动
3.1 ECharts点击事件
javascript
chart.on('click', (params) => {
const regionName = params.name
// 找到地图上对应的要素
const layer = map.getLayers().getArray().find(l => l.code === 'regions')
const features = layer.getSource().getFeatures()
const targetFeature = features.find(f => f.get('name') === regionName)
if (targetFeature) {
// 飞到该区域
map.getView().fit(targetFeature.getGeometry(), {
padding: [50, 50, 50, 50],
duration: 500
})
// 高亮
targetFeature.setStyle(highlightStyle)
}
})
四、完整Vue组件
vue
<template>
<div class="dashboard">
<div class="map-panel" ref="mapRef"></div>
<div class="chart-panel" ref="chartRef"></div>
</div>
</template>
<script setup>
import {ref, onMounted, onBeforeUnmount, shallowRef} from 'vue'
import * as echarts from 'echarts'
const mapRef = ref(null)
const chartRef = ref(null)
const map = shallowRef(null)
let chart = null
onMounted(() => {
// 初始化地图
map.value = new Map({ target: mapRef.value, ... })
// 初始化图表
chart = echarts.init(chartRef.value)
chart.setOption({
title: { text: '数据统计' },
xAxis: { type: 'category', data: [] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [] }]
})
// 地图点击 → 图表更新
map.value.on('click', (e) => {
const feature = map.value.forEachFeatureAtPixel(e.pixel, f => f)
if (feature) {
updateChart(feature.get('name'), feature.get('data'))
}
})
// 图表点击 → 地图联动
chart.on('click', (params) => {
flyToRegion(params.name)
})
// 窗口resize时同步
window.addEventListener('resize', () => {
chart.resize()
map.value.updateSize()
})
})
const updateChart = (name, data) => {
chart.setOption({
title: { text: name },
xAxis: { data: data.labels },
series: [{ data: data.values }]
})
}
const flyToRegion = (name) => {
const features = map.value.getLayers().getArray()
.find(l => l.code === 'regions')
.getSource().getFeatures()
const feature = features.find(f => f.get('name') === name)
if (feature) {
map.value.getView().fit(feature.getGeometry(), { duration: 500 })
}
}
onBeforeUnmount(() => {
chart?.dispose()
})
</script>
五、踩坑记录
坑1:ECharts图表不自适应
现象:窗口resize后图表大小不对。
原因:没有监听resize事件。
解决:
javascript
window.addEventListener('resize', () => chart.resize())
坑2:地图点击穿透
现象:点击地图时,下面的图表也响应了点击。
原因:事件冒泡。
解决 :图表容器设置pointer-events: auto,地图容器设置pointer-events: none(仅在重叠区域)。
六、总结
| 联动方向 | 触发方式 | 核心逻辑 |
|---|---|---|
| 地图→图表 | map.on('click') |
获取feature数据,更新chart.setOption |
| 图表→地图 | chart.on('click') |
找到对应feature,view.fit |
| 高亮同步 | pointermove + chart.dispatchAction |
双向高亮 |
更新日期 :2026年9月
调试版本:OpenLayers 10.9.0 / ECharts 5.x