Cesium自定义Popup框

在习惯了二维的Popup框之后,也想在三维里面有个。但是Cesium并没有封装过Popup框,有的只是一个悬浮固定位置的信息框,就是这样的:

显然这种框框展示,并不能满足狂拽酷炫diao炸天的特效,既然没有,那就照着二维的地图框架,自己整一个吧。先上图:

来个动的:

实现

在做三维之前,那时候用的最多的是 MapBoxGL,所以我就以 MapBoxGLPopup 为基础原型进行的封装。先说一下思路

  • 用js来动态创建弹窗的基础DOM框架。包括弹出框的名称,弹窗内容,弹窗的底部尖尖头。
  • 利用Cesium提供的实时帧渲染方法,来不停的修改弹出框的位置。
  • 然后就是完善和丰富整个功能了。
  1. 创建面板代码:

    CesiumPopup.prototype.initPanle = function () {

    var closeBtnIcon = '<svg t="1603334792546" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1328" width="32" height="32"><path d="M568.922 508.232L868.29 208.807a39.139 39.139 0 0 0 0-55.145l-1.64-1.64a39.139 39.139 0 0 0-55.09 0l-299.367 299.82-299.425-299.934a39.139 39.139 0 0 0-55.088 0l-1.697 1.64a38.46 38.46 0 0 0 0 55.09l299.48 299.594-299.424 299.48a39.139 39.139 0 0 0 0 55.09l1.64 1.696a39.139 39.139 0 0 0 55.09 0l299.424-299.48L811.56 864.441a39.139 39.139 0 0 0 55.089 0l1.696-1.64a39.139 39.139 0 0 0 0-55.09l-299.48-299.537z" p-id="1329"></path></svg>'

    _panelContainer = document.createElement('div')
    _panelContainer.classList.add('cesium-popup-panel')
    if (this.className && this.className !== '') {
    _panelContainer.classList.add(this.className)
    }

    _closeBtn = document.createElement('div')
    _closeBtn.classList.add('cesium-popup-close-btn')

    _closeBtn.innerHTML = closeBtnIcon

    // header container
    var headerContainer = document.createElement('div')
    headerContainer.classList.add('cesium-popup-header-panel')

    this.headerTitle = document.createElement('div')
    this.headerTitle.classList.add('cesium-poput-header-title')
    this.headerTitle.innerHTML = this.title

    headerContainer.appendChild(this.headerTitle)
    _panelContainer.appendChild(_closeBtn)

    _panelContainer.appendChild(headerContainer)

    // content container

    _contentContainer = document.createElement('div')
    _contentContainer.classList.add('cesium-popup-content-panel')
    _contentContainer.innerHTML = this.content

    _panelContainer.appendChild(_contentContainer)

    //tip container
    var tipContaienr = document.createElement('div')
    tipContaienr.classList.add('cesium-popup-tip-panel')

    var tipDiv = document.createElement('div')
    tipDiv.classList.add('cesium-popup-tip-bottom')

    tipContaienr.appendChild(tipDiv)

    _panelContainer.appendChild(tipContaienr)

    _panelContainer.style.display = 'none'
    // add to Viewer Container
    _viewer.cesiumWidget.container.appendChild(_panelContainer)
    this.emit('open')

    }
  2. 实时更新面板位置(核心代码)

    CesiumPopup.prototype.addTo = function (viewer) {
    if (_viewer) this.remove()
    _viewer = viewer
    this.initPanle();
    //关闭按钮
    _closeBtn.addEventListener('click', this.closeHander, false)
    if (this.position) {
    _panelContainer.style.display = 'block'
    _renderListener = _viewer.scene.postRender.addEventListener(this.render, this)
    }

    return this
    }
    CesiumPopup.prototype.render = function () {
    var geometry = this.position
    if (!geometry) return
    var position = Cesium.SceneTransforms.wgs84ToWindowCoordinates(_viewer.scene, geometry)
    if (!position) {
    return
    }
    if (_panelContainer) {
    _panelContainer.style.left = position.x - _panelContainer.offsetWidth / 2 + this.offset[0] + 'px';
    _panelContainer.style.top = position.y - _panelContainer.offsetHeight - 10 + this.offset[1] + 'px';
    }
    }

    代码中用到Cesium提供的实时渲染事件:postRender ,此外还有 preRenderpreUpdatepostUpdate,具体详细去文档查看Scene

  3. 功能和事件

  • 方法:

    • 设置弹窗标题的方法 setTitle(title:String)
    • 设置弹窗位置方法 setPosition(position:Cesium.Cartesian3)
    • 设置弹窗内容方法 setHTML(html:HTML)
    • 设置弹窗偏移量方法 setOffset(offset:Array) 默认[0,0]
    • 弹窗添加到Viewer里面 addTo(viewer:Viewer)
  • 事件

    • open 弹窗显示事件
    • close 弹窗关闭事件
  1. 初始值
    var options = {
    title:String, //弹窗名称
    className: String, //弹窗额外类名
    offset:[0,0] //弹窗默认偏移量
    }
  2. 使用示例
    var a = new CesiumPopup({
    title:'信息'
    }).setPosition(position).setHTML(html).addTo(viewer).setTitle('详细信息框')

    a.on('close',function(){
    console.log('close')
    })

    a.on('open',function(){
    console.log('open')
    })
  3. 相关样式
    /* pop框css*/
    .cesium-popup-panel {
    opacity: 0.8;
    width: 312px;
    position: absolute;
    z-index: 999;
    color: #00fcf9;

    background: rgba(23, 50, 108, 0.6);
    border: 1px solid #4674d6;
    }
    .cesium-popup-tip-panel {
    width: 40px;
    height: 20px;
    position: absolute;
    left: 50%;
    bottom: -20px;
    margin-left: -20px;
    overflow: hidden;
    pointer-events: none;
    opacity: 0.8;
    }
    .cesium-popup-tip-bottom {
    width: 17px;
    background: rgba(23, 50, 108, 0.8);
    border-bottom: 1px solid #4674d6;
    height: 17px;
    padding: 1px;
    margin: -10px auto 0;
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    transform: rotate(45deg);
    }
    .cesium-popup-header-panel {
    /* display: flex; */
    /* justify-content: space-between; */
    align-items: center;
    font-size: 14px;
    padding: 5px 15px;
    background: rgba(23, 50, 108, 0.8);

    border-bottom: 1px solid #4674d6;
    }

    .cesium-poput-header-title {
    font-size: 16px;
    font-family: Microsoft YaHei;
    font-weight: 400;
    color: #ffffff;
    }

    .cesium-popup-content-panel {
    padding: 18px;
    }
    .cesium-popup-close-btn{
    float: right;
    position: relative;
    right: 10px;
    }
    .cesium-popup-close-btn,
    .cesium-popup-close-btn:focus {
    cursor: pointer;
    }
    cesium-popup-close-btn > svg:hover {
    color: #00fcf9 !important;
    }
    .cesium-popup-close-btn > svg {
    user-select: auto;
    color: #4674d6;
    cursor: pointer;
    width: 15px;
    /* height: 15px; */
    }

    代码

    完整代码都放到 github 上,需要的移步Cesium-demo-view

音乐小憩