Cesium聚合+点击地图缩放+entity弹窗

聚合

  • 聚合功能可以提高Cesium性能,减少Entity的渲染数量。
  • 以下代码在官网实例中都有,只是做了些许的改动。

注意聚合功能只对label标签,point点和广告牌billboard生效

效果放在前面

未聚合

聚合

添加窗体

可以看到 使用聚合前帧数在40左右,使用后在55左右

const loadCustom = () => {
    //聚合属性只对label标签,point点和广告牌billboard生效
    const dataSource = new Cesium.CustomDataSource("myData");
    for (let i = 0; i < 2000; ++i) {
        dataSource.entities.add({
            position: Cesium.Cartesian3.fromDegrees(103.769644 + Math.random() * 0.1, 31.097718 + Math.random() * 0.1),
            // point: {
            //     color: Cesium.Color.RED,
            // },
            label: {
                text: '车辆编号-' + i,
                pixelOffset: new Cesium.Cartesian2(10, -70), // 偏移方向
                fillColor: Cesium.Color.BLACK.withAlpha(0.65),
                backgroundColor: Cesium.Color.YELLOW,
                showBackground: true,
                font: '12px;'
            },
            billboard: {
                image: 'icons/icon_chezai_m_d.png',
                width: 64,
                height: 64,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // //相对于对象的原点(注意是原点的位置)的水平位置
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(12.5, 0), // 偏移
            }
        });
    }
    const dataSourcePromise = viewer.dataSources.add(dataSource);
    dataSourcePromise.then(function (dataSource) {
        const pixelRange = 15;
        const minimumClusterSize = 3;
        const enabled = true;
        dataSource.clustering.enabled = enabled; //是否聚合
        dataSource.clustering.pixelRange = pixelRange;
        dataSource.clustering.minimumClusterSize = minimumClusterSize;
        const pinBuilder = new Cesium.PinBuilder();
        const pin1000 = pinBuilder
            .fromText("1000+", Cesium.Color.RED, 48)
            .toDataURL();
        const pin500 = pinBuilder
            .fromText("100+", Cesium.Color.RED, 48)
            .toDataURL();
        const pin100 = pinBuilder
            .fromText("100+", Cesium.Color.RED, 48)
            .toDataURL();
        const pin50 = pinBuilder
            .fromText("50+", Cesium.Color.RED, 48)
            .toDataURL();
        const pin40 = pinBuilder
            .fromText("40+", Cesium.Color.ORANGE, 48)
            .toDataURL();
        const pin30 = pinBuilder
            .fromText("30+", Cesium.Color.YELLOW, 48)
            .toDataURL();
        const pin20 = pinBuilder
            .fromText("20+", Cesium.Color.GREEN, 48)
            .toDataURL();
        const pin10 = pinBuilder
            .fromText("10+", Cesium.Color.BLUE, 48)
            .toDataURL();
        const singleDigitPins = new Array(8);
        for (let i = 0; i < singleDigitPins.length; ++i) {
            singleDigitPins[i] = pinBuilder
                .fromText(`${i + 2}`, Cesium.Color.VIOLET, 48)
                .toDataURL();
        }
        function customStyle() {
            if (Cesium.defined(removeListener)) {
                removeListener && removeListener();
                removeListener = undefined;
            } else {
                removeListener = dataSource.clustering.clusterEvent.addEventListener(
                    function (clusteredEntities, cluster) {
                        cluster.label.show = false;
                        cluster.billboard.show = true;
                        cluster.billboard.id = cluster.label.id;
                        cluster.billboard.verticalOrigin =
                            Cesium.VerticalOrigin.BOTTOM;

                        if (clusteredEntities.length >= 1000) {
                            cluster.billboard.image = pin1000;
                        } else if (clusteredEntities.length >= 500) {
                            cluster.billboard.image = pin500;
                        } else if (clusteredEntities.length >= 100) {
                            cluster.billboard.image = pin100;
                        } else if (clusteredEntities.length >= 50) {
                            cluster.billboard.image = pin50;
                        } else if (clusteredEntities.length >= 40) {
                            cluster.billboard.image = pin40;
                        } else if (clusteredEntities.length >= 30) {
                            cluster.billboard.image = pin30;
                        } else if (clusteredEntities.length >= 20) {
                            cluster.billboard.image = pin20;
                        } else if (clusteredEntities.length >= 10) {
                            cluster.billboard.image = pin10;
                        } else {
                            cluster.billboard.image =
                                singleDigitPins[clusteredEntities.length - 2];
                        }
                    }
                );
            }
            const pixelRange = dataSource.clustering.pixelRange;
            dataSource.clustering.pixelRange = 0;
            dataSource.clustering.pixelRange = pixelRange;
        }
        customStyle();
        const handler = new Cesium.ScreenSpaceEventHandler(
            viewer.scene.canvas
        );
        handler.setInputAction(function (movement) {
            const pickedLabel = viewer.scene.pick(movement.position);
            if (Cesium.defined(pickedLabel)) {
                const ids = pickedLabel.id;
                if(ids.length > 1) {
                	let PoRay = viewer.camera.getPickRay(ray);
                	const car3 = viewer.scene.globe.pick(PoRay, viewer.scene);
                   let cartographic = Cesium.Cartographic.fromCartesian(car3);
				   let longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
				   let latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
                    viewer.camera.flyTo({
			            destination: Cesium.Cartesian3.fromDegrees(longitudeString , latitudeString , 			height / 1.8),
			            duration: 1.0
			        });
                }
                console.log(pickedLabel)
                // if (Array.isArray(ids)) {
                //     for (let i = 0; i < ids.length; ++i) {
                //         ids[i].billboard.color = Cesium.Color.RED;
                //     }
                // }
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    })
}

entity添加弹窗

拾取

  • //识别到的entity ids为对象时单个entity ids为数组时 为entity数组
handler.setInputAction(function (movement) {
  const pickedLabel = viewer.scene.pick(movement.position);
    if (Cesium.defined(pickedLabel)) {
        const ids = pickedLabel.id;
       		console.log(ids)
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

添加弹窗-核心代码

  • 利用entity的point定位窗体,给entity一个空点,在cesium下一次渲染前 获取当前entity在屏幕上的坐标值 赋值给dom元素。
  • 缺点是即使在地球的另一面也还是会显示窗体,这个可以后面优化
  • let pos = (props.trackEntity.position && props.trackEntity.position.getValue(Cesium.JulianDate.now())) || Cesium.Cartesian3.ZERO; screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates( Viewer.scene, pos );
const handler = new Cesium.ScreenSpaceEventHandler();
const onUpdate = () => {
  if (element == null) return;
  let screenPos;
  if (trackCursor) {
    screenPos = mousePos;
  } else if (props.trackEntity) {
    let pos =
      (props.trackEntity.position &&
        props.trackEntity.position.getValue(Cesium.JulianDate.now())) ||
      Cesium.Cartesian3.ZERO;
    screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
      Viewer.scene,
      pos
    );
  } else if (props.trackPos) {
    screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
      Viewer.scene,
      props.trackPos
    );
  }

  if (screenPos) {
    if (element.value) {
      element.value.style.display = "";
      switch (props.alignX) {
        case "left":
          element.value.style.left = screenPos.x + "px";
          break;
        case "center":
          element.value.style.left =
            screenPos.x + element.value.clientWidth * 0.5 + "px";
          break;
        case "right":
        default:
          element.value.style.left =
            screenPos.x - element.value.clientWidth * 0.5 + "px";
      }

      switch (props.alignY) {
        case "top":
          element.value.style.top =
            screenPos.y - element.value.clientHeight + "px";
          break;
        case "bottom":
          // this.element.style.top = (screenPos.y + this.element.clientHeight * 0.5) + "px";
          element.value.style.top = screenPos.y + "px";
          break;
        case "center":
        default:
          element.value.style.top =
            screenPos.y - element.value.clientHeight * 0.5 + "px";
      }
    }
  } else {
    if (element.value) element.value.style.display = "none";
  }
};
onMounted(() => {
  handler.setInputAction((event) => {
    let offsetToLeftTop = Viewer.container.getBoundingClientRect();
    mousePos = Cesium.Cartesian2.subtract(
      event.endPosition,
      new Cesium.Cartesian2(offsetToLeftTop.left, offsetToLeftTop.top),
      new Cesium.Cartesian2()
    );
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  Viewer.scene.preUpdate.addEventListener(onUpdate);
});

你可能感兴趣的:(Cesium,Vue3,TS,前端)