原生 js 实现类 3d 地图大屏展示自动高亮轮播、显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎
要实现的效果
如下图,3d 地图高亮自动轮播,展示白云区各个镇街的人口数局。
原由
为什么想到这个方案,是因为我在用 echarts-gl
实现 3d 地图效果的过程中,我发现通过 dispatchAction 触发不了 3d 的高亮。不知道大家有没有遇到,所以我实现不出自动轮播的 3d 效果,因为显示悬浮提示 tooltip 不出来,必须要 hover 的时候才行。(不知道是不是我的配置问题,如果大家有好的 3d 地图自动轮播方案,欢迎在下面评论分享。)
于是,我在想能不能用 svg 直接渲染成 dom,然后在定时的修改对应 dom 的样式,并且显示出对应标签的 tooltip 提示。我觉得可以一试,于是我找了一些相关资料,简单的实现了一下。
代码实现
1、修改地图的视觉提供地图的 svg 图
由于 svg 的字符过多,博客放不下,这里就不展示 svg 的全部代码了。
主要的就是为了方便激活地块,快速的找到 dom 元素,我们需要给地块加一些 id,还有标签定位 tooltip,方便获取跟标记。
<g id="plot" name="地块" transform="translate(0.000000, -0.000000)"><g id="plot_yuncheng"><use fill="#eee" fill-rule="evenodd" xlink:href="#path-47"></use><use fill="black" fill-opacity="1" filter="url(#filter-48)" xlink:href="#path-47"></use><use stroke="#aaa" stroke-width="2" xlink:href="#path-47"></use></g>
...
</g>
<g id="label" name="标签" transform="translate(80.000000, 128.000000)"><g id="label_renhe" transform="translate(176.000000, 81.000000)"><g id="编组-77备份-3"><path d="M71.0581411,-0.5 L71.0581411,24.3372098 L-0.5,24.3372098 L-0.5,-0.5 L71.0581411,-0.5 Z"id="矩形备份-37" stroke="#fff" fill="orange"></path><pathd="M70.5581411,19.8643415 L70.5581411,23.8372098 L66.8722681,23.8372098 L70.5581411,19.8643415 Z M3.68587304,0 L0,3.97286831 L0,0 L3.68587304,0 Z"id="形状结合" fill="#fff"></path></g><text id="人和镇" font-family="PingFangSC-Medium, PingFang SC" font-size="14" font-weight="400" fill="#FFFFFF"><tspan x="14.1116282" y="16.9186049">人和镇</tspan></text></g>...
</g>
2、引入 popper.js 定位引擎
官网:TOOLTIP & POPOVER POSITIONING ENGINE
第一种使用方式:
npm i @popperjs/core -s
import { createPopper } from '@popperjs/core';
const popcorn = document.querySelector('#popcorn');
const tooltip = document.querySelector('#tooltip');
createPopper(popcorn, tooltip, {placement: 'top',
});
第二种使用方式:
在 html 中引入 popper.js
定位引擎:
<script src="https://unpkg.com/@popperjs/core@2"></script>
<!DOCTYPE html>
<html><head><title>Popper Tutorial</title></head><body><button id="button" aria-describedby="tooltip">My button</button><div id="tooltip" role="tooltip">My tooltip</div><script src="https://unpkg.com/@popperjs/core@2"></script><script>const button = document.querySelector('#button');const tooltip = document.querySelector('#tooltip');const popperInstance = Popper.createPopper(button, tooltip);</script></body>
</html>
3、激活地块
需要给 use 元素设置激活的 style 属性
let activedStyle = "fill:blue"; // 地块激活样式
// 激活地块
function addPlotActive(index) {baiyunSvgDom.getElementById(`plot_${plotArrs[index]}`).getElementsByTagName('use')[0].setAttribute("style", activedStyle);
}
4、tooltip 定位
我们需要找到当前轮播的标签元素,以及提示框的元素,然后通过 Popper.createPopper
设置就行。
// 设置标签提示定位
function setCreatePopper() {Popper.createPopper(baiyunSvgDom.getElementById(`label_${plotArrs[index]}`), mapTooltipsDom, {placement: 'top-start',positionFixed: true});
}
5、自动轮播跟赋值
自动轮播的话主要需要注意第一次跟最后一次就行,另外赋值的时候,innerHTML 不要写错了。具体代码的话看逻辑代码即可。
逻辑代码
这里的代码缺失了 svg 里的内容。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SVG地图轮播</title><style>.svg-geo-map-tooltips {min-width: 160px;background-color: rgba(0,0,0,.8);border-radius: 8px;text-align: center;padding: 18px 8px;transition: .4s;left: 20px !important;bottom: 5px !important;}.svg-geo-map-tooltips .name {font-size: 16px;font-weight: 400;color: #ffffff;height: 22px;line-height: 22px;margin-bottom: 8px;}.svg-geo-map-tooltips .value {color: #ffffff;}.svg-geo-map-tooltips .value .num {font-size: 24px;font-weight: bold;height: 32px;line-height: 32px;}.svg-geo-map-tooltips .value .unit {font-size: 14px;}</style><script src="https://unpkg.com/@popperjs/core@2"></script>
</head>
<body><div class='svg-geo-map-chart'><svg id="baiyunSvg" width="804px" height="597px" viewBox="0 0 804 597" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg><!-- 提示 --><div class="svg-geo-map-tooltips"><div class="name"></div><div class="value"><span class="num"></span><span class="unit">人</span></div></div></div><script>let curPlotName = ""; // 当前激活的地块名let curPlotValue = 0; // 当前激活的地块服务量数let interval = 1000; // 时间间隔毫秒数let index = 0; // 播放所在下标let timer = null;let activedStyle = "fill:blue"; // 地块激活样式let baiyunSvgDom = null; // svg 的 dom 元素let mapTooltipsDom = null; // 提示的 dom 元素let baiyunPlotDataList = [{id: "jianggao",name: "江高镇",value: 883945},{id: "renhe",name: "人和镇",value: 4567992},{id: "taihe",name: "太和镇",value: 4567323},{id: "zhongluotan",name: "钟落潭镇",value: 497863},{id: "longgui",name: "龙归街",value: 3486257},{id: "dayuan",name: "大源街",value: 897435},{id: "sanyuanli",name: "三元里街",value: 46809544},{id: "songzhou",name: "松洲街",value: 123403},{id: "jingtai",name: "景泰街",value: 342256677},{id: "tongde",name: "同德街",value: 234677},{id: "huangshi",name: "黄石街",value: 976542},{id: "tangjing",name: "棠景街",value: 33456},{id: "xinshi",name: "新市街",value: 3455602},{id: "tonghe",name: "同和街",value: 487654},{id: "jingxi",name: "京溪街",value: 3876735},{id: "yongping",name: "永平街",value: 6677544},{id: "jiahe",name: "嘉禾街",value: 34526784},{id: "junhe",name: "均禾街",value: 8756534},{id: "shijing",name: "石井街",value: 220232},{id: "jinsha",name: "金沙街",value: 3352256},{id: "yuncheng",name: "云城街",value: 335677},{id: "helong",name: "鹤龙街",value: 334225},{id: "baiyunhu",name: "白云湖街",value: 34556},{id: "shimen",name: "石门街",value: 1354667}]; // 默认地块数据let plotArrs = baiyunPlotDataList.map(el => el.id); // 地块的id数据// 数字加千位分隔符function numToThsSprtr (num) {let res = num.toString().replace(/\d+/, function (n) { // 先提取整数部分return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {return $1 + ',';});})return res;}// 初始化function initRender() {// 获取 dom 元素baiyunSvgDom = document.getElementById('baiyunSvg');mapTooltipsDom = document.querySelector('.svg-geo-map-tooltips');// 地块的id数据plotArrs = baiyunPlotDataList.map(el => el.id);// 初始化激活颜色this.addPlotActive(index);// 赋值setPlotValue();console.log(index, plotArrs[index], curPlotName, curPlotValue);// 初始化定位this.setCreatePopper();}// 设置轮播function setIntervalSvg() {timer = setInterval(() => {// 先清除上一次的激活效果if(index !== -1) {removePlotActive(index);}// 索引自增index++;// 地块激活this.addPlotActive(index);// 赋值setPlotValue();console.log(index, plotArrs[index], curPlotName, curPlotValue);// 进行提示定位this.setCreatePopper();// 处理最后一个地块激活问题if(index === plotArrs.length - 1) {let tempTimer = setTimeout(() => {// 移除地块最后一个的激活removePlotActive(plotArrs.length - 1);clearTimeout(tempTimer);}, interval);index = -1;}}, interval);}// 激活地块function addPlotActive(index) {baiyunSvgDom.getElementById(`plot_${plotArrs[index]}`).getElementsByTagName('use')[0].setAttribute("style", activedStyle);}// 赋值function setPlotValue() {curPlotName = baiyunPlotDataList[index].name;curPlotValue = numToThsSprtr(baiyunPlotDataList[index].value);mapTooltipsDom.querySelector('.name').innerHTML = `${curPlotName}常住人口`;mapTooltipsDom.querySelector('.num').innerHTML = curPlotValue;}// 移除地块激活function removePlotActive(index) {baiyunSvgDom.getElementById(`plot_${plotArrs[index]}`).getElementsByTagName('use')[0].removeAttribute("style", activedStyle);}// 设置标签提示定位function setCreatePopper() {Popper.createPopper(baiyunSvgDom.getElementById(`label_${plotArrs[index]}`), mapTooltipsDom, {placement: 'top-start',positionFixed: true});}// 初始化initRender();// 设置轮播setIntervalSvg();</script>
</body>
</html>
完整代码
里面包含视频,图片,全部代码,由于展示不了 svg 的全部代码。下面我整理了资源,有需要的可以下载。
完整资源下载
参考资料
- TOOLTIP & POPOVER POSITIONING ENGINE
原生 js 实现类 3d 地图大屏展示自动高亮轮播、显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎相关推荐
- 基于js+echarts实现数据可视化大屏展示
vue+echarts大屏数据可视化展示点击进入 写在前面: 本项目中使用的是echarts图表库,ECharts 提供了常规的折线图.柱状图.散点图.饼图.K线图,用于统计的盒形图,用于地理数据可视 ...
- react + dataV + three.js + blender 实现3D可视化大屏效果
效果图 3D 可视化展示是一个很不错的方向,但是纯three.js 开发效率低,简单展示类的可视化,可以考虑使用blender 等3D 绘制工具,快速,高效. 文章目录 效果图 前言 一.DataV ...
- 智慧管廊可视化3d监控大屏展示的应用及优势
随着城市建设越来越智能化,管廊设备及线路越来越多,动环检测数据越来越多,对管廊管理手段面临极大的挑战.智慧管廊可视化三维虚拟检修管控系统集宏观场景.设备及数据进行三维仿真还原和可视化实时呈现,实现日常 ...
- 使用Three.js实现炫酷的赛博朋克风格3D数字地球大屏
声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 近期工作有涉及到数字大屏的需求,于是利用业余时间,结合 Three.js ...
- 如何使用 WEB 技术编写前端代码,实现大屏展示和地图显示功能
使用 WEB 技术编写前端代码实现大屏展示和地图显示功能可以采用以下步骤: 使用 HTML.CSS.JavaScript 等前端技术构建页面布局和样式. 使用 JavaScript 库或框架,如 jQ ...
- iPortal地图大屏自定义组件示例--立体地图
作者:刘大 通过iPortal地图大屏自定义组件要点梳理这篇文章,我们基本了解了地图大屏如何进行自定义,也准备好了开发环境,那我们就接着进行实际操作下吧. 立体建筑实质是mapboxgl中的" ...
- Three.js之GeoJson 3D地图数据可视化飞行线实战
Three.js之GeoJson 3D地图数据可视化飞行线实战 GeoJSON是一种对各种地理数据结构进行编码的格式,基于Javascript对象表示法的地理空间信息数据交换格式.GeoJSON对象可 ...
- web大屏展示用到的组件_基于 HTML5 的工业组态高炉炼铁 3D 大屏可视化
前言 在大数据盛行的现在,大屏数据可视化也已经成为了一个热门的话题.大屏可视化可以运用在众多领域中,比如工业互联网.医疗.交通.工业控制等等.将各项重要指标数据以图表.各种图形等形式表现在一个页面上, ...
- 3D可视化大屏是如何实现的?
3D可视化是指拥有3D效果的数据可视化,对于所要展示的数据可视化内容还原出真实场景,并实时接入数据,在面对复杂操作时灵活应对,使得整个场景在大屏上的展示更具立体.更具科技感.更具易用性. 物联网时代, ...
最新文章
- 【camera】5.相机内嵌图像处理(ISP)介绍
- foreach遍历进阶_“枚举器“/GetEnumerator()方法
- go.sum中特殊hash如何计算
- cad显示有点暗_CAD参照的图框颜色太暗怎么调整?
- Struts2的自动装配
- emui内核支持kvm吗_KVM虚拟化详解
- python如何在列表中查找元素位置_查找元素在list中的位置以及折半查询
- idea git和svn间切换
- 三菱FX系列PLC-编程1
- ORACLE11g升级19c,报ORA-01017
- 转录组:STAR-Fusion融合基因
- App登录功能(用户名+密码)
- CSS实现播放暂停按钮样式
- android配置jni cmake,Android JNI之青春期 Cmake(android studio)
- 箱线图(Boxplot)
- 自己动手写一个番茄小助手
- Excel文件显示“文件已损坏,无法打开”情况的解决办法
- 双击打开Excel文件要反应很久之后才能打开,先开excel程序,再打开文件就很快的解决办法...
- python 使用wxpy实现获取微信好友列表 头像 群成员
- 程序员七夕特刊,绝无狗粮添加