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

相关推荐
时间的情敌3 小时前
Electron 设置-webkit-app-region: drag;实现拖拽后, 无法响应鼠标划过事件及点击事件的解决方式
前端·vue.js
程序猿阿森4 小时前
深入解析 NLI:RAG 与大模型防幻觉的“最后一道防线”
前端·人工智能·算法
瓶瓶持续学习中4 小时前
数字孪生数据模型如何连接空间智能与仿真
人工智能·信息可视化
iCxhust5 小时前
模型:500kW飞轮 10kV输电线路 油田抽油机 同时考虑无功补偿 统计:全年节电量 结果56万度电
前端·css·css3·电力·飞轮
志尊宝6 小时前
AI原生前端开发(011):Chrome 148+内置Gemini Nano入门
前端·chrome·ai-native
Liu.7746 小时前
uniapp swiper 常见问题及修复
前端·uni-app
u0111026756 小时前
图片生成任务的日志记录与敏感信息取舍
前端·图像处理·算法·ai作画
梦想很大很大6 小时前
重新思考 Workrun:AI 时代,我们还需要手动编排 Workflow 吗?
前端·人工智能·后端
小羊没烦恼!6 小时前
深入浅出SQL Server中的死锁
java·开发语言·前端·数据库·后端·spring·c#