原生 js 实现类 3d 地图大屏展示自动高亮轮播显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎
Posted 凯小默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生 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>
<path
d="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)(?=(\\d3)+$)/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(以上是关于原生 js 实现类 3d 地图大屏展示自动高亮轮播显示悬浮提示 tootip 的方案:svg + popper.js 定位引擎的主要内容,如果未能解决你的问题,请参考以下文章