cesium标注,弹窗,点击事件的学习

需求:在cesium地图上,添加一个标注,点击标注弹窗显示内容,地图拖拉移动,弹窗内容跟随移动,始终保持在标注点未知上方。

实现:如图。

环境:vue、cesium。初始化地图相关代码就略过。

1.加载标注。

async loadMarker(item) {
    let self = this;
    let height = await this.getMapHeight(item.lng, item.lat)
    let marker = self.viewer.entities.add({
        clickType: 'marker', // 点击标记,用于分派点击事件
        name: item.name,
        extra: item,
        position: Cesium.Cartesian3.fromDegrees(item.lng, item.lat, height),
        billboard: {
            image: CESIUM_URL + `/map/img/ddc-icon.png`,
            scale: 0.4,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
            pixelOffset: new Cesium.Cartesian2(0, 20),
        },
        click: function (entity, e) {
            self.viewer.scene.globe.depthTestAgainstTerrain = true;
            if (self.viewer.camera.positionCartographic.height > 90000) {
                const camera = self.viewer.scene.camera;
                camera.flyTo({
                    destination: Cesium.Cartesian3.fromDegrees(item.lng, item.lat - 0.06, 5000.0),
                    duration: 5,
                    orientation: {
                        heading: Cesium.Math.toRadians(0.0),
                        pitch: Cesium.Math.toRadians(-35.0),
                        roll: 0.0,
                    },
                    complete: function () {
                        if (self.clickMarker && typeof self.clickMarker === "function") {
                            self.clickMarker(entity, e, item)
                        }
                    }
                });
            } else {
                if (self.clickMarker && typeof self.clickMarker === "function") {
                    self.clickMarker(entity, e, item)
                }
            }
        },
    });
    self.markers[item.name] = marker;
}

这里标注点的position,需要带高度,贴地高度之前有文档发过,代码中的click,并不是可以直接注册事件,这个到后面注册事件的时候直接分派。click/clickType/extra这几个字段是我额外添加的。目的就是点击的时候识别到clickType==marker,就直接执行额外添加的click函数。

2.注册点击事件。

// 注册鼠标左点击事件
registerLeftClick() {
    let self = this;
    let handler = new Cesium.ScreenSpaceEventHandler(self.viewer.canvas);
    function leftClickHandler(e) {
        // 先判断是否获取到目标要素
        let target = self.viewer.scene.pick(e.position);
        if (target) {
            // 分派业务逻辑
            if (!target.id) {
                self.mapClick(e);
                return;
            }
            if (target.id.clickType === 'marker') {
                // 点击标注
                if (typeof target.id.click == "function") {
                    target.id.click(target.id, e);
                }
            }
        }
    }
    handler.setInputAction(leftClickHandler, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

registerLeftClick这个函数会在初始化地图之后调用。

3.vue调用标注添加,注入clickMarker点击逻辑函数。

onMounted(() => {
  setTimeout(() => {
    map = new CimRander();
    map.initMap("home_map_container").then((_viewer: any) => {
      viewer.value = _viewer;
      _viewer.scene.postRender.addEventListener(updatePopupPosition);
      map.loadBoundary();
      setTimeout(() => {
        map.loadMarker({
          name: "marker1",
          lng: 114.100807,
          lat: 22.663633,
        });
      }, 1300);
      map.clickMarker = (entity: any, e: any, item: any) => {
        selectedEntity.data = entity;
        selectedEntity.win = layerInfoWin;
        layerInfoWin.show = true;
        updatePopupPosition();
      };
    });
  }, 10);
});
const layerInfoWin = reactive<any>({
  title: "标题",
  mj: "34.23亩",
  lx: "标注类型",
  dw: "点",
  show: false,
  position: {
    left: "-5000px",
    top: "-5000px",
  },
});
// 更新弹出框位置
const updatePopupPosition = () => {
  // 计算弹窗位置
  if (!selectedEntity.data) return;
  let cesiumPosition: any;
  if (selectedEntity.data.position instanceof Cesium.Cartesian3) {
    cesiumPosition = selectedEntity.data.position;
  } else {
    cesiumPosition = selectedEntity.data.position.getValue(
      viewer.value.clock.currentTime
    );
  }
  //如果视角和位置都没有变化,直接返回
  let camera = viewer.value.camera;
  let _thiscache =
    cesiumPosition.x +
    "=" +
    cesiumPosition.y +
    "-" +
    cesiumPosition.z +
    "-" +
    camera.positionWC.x +
    "=" +
    camera.positionWC.y +
    "-" +
    camera.positionWC.z +
    "-" +
    camera.heading +
    "-" +
    camera.pitch +
    "-" +
    camera.roll;
  if (_thiscache == _camera_cache.data) {
    return true;
  }
  _camera_cache.data = _thiscache;
  // 这一步是将 3D 世界中的点位转换为 2D 屏幕上的像素位置。
  const canvasPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
    viewer.value.scene,
    cesiumPosition
  );
  // 检查转换是否成功。有时候,如果点位不在当前视图中,则转换可能失败。
  if (canvasPosition) {
    // 更新弹窗位置
    selectedEntity.win.position.left = canvasPosition.x + 2 + "px";
    selectedEntity.win.position.top = canvasPosition.y - 0 + "px";
  }
};

代码主要是添加标注点marker1,监听场景渲染变化。调用updatePopupPosition。selectedEntity存点击选中的点。layerInfoWin弹框的信息,主要的是position。操作地图过程中,需要实时更新弹窗的position。

总结,主要目的是为了记录学习过程,代码中的很多变量没有解释,都是比较简单的vue响应式变量,或者是类中的属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值