ArcGis For JavaScript自定义弹窗实现 附NPM包

前言

在做arcGis地图时总会涉及popup的操作,但是官方的popup属实不好用特别是在定制化这方面。

比如最近做的点击地图点时需要打开弹窗,而且UI是那种透明带背景图那种大屏样式,
要实现这种开始想着做css覆盖吧。

产品又说:这个弹窗不要自动关闭 要用户手动关闭。

前端:***

要知道arcGis的弹窗默认是点击空白就自动关闭,遇上这些需求比较难搞,难搞归难搞还是得想办法实现。

实现步骤

  1. 自己写弹窗,利用子绝父项点位,实现弹窗定位。
  2. 使用view.on(‘click’)view.hitTest() 方法获取定位位置
  3. 然后就是css absolute 设置topleft就行

自己写弹窗

这个应该很简单主要是 设置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>

以上弹窗大概是这个样子。

ArcGis For JavaScript自定义弹窗实现 附NPM包

在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’) 其实就返回了点击的屏幕像素点,为啥还需要 hitTsettoScreen呢?

答:因为如果直接使用view.on的点做定位,可能会出现弹窗与点位相距甚远的情况(如下图一)

这是因为地图缩放后点击的位置在地图放大后根本就是两个地方,所以我们要拿重合图形的经纬度转换为屏幕像素 这样无论地图如何缩放都能与图形重合(如下图二)

ArcGis For JavaScript自定义弹窗实现 附NPM包

我们把检测到的重合图形经纬度转换为屏幕像素,这样就不会存在偏差,同时也是实现图中跟随效果的核心(如下图)。

ArcGis For JavaScript自定义弹窗实现 附NPM包

监听点击事件

设置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 作者:_引力波

(0)
上一篇 2023年6月1日 上午11:07
下一篇 2023年6月2日 上午10:01

相关推荐

发表回复

登录后才能评论