当前位置: 首页 > ai >正文

Echarts实现3D地图(多层geo)同步缩放

echarts 3D地图实现缩放

    • 功能实现
      • 静态3D地图实现
      • 缩放功能实现
        • 修改配置项使其可缩放
        • 监听缩放事件
        • 同步缩放效果
        • 中心点偏移问题处理
    • 性能优化
      • 添加节流
    • 最终展示
      • 效果展示
      • 完整代码

功能实现

静态3D地图实现

这里使用echarts-for-react组件来实现,使用echarts 配置项也通用

import ReactECharts from "echarts-for-react";
import * as echarts from 'echarts'const eCharts_react = useRef(null); // 地图实例
const [option, setOption] = useState({}); // 配置项
const [mapJson, setMapJson] = useState({features: []}) // geoJson
// 获取地图geoJson
const getGeoJson = (city) => {const url = `${httpUrl}/region/hlj/${city}_full.json`axios.get(url).then(response => {const geoJSON = response.datasetMapJson(geoJSON)}).catch(error => {noMapData() // 报错的一些处理console.error('Error fetching district data:', error);});
}
// 城市下钻要切换地图,所以这里需要根据父级的code来获取对应的geo数据
useEffect(() => {getGeoJson(mapCode)const chartIns = eCharts_react?.current.getEchartsInstance()setMyChart(chartIns)myChart && myChart.dispose();
}, [mapCode])useEffect(() => {// 处理地图geoJsonlet data = mapJson?.features?.map((item) => {return {name: item.properties.name,adCode: item.properties.adcode};});// map配置let exampleOption = {geo: [{type: "map",map: mapName, // 父级传递当前地图名称aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "50%"],layoutSize: "146%",label: {emphasis: {show: false,},},itemStyle: {normal: {borderColor: "#00E9FF",borderWidth: 2,shadowColor: "#8cd3ef",shadowOffsetY: 20,shadowBlur: 120,areaColor: "transparent",},}},// 重影{type: "map",map: mapName,zlevel: -1,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "51%"],layoutSize: "146%",silent: true,itemStyle: {normal: {borderWidth: 1,borderColor: "rgba(58,149,253,0.8)",shadowColor: "rgba(172, 122, 255,0.5)",shadowOffsetY: 58,shadowBlur: 15,areaColor: "rgba(5,21,35,0.1)",},},},{type: "map",map: mapName,zlevel: -2,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "52%"],layoutSize: "146%",silent: true,itemStyle: {normal: {borderWidth: 1,borderColor: "rgba(58,149,253,0.6)",shadowColor: "rgba(65, 214, 255,1)",shadowOffsetY: 5,shadowBlur: 15,areaColor: "transpercent",},},},{type: "map",map: mapName,zlevel: -3,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "53%"],layoutSize: "146%",silent: true,itemStyle: {normal: {borderWidth: 1,borderColor: "rgba(58,149,253,0.4)",shadowColor: "rgba(58,149,253,1)",shadowOffsetY: 15,shadowBlur: 10,areaColor: "transpercent",},},},{type: "map",map: mapName,zlevel: -4,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "54%"],layoutSize: "146%",silent: true,itemStyle: {normal: {borderWidth: 5,borderColor: "rgba(5,9,57,0.8)",shadowColor: "rgba(29, 111, 165,0.8)",shadowOffsetY: 15,shadowBlur: 10,areaColor: "rgba(5,21,35,0.1)",},},},],series: [{name: "丹东市数据",type: "map",map: mapName, // 自定义扩展图表类型aspectScale: 1,zoom: 0.65,showLegendSymbol: true,label: {normal: {show: true,textStyle: {color: "#fff", fontSize: "120%"},},},itemStyle: {normal: {areaColor: {type: "linear",x: 1200,y: 0,x2: 0,y2: 0,colorStops: [{offset: 0,color: "rgba(3,27,78,0.75)", // 0% 处的颜色},{offset: 1,color: "rgba(58,149,253,0.75)", // 50% 处的颜色},],global: true, // 缺省为 false},borderColor: "#fff",borderWidth: 0.2,},emphasis: {show: false,color: "#fff",areaColor: "rgba(0,254,233,0.6)",},},layoutCenter: ["50%", "50%"],layoutSize: "146%",markPoint: {symbol: "none",},data: data,roam:"scale"},],};setOption(exampleOption)// 注册地图echarts.registerMap(mapName, mapJson)}, [mapJson])return (<div style={{height: '100%', width: '100%'}}><ReactEChartsoption={option}style={{ height: '100%', width: '100%' }} ref={eCharts_react}/></div>)

效果
3D地图效果

缩放功能实现

修改配置项使其可缩放
// 每一个geo以及series添加
roam:"scale"
// true 开启缩放和移动
// scale 开始缩放  move 开启移动

此时,地图的缩放功能已开启。
但是有个问题,光标在地图之外缩放时效果正常,
光标在地图上时,只有最上层的地图触发了缩放。
最上层缩放效果
于是想,某一层缩放时,将他的缩放比例同步到其他层来实现效果。

监听缩放事件

根据百度尝试了多种监听,均未生效。
找到文档发现该组件的onEvents支持所有 ECharts 事件类型。
欣喜若狂,立即前往。查阅文档找到georoam事件监听,尝试了下,果然生效了!
在这里插入图片描述

const onEvents = {'click': handleClickMap, // 下钻点击事件// 'mapRoam': zoomMap// 'mousewheel': zoomMap// 'wheel': zoomMap// 'graphRoam': zoomMap'georoam': sameData}
return (<div style={{height: '100%', width: '100%'}}><ReactEChartsoption={option}onEvents={onEvents}style={{ height: '100%', width: '100%' }} ref={eCharts_react}/></div>
)

除了组件的onEvents事件监听,还尝试了echart实例的on事件监听,但是都没有生效。
如果有生效的,麻烦请留言告知,万分感激🙏

同步缩放效果
 const sameData = (params) => {if(params.zoom){option.geo.map((item) => {item.zoom = item.zoom * params.zoom})option.series[0].zoom = option.series[0].zoom * params.zoomeCharts_react.current.getEchartsInstance().setOption(option)}}

在这里插入图片描述
同步缩放生效了,但是发现了新的问题。
光标在不同的位置进行缩放,不同层的中心点会出现一定程度的偏移。导致地图出现上图错位的效果。

中心点偏移问题处理

设置zoom时,将每一层的center设置为undefined

option.geo.map((item) => {item.zoom = item.zoom * params.zoomitem.center = undefined
})
option.series[0].zoom = option.series[0].zoom * params.zoom
option.series[0].center = undefined
eCharts_react.current.getEchartsInstance().setOption(option)

性能优化

添加节流

function throttle (fn, delay) {let last = 0;return function(...args) {const now = Date.now();if (now - last > delay) {fn.apply(this, args);last = now;}}
}
// 这个箭头函数要记得换成普通函数
function sameData(params) {if(params.zoom){option.geo.map((item) => {item.zoom = item.zoom * params.zoomitem.center = undefined})option.series[0].zoom = option.series[0].zoom * params.zoomoption.series[0].center = undefinedeCharts_react.current.getEchartsInstance().setOption(option)}
}
const onEvents = {'georoam': throttle(sameData, 100)
}

最终展示

效果展示

最终效果

完整代码

import React, {useEffect, useRef, useState} from 'react'
import './index.less'
import ReactECharts from "echarts-for-react";
import * as echarts from 'echarts'
import axios from 'axios'
import {httpUrl} from '@/public/loginConfig'const CityMap: React.FC = ({mapCode, mapName, noMapData, underMap}:{}) => {const eCharts_react = useRef(null);const [myChart, setMyChart] = useState(null)const [option, setOption] = useState({});const [mapJson, setMapJson] = useState({features: []})const handleClickMap = (params) => {underMap(params)}const getGeoJson = (city) => {const url = `${httpUrl}/region/hlj/${city}_full.json` // 公司服务axios.get(url).then(response => {const geoJSON = response.datasetMapJson(geoJSON)}).catch(error => {noMapData()console.error('Error fetching district data:', error);});}function throttle (fn, delay) {let last = 0;return function(...args) {const now = Date.now();if (now - last > delay) {fn.apply(this, args);last = now;}}}function sameData(params) {if(params.zoom){option.geo.map((item) => {item.zoom = item.zoom * params.zoomitem.center = undefined})option.series[0].zoom = option.series[0].zoom * params.zoomoption.series[0].center = undefinedeCharts_react.current.getEchartsInstance().setOption(option)}}const registerMap = () => {echarts.registerMap(mapName, mapJson)}useEffect(() => {getGeoJson(mapCode)const chartIns = eCharts_react?.current.getEchartsInstance()setMyChart(chartIns)myChart&& myChart.dispose();}, [mapCode])useEffect(() => {let data = mapJson?.features?.map((item) => {return {name: item.properties.name,adCode: item.properties.adcode};});let exampleOption = {geo: [{type: "map",map: mapName,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "50%"],layoutSize: "146%",roam:"scale",label: {emphasis: {show: false,},},itemStyle: {normal: {borderColor: "#00E9FF",borderWidth: 2,shadowColor: "#8cd3ef",shadowOffsetY: 20,shadowBlur: 120,areaColor: "transparent",},}},// 重影{type: "map",map: mapName,zlevel: -1,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "51%"],layoutSize: "146%",roam:"scale",silent: true,itemStyle: {normal: {borderWidth: 1,borderColor: "rgba(58,149,253,0.8)",shadowColor: "rgba(172, 122, 255,0.5)",shadowOffsetY: 58,shadowBlur: 15,areaColor: "rgba(5,21,35,0.1)",},},},{type: "map",map: mapName,zlevel: -2,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "52%"],layoutSize: "146%",roam:"scale",silent: true,itemStyle: {normal: {borderWidth: 1,borderColor: "rgba(58,149,253,0.6)",shadowColor: "rgba(65, 214, 255,1)",shadowOffsetY: 5,shadowBlur: 15,areaColor: "transpercent",},},},{type: "map",map: mapName,zlevel: -3,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "53%"],layoutSize: "146%",roam:"scale",silent: true,itemStyle: {normal: {borderWidth: 1,borderColor: "rgba(58,149,253,0.4)",shadowColor: "rgba(58,149,253,1)",shadowOffsetY: 15,shadowBlur: 10,areaColor: "transpercent",},},},{type: "map",map: mapName,zlevel: -4,aspectScale: 1,zoom: 0.65,layoutCenter: ["50%", "54%"],layoutSize: "146%",roam:"scale",silent: true,itemStyle: {normal: {borderWidth: 5,borderColor: "rgba(5,9,57,0.8)",shadowColor: "rgba(29, 111, 165,0.8)",shadowOffsetY: 15,shadowBlur: 10,areaColor: "rgba(5,21,35,0.1)",},},},],series: [{name: "丹东市数据",type: "map",map: mapName, // 自定义扩展图表类型aspectScale: 1,zoom: 0.65, // 缩放showLegendSymbol: true,label: {normal: {show: true,textStyle: {color: "#fff", fontSize: "120%"},},},itemStyle: {normal: {areaColor: {type: "linear",x: 1200,y: 0,x2: 0,y2: 0,colorStops: [{offset: 0,color: "rgba(3,27,78,0.75)", // 0% 处的颜色},{offset: 1,color: "rgba(58,149,253,0.75)", // 50% 处的颜色},],global: true, // 缺省为 false},borderColor: "#fff",borderWidth: 0.2,},emphasis: {show: false,color: "#fff",areaColor: "rgba(0,254,233,0.6)",},},layoutCenter: ["50%", "50%"],layoutSize: "146%",markPoint: {symbol: "none",},data: data,roam:"scale"},],};setOption(exampleOption)registerMap()}, [mapJson])const onEvents = {'click': handleClickMap,'georoam': throttle(sameData, 100)}return (<div style={{height: '100%', width: '100%'}}><ReactEChartsoption={option}onEvents={onEvents}style={{ height: '100%', width: '100%' }} ref={eCharts_react}/></div>)
}
export default CityMap
http://www.xdnf.cn/news/9602.html

相关文章:

  • LangChain + Redis:实现持久化的聊天历史记录管理
  • 华为认证是什么?网络工程师的华为认证考试详解
  • ActiveMQ 可观测性最佳实践
  • 日立HDS G350存储Dynamic Link Manager(HDLM)在linux系统多路径绑定
  • ChatGPT + 知网 + 知乎,如何高效整合信息写出一篇专业内容?
  • 多元素纳米颗粒:开启能源催化新纪元
  • C语言_编译和链接
  • 基于stm32风速风向温湿度和瓦斯检测(仿真+代码)
  • 如何在python3.8环境中安装pytorch
  • 子网的划分
  • 深圳南柯电子|交流电机EMC整改:电磁兼容问题为何成为核心挑战
  • 程序员出海手册
  • 国际数字影像产业园:以科技赋能,打造文创产业升级新引擎
  • DAY 36神经网络加速器easy
  • 遥控器主副控设计运行要点分析!
  • AI任务相关解决方案2-基于WOA-CNN-BIGRU-Transformer模型解决光纤通信中的非线性问题
  • MMR-Mamba:基于 Mamba 和空间频率信息融合的多模态 MRI 重建|文献速递-深度学习医疗AI最新文献
  • 简述多路复用与多路分解
  • linux系统(centos7为例)将jar配置成服务操作教程
  • 专业课复习笔记 10
  • Allegro X PCB设计小诀窍--05.如何在Allegro X中实现隐藏电源飞线效果
  • 如何解决幻读问题?
  • 生成圆锥的点云图像
  • Spring Boot微服务架构(八):开发之初就引入APM工具监控
  • LLama-Factory使用教程-2025最新版
  • [CSS3]vw/vh移动适配
  • 实时计算是什么?如何通过实时计算实现增量同步?
  • Python中使用处理数据、路径的2个方法,对应两个第三方库
  • 基于RPA技术的ECRobot企业智能体解决方案,打通企业自动化业务流程的最后一公里
  • Vim文本编辑器快捷键用法以及简单介绍