cesium弹窗加强版 cesium弹窗dom连接线

5 篇文章 0 订阅
1 篇文章 0 订阅

上图在这里插入图片描述
1: 创建一个热点基类

export default class Hot {
  /**
   * @description id
   * @type {string}
   */
  id = ''

  /**
   * 热点绑定的网格id
   * @type {number}
   */
  modelId = 0

  /**
   * 热点绑定的元素
   * @type {string}
   */
  innerHTML = ''

  /**
   * 元素
   * @type {HTMLElement}
   */
  element = null

  /**
   * 视角点
   * @type {{position: {x: number, y: number, z: number}, orientation: {}}}
   */
  viewPoint = {
    position: {},
    orientation: {}
  }

  /**
   * 热点位置
   * @type {{x: number, y: number, z: number}}
   */
  position = null

  /**
   * 热点被点击触发
   * @type{Function}
   */
  click = function () {

  }

  /**
   * 更新时调用
   * @type{Function}
   */
  onUpdate = function (e) {

  }

  /**
   * 热点屏幕坐标
   * @type {{x: number, y: number}}
   */
  screenCoordinates = {}

  /**
   * 设置关联dom
   * @type {HTMLElement}
   */
  connectionDom = null

  /**
   * 设置svg线 dom
   * @type {HTMLElement}
   */
  linesDom = null

	/**
	 * 偏移多少个像素
	 * @type {{x: number, y: number}}
	 */
	offset = {
  	x: 0,
		y: 0
	}

  /**
   * 关联线样式
   * @type {{
   * stroke: string,
   * strokeWidth: number,
   * opacity: number
   * }}
   */
  connectionLineStyle = {
    stroke: 'red',
    strokeWidth: 3,
    opacity: 0.7
  }

  /**
   * 创建一个热点
   * @type{{id: string,
   * modelId: number,
   * innerHTML: string,
   * viewPoint: {position: {},
   * orientation: {}},
   * position: {x: number, y: number, z: number},
   * click: Function,
   * onUpdate: Function,
   * offset: {x: number, y: number}
   * }}
   */
  constructor (options) {
    this.id = options.id
    this.modelId = options.modelId
    this.innerHTML = options.innerHTML
    this.viewPoint = options.viewPoint
    this.position = options.position
    this.click = options.click
    this.onUpdate = options.onUpdate
	  this.offset = options.offset || this.offset
  }
}

2: 创建热点管理对象

import EventConstant from '../constant/EventConstant'
import CesiumUtils from '../utils/CesiumUtils'
import GraphUtils from '../utils/GraphUtils'

export default class HotManager {
  /**
   * 视图管理
   * @type {Viewer}
   */
  viewer = null

  /**
   * 热点列表
   * @type {Hot[]}
   */
  hotList = []

  /**
   * 构建一个热点管理工具
   * @param viewer
   */
  constructor (viewer) {
      this.viewer = viewer

      this.viewer.eventManager.addEventListener(EventConstant.RENDER, e => {
    	try{
		    this.hotList.forEach(item => {
			    const windowCoordinates = CesiumUtils.wgs84ToWindowCoordinates(this.viewer.baseViewer.scene, item.position)
			    if (windowCoordinates) {
				    this.onUpdate(item, windowCoordinates)
				    // 如果关联dom 有值 且位置有变更, 需要更新连接线线的位置
				    if (item.connectionDom && (windowCoordinates.x !== item.screenCoordinates.x || windowCoordinates.y !== item.screenCoordinates.y)) {
					    this._processConnectionLines(item)
				    }
				    item.screenCoordinates = windowCoordinates
			    }
		    })
    	}catch(e) {
    	 console.error(e, ' 请检查传入的参数[position]是否错误')
    	}
      })
  }

  /**
   * 新增一个热点
   * @param hot{Hot} 热点
   */
  add (hot) {
  	if (!hot) {
  		throw new Error('错误的热点对象')
	  }
      const find = this.hotList.find(item => item.id === hot.id)
      if (find) {
          throw new Error('不允许重复的id!')
      }

      this.hotList.push(hot)
	  let element = document.createElement('div')
	  if (hot.innerHTML.constructor === HTMLDivElement){
		  element = hot.innerHTML
	  } else {
		  element.innerHTML = hot.innerHTML
	  }
      element.style.position = 'absolute'
      element.style.top = '0px'
      element.style.left = '0px'
      // 窗口内挂上dom
      this.viewer.baseViewer.container.appendChild(element)
      element.style.display = 'block'
      element.onclick = () => {
          this.click(hot)
      }
      hot.element = element
  }

  /**
   * 实时更新点位 *** 需要变更时外部重写 ***
   * @param hot{Hot}
   * @param screenPosition{{x: number, y: number}}
   */
  onUpdate (hot, screenPosition) {
      hot.element.style.left = screenPosition.x - hot.offset.x + 'px'
      hot.element.style.top = screenPosition.y - hot.offset.y + 'px'
  }

  /**
   * 热点信息
   * @param hot{Hot}
   */
  click (hot) {
      hot.viewPoint && this.viewer.flyTo(hot.viewPoint.position, hot.viewPoint.orientation)
  }

  /**
	 * 飞到这个热点
	 * @param hot{Hot} 热点
	 */
  flyToHot(hot) {
      this.viewer.flyTo(hot.viewPoint.position, hot.viewPoint.orientation)
  }

  /**
   * 移除全部热点
   */
  removeAll () {
      const length = this.hotList.length
      for (let i = 0; i < length; i++) {
          this.remove(this.hotList[0])
      }
  }

  /**
   * 移除热点
   * @param hot{Hot} 热点
   */
  remove (hot) {
      this.viewer.baseViewer.container.removeChild(hot.element)
	  hot.linesDom && this.viewer.baseViewer.container.removeChild(hot.linesDom)
      hot.connectionDom = null
      hot.linesDom = null
      const index = this.hotList.findIndex(item => item === hot)
      this.hotList.splice(index, 1)
  }

  /**
   * 通过id移除指定热点
   * @param id{string}
   */
  removeById (id) {
      const hot = this.hotList.find(item => item.id === id)
	  hot && this.remove(hot)
  }

  /**
   * 设置连接dom
   * @param hot{Hot} 指定热点
   * @param dom{HTMLElement} HTML dom元素
   * @param lineStyle{{
   * stroke: string,
   * strokeWidth: number,
   * opacity: number
   * }} 连接线样式
   */
  setConnectionDom (hot, dom, lineStyle) {
      const element = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
      element.style.height = '100%'
      element.style.width = '100%'
      element.style.position = 'absolute'
      element.style.top = '0px'
      element.style.pointerEvents = 'none'
      element.id = hot.id + '_hot'
      hot.connectionDom = dom
      // 覆盖默认样式
      hot.connectionLineStyle = { ...hot.connectionLineStyle, ...lineStyle }
      hot.linesDom = element
      // 窗口内挂上dom
      this.viewer.baseViewer.container.appendChild(element)
  }

  /**
   * 处理连接线渲染
   * @param hot{Hot} 热点
   * @private
   */
  _processConnectionLines (hot) {
      const lines = GraphUtils.generateLine(hot.connectionDom, hot.element)
      let innerHTML = ''
      lines.forEach(ite => {
          innerHTML += '<line x1="' + ite.start.x + '"' +
        ' x2="' + ite.end.x + '" ' +
        'y1="' + ite.start.y + '"' +
        ' y2="' + ite.end.y + '"' +
        'style="stroke:' + hot.connectionLineStyle.stroke +
        ';stroke-width:' + hot.connectionLineStyle.strokeWidth +
        '; opacity: ' + hot.connectionLineStyle.opacity + ';"> </line>'
      })
      hot.linesDom.innerHTML = innerHTML
  }
}

3: 一个简单的dom连接计算

  /**
	 * 生成连接线点位
	 * @param startObj{HTMLElement}
	 * @param endObj{HTMLElement}
	 * @return {[]}
	 */
  static generateLine (startObj, endObj) {
    if (!startObj.getBoundingClientRect) return []
    let end = {}
    const startRange = startObj.getBoundingClientRect()
    const endRange = endObj.getBoundingClientRect()
    const distance = 0.05
    const arr = []
    const start = {}
    start.x = Number(startRange.x)
    start.y = Number(startRange.y) + startRange.height / 2
    end.x = Number(endRange.x) + endRange.width / 2
    end.y = Number(endRange.y) + endRange.height

    if (end.x > window.innerWidth || end.y > window.innerHeight) {
      return []
    }

    // 第1个点
    arr.push({
      start: {
        ...start
      },
      end: {
        x: start.x - start.x * distance,
        y: start.y
      }
    })

    /*	// 第2个点. 下
			arr.push({
				start: {
					...arr[0].end
				},
				end: {
					x: arr[0].end.x,
					y: end.y - start.y + ((end.y - start.y) * distance) + start.y
				}
			}) */

    /*	// 第3个点. 下
			arr.push({
				start: {
					...arr[1].end
				},
				end: {
					x: end.x,
					y: arr[1].end.y
				}
			}) */

    // 第3个点. 下
    arr.push({
      start: {
        ...arr[0].end
      },
      end: {
        ...end
      }
    })
    return arr
  }

4:使用 (这里也可以用vue v-show 改成false, 这样节点生成了, 可以使用双向绑定, 非常滴方便 )

const hot = new Hot({
                    id: Clever.MathUtils.generateUUID(),
                    position: res.position,
                    viewPoint: this.viewer.getViewPoint(),
	                offset: {x: 70, y: 141},
                    innerHTML: document.getElementById('hot_point').innerHTML
                })
                // 热点管理
            this.hotManager = new HotManager(this.viewer)
            this.hotManager.add(hot)
            this.hotManager.setConnectionDom(hot, document.getElementById('novice')) // 设置连接的dom

5: 附赠css游动样式一个

@keyframes dong {
  0% {
    transform: translate(0px, 0px);
  }
  50% {
    transform: translate(0px, -10px);
  }
  100% {
    transform: translate(0px, 0px);
  }
}
.top{
  animation: dong 1s infinite;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值