前言
在做arcGis地图时总会涉及popup的操作,但是官方的popup属实不好用特别是在定制化这方面。
比如最近做的点击地图点时需要打开弹窗,而且UI是那种透明带背景图那种大屏样式,
要实现这种开始想着做css覆盖吧。
产品又说:这个弹窗不要自动关闭 要用户手动关闭。
前端:***
要知道arcGis的弹窗默认是点击空白就自动关闭,遇上这些需求比较难搞,难搞归难搞还是得想办法实现。
实现步骤
- 自己写弹窗,利用子绝父项点位,实现弹窗定位。
- 使用view.on(‘click’) 与 view.hitTest() 方法获取定位位置
- 然后就是css absolute 设置top与left就行
自己写弹窗
这个应该很简单主要是 设置position: absolute
这里简单写个Vue弹窗组件 以Vue3为例
<template>
<div class="popover-container" :style="{ '--left': props.popupData.left + 'px', '--top': props.popupData.top + 'px' }">
<div class="name g-ellipsis">attributes:{{ props.popupData.attributes }}</div>
</div>
</template>
<script setup lang="js">
const props = defineProps({
popupData: {
type: Object,
default: () => ({}),
},
})
</script>
<script lang="js">
export default {
name: 'MyPopup',
}
</script>
<style scoped>
.popover-container {
position: absolute;
top: var(--top);
left: var(--left);
font-size: 15px;
background: #feffff;
box-shadow: 0 3px 3px 1px rgb(0 0 0 / 12%);
border-radius: 2px;
opacity: 1;
transform: translate(-50%, calc(-100% - 10px));
background-color: #fff;
}
.popover-container::before {
content: '';
width: 10px;
height: 10px;
position: absolute;
bottom: 0;
left: 50%;
background-color: #fff;
transform: translate(-50%, 50%) rotate(45deg);
border-right: 0;
border-bottom: 0;
box-shadow: 3px 3px 3px -3px rgb(0 0 0 / 12%);
}
.name {
padding: 8px 14px;
max-width: 50vw;
}
</style>
以上弹窗大概是这个样子。
在vue中使用
利用v-show控制显示隐藏,popupData包含定位所需的left top以及attributes数据。
<template>
<div id="map-root">
<MyPopup v-show="popupVisible" :popupData="popupData"/>
</div>
</template>
获取定位坐标
- 主要是通过view.on监测地图点击事件拿到event点击点
- 然后使用view.hitTest做点击重合检测,返回重合的Graphic结果数组
- 再使用view.toScreen将经纬度转屏幕像素,拿给我们的popup做定位展示
可能有同学问 view.on(‘click’) 其实就返回了点击的屏幕像素点,为啥还需要 hitTset和 toScreen呢?
答:因为如果直接使用view.on的点做定位,可能会出现弹窗与点位相距甚远的情况(如下图一)
这是因为地图缩放后点击的位置在地图放大后根本就是两个地方,所以我们要拿重合图形的经纬度转换为屏幕像素 这样无论地图如何缩放都能与图形重合(如下图二)
我们把检测到的重合图形经纬度转换为屏幕像素,这样就不会存在偏差,同时也是实现图中跟随效果的核心(如下图)。
监听点击事件
设置viwe.on(‘click’) 在回调方法中在进行 hitTest 图形重合检测拿到图形 graphic
再根据 graphic type取经纬度还是图形的中心经纬度做定位
我的处理逻辑:如果是 point 就拿geometry,如果是线段或者多边形就拿geometry.extent.center中心点做定位坐标, 如果都不是就拿点击点做兜底处理
const popupData = {left: 0, top: 0, attributes: {}}
let popupVisible = false
let coordinate = null
const viewOnClick = view.on('click', (e) => {
// include: 在包含的图层内做碰撞检查
view.hitTest(e).then(({ results }) => {
if (results?.length) {
const {
graphic,
graphic: {
geometry,
attributes // 图形属性
}
} = results[0] // 如果用重叠要素的话可能有多个返回,咱只拿第一个
let coordinate = null
if (geometry) {
// 如果是 point 就拿geometry,如果是线段或者多边形就拿extent.center中心点做定位坐标, 如果都不是就拿点击点做兜底处理
coordinate = geometry?.type === 'point' ? geometry : geometry.extent ? geometry.extent.center : e.mapPoint
} else {
popupVisible = false
}
// 坐标转屏幕像素 这里的x y 就是left top 屏幕像素
// 赋给弹窗做定位就行
if (coordinate) {
const { x, y } = this.view.toScreen(coordinate)
popupData.left = x
popupData.top = y
popupData.attributes = attributes
popupVisible = true
}
} else {
popupVisible = false
}
})
})
简单的点击打开弹窗就完成了,但是我们可以再完善一下
拖动跟随
要实现跟随主要是监听center变化 view.watch(‘center’) 然后在回调方法中不断转换屏幕坐标 不断更新定位即可
const viewWatchCenter = view.watch('center', () => {
if (coordinate) {
const { x, y } = view.toScreen(coordinate)
popupData.left = x
popupData.top = y
popupVisible = true
}
})
同学们可以自己再完善一下,不想自己写的同学也可以使用我封装的包,完善了处理逻辑等等,感兴趣的同学往下看
arcgis-popup-control npm
基于ArcGis For JavaScript 4.x的自定义弹窗控制
Install
npm install --save arcgis-popup-control
or
pnpm install --save arcgis-popup-control
Usage
使用示例:
import PopupControl from 'arcgis-popup-control'
// PopupControl 的部分配置参数
const options = {
view,
// open的回调返回 { left: 100, top: 100, attributes: {} } 结构的对象
open: (obj) => {
// 更新定位并打开弹窗等逻辑
},
close: () => {
// popupVisible = false等一些操作逻辑
}
}
// 创建 PopupControl
const popupControl = new PopupControl(options)
附
原文链接:https://juejin.cn/post/7239241544959737913 作者:_引力波