arcgis js 完整悬停效果实现

arcgis 中的悬停效果并不如想象中那么容易实现,本文会介绍如何完整的实现如下悬停效果,并对相关的技术细节进行解释,讲解如何避免一些小坑。让你不仅知其然,更知其所以然。

文章正文主要涉及对细节和原理的讲解,如果你着急的话,文末有完整的使用 demo,需要自取。

效果拆分

从上面的 gif 里可以看的,一个完整的悬停效果包含三部分:

  • 鼠标指针变为小手(pointer)
  • 显示标签名称
  • 悬停图标放大

在网上有很多的文章都只是简单的解释了某一种效果(大多数都只是简单的更新下鼠标样式),但是大概率是满足不了需求的,下面咱们来一一介绍一下:

1、获取鼠标悬停事件回调

arcgis 中并不能通过类似 .addEventListener 或者 .on('hover-icon') 的形式直接监听图标的悬停事件,所以我们把这部分内容单独拿出来讲。

我们知道 arcgis js 的实例化分两部分:地图创建和视图创建:

const map = new Map({ layers: [baseMap] });
const view = new MapView({ container: "viewDiv", map }); 

map 对象就是地图实例,包含了核心的地图实现,是不包含任何与显示相关的功能的。而 view 则是视图实例,负责把一个数字化的地图显示在我们眼前的,例如这里使用的 MapView 就是 2D 渲染,而 SceneView 则是负责 3D 地图的渲染。

所以,我们可以通过 view.on('pointer-move', callback) 来监听鼠标在视图上的移动操作,并通过另一个方法 view.hitTest 来检测某个事件和那些地图元素重合:

view.on('pointer-move', async e => {const { results = [] } = await view.hitTest(e);console.log('悬停到的元素', results);
}); 

这里可以优化一下,使用 lodash 的 throttle 做一个节流,因为 hitTest 毕竟也是有一定消耗的异步操作,如果频繁触发的话不仅会导致卡顿,也会因为异步返回导致已经从元素上移走了,悬停效果却出现的问题。注意这里不能用 arcgis 自带的 promiseUtils.debounce 因为防抖并不适合这个场景,并且它还会阻塞异步事件,会导致悬停效果不跟手。

view.on('pointer-move', _.throttle(async e => {const { results = [] } = await view.hitTest(e);if (results.length <= 0) return;// 后续逻辑
}, 50)); 

由于 result 是个数组,因为鼠标有可能同时经过了多个元素,所以说我们要在这里元素里匹配到我们要实现悬停效果的那部分。

注意,这里不能直接取 result[0],因为鼠标可能会触及多种类型的元素,例如底图图层、或者悬停后显示的名称,所以有可能会出现悬停到了名字上,挡住了后面的图标的情况:

view.on('pointer-move', _.throttle(async e => {const { results = [] } = await view.hitTest(e);if (results.length <= 0) return;// 找到第一个图标,因为有可能悬停到了上一个图标的名称 label 上const { graphic } = results.find(hit => {// 注意这里判断了是否有 name 这个属性,你的场景可能和我不同return hit?.graphic?.attributes?.name;}) || {};if (!graphic) return;// 后续逻辑
}, 50)); 

现在我们就能准确且轻量的获取到当前悬停到了哪个图标上。

2、悬停时修改鼠标指针

这个效果其实是最简单的,在悬停时修改 css 的 cursor 属性就行了,我们可以封装一下:

const setCoursor = (type) => {// 这个 viewDiv 要换成你的const containerDom = document.getElementById('viewDiv');if (containerDom) containerDom.style.cursor = type;
} 

注意,这里获取的目标 dom 是地图的容器,不是 document.body,网上有很多文章都是直接设置 body 或其他全局样式,这其实是不太合适的,因为总会出现鼠标样式没有正确复原的情况,例如点击地图图标后弹出一个 html 的弹窗,此时是不会触发

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值