类名 view/utils/Popup.js
import { defaultValue, Evented, Log } from '@mapgis/webclient-common'
/**
 * 二维场景信息弹窗(leaflet引擎)
 * 参考示例:
 * <a href='#MapView'>[初始化二维场景视图]</a>
 * [ES6引入方式]:<br/>
 * import { Popup } from '@mapgis/webclient-leaflet-plugin' <br/>
 * 自定义样式说明:<br/>
 * zondy-popup__content 弹窗容器样式<br/>
 * zondy-popup__tip 弹窗对话框箭头样式<br/>
 * zondy-popup__header 弹窗头部样式<br/>
 * zondy-popup__content 弹窗主体样式<br/>
 * zondy-popup__footer 弹窗底部样式<br/>
 * @class Popup
 * @moduleEX Widget
 * @param {Object} options 构造参数
 * @param {MapView} [options.view] 弹窗地图视图对象
 * @param {String}  [options.id]  弹窗ID
 * @param {Point} [options.location] 弹窗定位点
 * @param {String} [options.title] 弹窗标题
 * @param {String|HTMLElement} [options.content] 弹框内容
 * @param {String} [options.alignment] 弹框方位,值为"auto"或"bottom-left"或"top-center"或"top-right"或"bottom-left"或"bottom-center"或"bottom-right"。
 * @param {Array} [options.defaultButtons] 弹框内容,可选数组项有'toggle','close','zoom'。toggle:收缩主题内容按钮;close:关闭按钮;zoom:缩放按钮。
 *
 * @example <caption><h7 id='Popup'>打开视图弹窗</h7></caption>
 * // ES5引入方式
 * const { Map, MapView } = Zondy
 * // ES6引入方式
 * import { Map, MapView } from "@mapgis/webclient-leaflet-plugin"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化地图视图对象
 * const mapView = new MapView({
 *   // 二维场景视图的容器(html的div标签)ID
 *   viewId: "二维场景视图的容器的id",
 *   // 图层管理容器
 *   map: map
 * });
 * const popupObj = {
 *  title: "标题",
 *  content:"弹出窗口主题内容,详细内容",
 *  location: new Point({coordinates:[123,34]}),
 *  alignment: "bottom-center"
 *}
 * mapView.popup.open(popupObj)
 * mapView.popup.close(popupObj)
 * <style>
 * .zondy-popup__container{
 *   background-color: #40a9ff;
 *   margin: 0
 * }
 * .zondy-popup__tip{
 *   // display: none;
 *   background-color: #ffffff;
 * }
 * .zondy-popup__header{
 *   background-color: #40a9ff;
 * }
 * .zondy-popup__content{
 *   background-color: #ffffff;
 * }
 * .zondy-popup__footer{
 *   // display: none;
 *   background-color: #40a9ff;
 * }
 * </style>
 */

class Popup extends Evented {
  constructor(options) {
    super(options)
    /**
     * 弹框的地图视野
     * @member {MapView}
     */
    this.view = defaultValue(options.view, null)
    // /**
    //  * 弹框唯一id
    //  * @member {String}
    //  */
    // this.id = this._id
    /**
     * 弹框位置
     * @member {String}
     */
    this.location = defaultValue(options.location, '')
    /**
     * 弹框标题
     * @member {String}
     */
    this.title = defaultValue(options.title, '')
    /**
     * 弹框内容
     * @member {String}
     */
    this.content = defaultValue(options.content, '')
    // /**
    //  * 弹框按钮事件
    //  * @member {String}
    //  */
    // this.action = undefined
    /**
     * 弹框方位,值为"auto"|"bottom-left"|"top-center"|"top-right"|"bottom-left"|"bottom-center"|"bottom-right"
     * @member {String}
     */
    this.alignment = defaultValue(options.alignment, 'bottom-center')
    /**
     * 默认按钮 ['toggle','close','zoom']
     * @member {Array}
     */
    this.defaultButtons = defaultValue(options.defaultButtons, [
      'toggle',
      'close',
      'zoom'
    ])
    this._popup = undefined
    // 初始化弹窗
    this._initPopup()
    // 设置popup自定义class样式
    this._initDefaultClass()
  }

  /**
   * 初始化弹窗
   * @private
   * */
  _initPopup() {
    this._customPopup()
    // 关闭地图点击关闭弹窗事件
    this.view._innerView.closePopupOnClick = false
  }

  _initDefaultClass() {}

  _customPopup() {}

  /**
   * 打开popup弹窗
   * @param {Object} options 弹窗属性对象
   * */
  open(options) {
    if (this._popup) {
      this.close()
      this._popup = undefined
      this.openPopup(options)
    } else {
      this.openPopup(options)
    }
  }

  /**
   * 打开popup弹窗
   * @param {Object} options 弹窗属性对象
   * */
  openPopup(options) {
    this.view = options.view ? options.view : this.view
    this.location = options.location ? options.location : this.location
    this.title = options.title ? options.title : this.title
    this.content = options.content ? options.content : this.content
    this.alignment = options.alignment ? options.alignment : this.alignment

    if (!this.view._innerView) {
      Log.info('没有视图引擎!')
      return
    }

    const content = this._contentUI(this.title, this.content)

    // const popup = new mapboxGl.Popup({ closeOnClick: false })
    this._popup = new mapboxgl.Popup({
      closeOnClick: false,
      closeButton: false,
      maxWidth: '1900px'
    })
      .setLngLat(this.location.coordinates)
      .setDOMContent(content)
      .addTo(this.view._innerView)

    this._popup.toggleClassName('highlighted')
    const collection = this._popup._container.getElementsByClassName(
      'mapboxgl-popup-content'
    )
    for (const i in collection) {
      collection[i].style.padding = '0'
      collection[i].style.borderRadius = '10px'
    }
  }

  _contentUI(title, content) {
    const self = this
    let defaultUI = undefined
    const string2Dom = function (arg) {
      const objE = document.createElement('div')
      objE.innerHTML = arg
      return objE.childNodes
    }
    defaultUI = document.createElement('div')
    defaultUI.setAttribute('id', `${this.id}-popup-default`)
    // 构建头部DOM
    const headerDom = document.createElement('div')
    headerDom.setAttribute('class', 'zondy-popup__header')
    headerDom.setAttribute('style', 'display: flex;')
    // 收缩按钮
    const toggleDom = string2Dom(`<div class="zondy-popup__toggle">
      <svg aria-hidden="true" class="svg" fill="currentColor" height="16px" width="16px" viewBox="0 0 24 24" width="100%" xmlns="http://www.w3.org/2000/svg"><path d="M5 13.793l7-7 7 7v1.414l-7-7-7 7z"></path></svg>
    </div>`)[0]
    // 关闭按钮
    const closeDom = string2Dom(`<div class="zondy-popup__close">
      <svg aria-hidden="true" class="svg" fill="currentColor" height="16px" width="16px" viewBox="0 0 16 16" width="100%" xmlns="http://www.w3.org/2000/svg"><path d="M3.98 11.303L7.281 8 3.98 4.697l.707-.707L7.99 7.293l.01-.01.01.01 3.304-3.303.707.707L8.718 8l3.303 3.303-.707.707L8.01 8.707l-.01.01-.01-.01-3.304 3.303z"></path></svg>
    </div>`)[0]
    if (title) {
      const titleDom = string2Dom(`<div style="flex: 1;"></div>`)[0]
      headerDom.appendChild(titleDom)
      if (typeof title === 'object') {
        if (title instanceof Node) {
          titleDom.appendChild(title)
        } else if (title instanceof NodeList) {
          title.forEach((dom) => {
            titleDom.appendChild(dom)
          })
        }
      } else {
        titleDom.innerHTML = title
      }
      if (this.defaultButtons.indexOf('toggle') > -1) {
        headerDom.appendChild(toggleDom)
        let showContentFlag = true
        // 收缩按钮事件
        toggleDom.onclick = function () {
          showContentFlag = !showContentFlag
          if (showContentFlag) {
            document
              .getElementById(`${self.id}-popup-default`)
              .querySelector('.zondy-popup__content').style.display = 'block'
          } else {
            document
              .getElementById(`${self.id}-popup-default`)
              .querySelector('.zondy-popup__content').style.display = 'none'
          }
        }
      }
      if (this.defaultButtons.indexOf('close') > -1) {
        headerDom.appendChild(closeDom)
        // 关闭按钮事件
        closeDom.onclick = () => {
          this.close()
        }
      }
    }
    // 构建中间内容DOM
    const contentDom = document.createElement('div')
    contentDom.setAttribute('class', 'zondy-popup__content')
    if (content) {
      if (typeof content === 'object') {
        if (content instanceof Node) {
          contentDom.appendChild(content)
        } else if (content instanceof NodeList) {
          // content.forEach((dom)=>{
          //   contentDom.appendChild(dom)
          // })
          for (let i = 0; i < content.length; i++) {
            contentDom.appendChild(content[i])
            i--
          }
        }
      } else {
        contentDom.innerHTML = content
      }
    }
    // 构建底部页脚DOM
    const footerDom = document.createElement('div')
    footerDom.setAttribute('class', 'zondy-popup__footer')
    // 缩放按钮
    const zoomDom =
      string2Dom(`<div class="zondy-popup__zoom" style="display: inline-block;width: 36px;height: 36px;line-height: 36px;text-align: center;">
      <svg class="svg" fill="currentColor" height="16px" width="16px" viewBox="0 0 16 16" width="100%" xmlns="http://www.w3.org/2000/svg"><path d="M9 7H7v2H6V7H4V6h2V4h1v2h2zm6.805 7.861l-.943.942a.665.665 0 0 1-.943 0l-3.067-3.067a.667.667 0 0 1 0-.943l.129-.13-1.108-1.107A5.279 5.279 0 1 1 11.8 6.5a5.251 5.251 0 0 1-1.237 3.366l1.108 1.108.124-.124a.668.668 0 0 1 .943 0l3.067 3.068a.666.666 0 0 1 0 .943zM10.8 6.5a4.3 4.3 0 1 0-4.3 4.3 4.304 4.304 0 0 0 4.3-4.3zm4.062 7.89l-2.595-2.598-.473.473 2.597 2.595z"></path></svg>
    </div>`)[0]
    if (this.defaultButtons.indexOf('zoom') > -1) {
      footerDom.appendChild(zoomDom)
      // 缩放按钮事件
      zoomDom.onclick = function () {
        self.view._setZoomAndCenter({
          zoom: self.view._zoom + 1,
          center: self.location
        })
      }
    }
    // footer有子节点,增加分割线样式
    if (footerDom.childNodes.length > 0) {
      footerDom.setAttribute(
        'class',
        'zondy-popup__footer zondy-popup__footer-division'
      )
    }
    defaultUI.appendChild(headerDom)
    defaultUI.appendChild(contentDom)
    defaultUI.appendChild(footerDom)
    return defaultUI
  }

  /**
   * 获取偏移对象
   * @private
   */
  _getOffset() {}

  /**
   * 将锚点位置转换成x、y方向偏移量
   * @private
   */
  _getOffsetByAlignment(alignment, width, height) {
    let offsetX = 0
    let offsetY = 0
    switch (alignment) {
      case 'top-left':
        offsetX = width / 2
        offsetY = height
        break
      case 'top-center':
        offsetY = height
        break
      case 'top-right':
        offsetX = -width / 2
        offsetY = height
        break
      case 'bottom-left':
        offsetX = width / 2
        break
      case 'auto':
      case 'bottom-center':
        break
      case 'bottom-right':
        offsetX = -width / 2
        break
      default:
        break
    }
    return { x: offsetX, y: offsetY }
  }

  /**
   * 关闭popup弹窗
   * */
  close() {
    if (this.view._innerView) {
      this._popup.remove()
    }
  }

  destroy() {}
}
export default Popup
构造函数
成员变量
方法
事件