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

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

相关文章:

  • 什么是可视化组态软件? 主流可视化组态软件有哪些?
  • [C]基础16.数据在内存中的存储
  • Python训练打卡Day36
  • 井喷式增长下的证件缺口:特种设备人才供需矛盾如何破局?
  • 程序员出海之英语-基础-小猪佩奇 第 1 季第 1 集 泥坑
  • JWT安全:弱签名测试.【实现越权绕过.】
  • Linux C++ 开发基础命令指南
  • SQL输出20个9
  • IP地址基础知识
  • 论文略读:Deep reinforcement learning for community architectural layout generation
  • vue+threeJs 根据屏幕调整gltf模型的大小、重心、并更换骑车整体颜色
  • vscode中launch.json、tasks.json的作用及实例
  • (九)深度学习---自然语言处理基础
  • AI 赋能数据可视化:漏斗图制作的创新攻略
  • 6个月Python学习计划 Day 7 - 复盘 + 测试日
  • 电位滴定仪测定锂电池正极材料残余碱含量
  • 探索Dify-LLM:构建自定义大模型应用的高效平台
  • docker中多个容器相互访问的端口问题
  • MSMQ消息队列》》Rabbit MQ》》集群
  • Linux进程调度的理解
  • 微信优惠券网站怎么做的/qq群推广网站
  • 企业网站建设方案教程/线上推广渠道有哪些方式
  • pc网站建设的三大条件/seo关键技术有哪些
  • wordpress分类链接失效/网站关键词优化排名外包
  • 深圳租房建设局网站首页/百度人工服务24小时
  • 昆明做网站公司/谷歌推广费用多少