OpenLayers+ECharts联动:地图点击联动图表,数据可视化大屏方案

领导说"做一个数据大屏,左边地图右边图表,点击地图上的区域,右边图表跟着变"。这就是典型的地图+图表联动场景。但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

相关推荐
芭拉拉小魔仙1 小时前
Vue 2 门诊收费系统中的医保结算流程设计与实践
前端·javascript·vue.js
moonrailgun1 小时前
用 Node.js 复刻 Codex Astra 的终端星光
前端·javascript·算法
海上彼尚1 小时前
Cursor 模型的强度实测排行
前端·人工智能·后端
默_笙2 小时前
💫 给金鱼建图书馆(下):Milvus 向量数据库,让 AI 拥有长期记忆
前端·javascript
EatFan2 小时前
HTML前端利用flex解决input定位的问题
前端·css·html·css3
时空节拍AI数字人3 小时前
AI 数字人为什么需要“3D”?2D 不够用吗
人工智能·网络协议·tcp/ip·3d·信息可视化
CoderYanger3 小时前
前端基础——JavaScript(WebAPI)(下篇)
java·开发语言·前端·javascript·程序人生·面试·职场和发展
kyriewen3 小时前
AI 改祖传模块后,代码评审总绕不开两个问题
前端·程序员·ai编程
飞翔的熊blabla3 小时前
# Webpack 5 + Jenkins 持久化缓存实战:前端构建从 288 秒降到 30 秒>
前端·webpack·jenkins