import { deepMerge, wgs84ToGcj02Format, convertPosition } from "../util"; import Layer from "./layer"; import CesiumPopup from "../base/cesium_popup"; export default (hnMap: any) => { const defaultOption = { id: "", position: [], pixelRange: 20, cluster: true, image: "", width: 20, height: 20, data: null, }; class mars3d_class extends Layer(hnMap) { type: any = "cluster"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config_layer: any = null; config_label: any = null; children: any = null; layerEntity: any = null; constructor(option: any) { super(option); this.id = option.id; this.children = []; deepMerge(this.option, option); this.config_layer = this.formatConfigLayer(this.option); this.config_label = this.formatConfigLabel(this.option); this.layerEntity = new mars3d.layer.GraphicLayer(this.config_layer); // this.graphic = new mars3d.graphic.BillboardEntity(this.config_label); } // 格式化layer配置 formatConfigLayer(option: any) { return { id: option.id, cluster: { enabled: option.cluster !== false, // 默认开启聚合 pixelRange: option.pixelRange || 20, // 添加更多聚合样式配置 styles: [ { scale: 1, image: "img/marker/mark1.png", label: { text: "{count}", color: "#ffffff", font_size: 16, stroke: true, strokeColor: "#000000", }, }, { scale: 1.5, image: "img/marker/mark2.png", label: { text: "{count}", color: "#ffffff", font_size: 18, }, }, { scale: 2, image: "img/marker/mark3.png", label: { text: "{count}", color: "#ffffff", font_size: 20, }, }, ], }, }; } // 格式化点位配置 formatConfigLabel(option: any) { return { id: "label_" + option.id, image: option.image, width: option.width, height: option.height, }; } clearEntity() { this.children = []; if (this.layerEntity) { this.layerEntity.clear(); } } addEntity(entity: any) { this.children.push(entity); if (this.layerEntity) { this.layerEntity.addGraphic(entity.graphic); } } setPosition(data: any) { this.clearEntity(); data.forEach((item: any, index: any) => { let imagePointOption = { id: this.config_label.id + "_point" + item.id, position: item.position, image: this.config_label.image, height: this.config_label.height, width: this.config_label.width, data: item.data, }; const imagePoint = new hnMap.ImagePoint(imagePointOption); this.addEntity(imagePoint); }); } // 修改 cluster.ts 中的 mars3d_class 类 destroy() { this.clearEntity(); if (this.layerEntity) { this.layerEntity.remove(true); } hnMap.map.layerList = hnMap.map.layerList.filter( (v: any) => v.id !== this.id ); } // 添加属性弹窗 addPopupByAttr() { this.layerEntity.bindPopup((event: any) => { const data = event.graphic.attr; return mars3d.Util.getTemplateHtml({ title: "详情", template: "all", attr: data, }); }); } // 添加自定义dom弹窗 addCustomPopup(getCustomDom: any) { this.layerEntity.bindPopup( async (event: any) => { if (event.graphic.attr) { const data = event.graphic.attr || {}; return await getCustomDom(data); } }, { offsetY: -20 } ); } flyTo() { this.layerEntity.flyTo(); } getEntity(entityParam: any) { let entity; if (typeof entityParam == "string") { entity = this.children.find((v: any) => v.id === entityParam); } else { entity = entityParam; } if (!entity) { return Promise.reject(new Error("未找到此图形")); } return entity; } // 手动打开聚合功能 openCluster() { deepMerge(this.option, { cluster: true }); this.config_layer = this.formatConfigLayer(this.option); this.layerEntity.clusterEnabled = true; } // 手动关闭聚合功能 closeCluster() { deepMerge(this.option, { cluster: false }); this.config_layer = this.formatConfigLayer(this.option); this.layerEntity.clusterEnabled = false; } } class gaode_class { type: any = "cluster"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; layerEntity: any = null; // 创建全局信息窗口实例 infoWindow: any = null; constructor(option: any) { this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.layerEntity = new AMap.MarkerCluster( hnMap.map.map, this.config.position, this.config ); } formatConfig(option: any) { const position = option.position.map((item: any, index: any) => { return { lnglat: wgs84ToGcj02Format(item), // 添加弹窗属性参数 extData: { id: this.id + "_point" + index, }, }; }); const count = position.length; const _renderClusterMarker = (context: any) => { var factor = Math.pow(context.count / count, 1 / 18); var div = document.createElement("div"); var Hue = 180 - factor * 180; var bgColor = "hsla(" + Hue + ",100%,40%,0.7)"; var fontColor = "hsla(" + Hue + ",100%,90%,1)"; var borderColor = "hsla(" + Hue + ",100%,40%,1)"; var shadowColor = "hsla(" + Hue + ",100%,90%,1)"; div.style.backgroundColor = bgColor; var size = Math.round(30 + Math.pow(context.count / count, 1 / 5) * 20); div.style.width = div.style.height = size + "px"; div.style.border = "solid 1px " + borderColor; div.style.borderRadius = size / 2 + "px"; div.style.boxShadow = "0 0 5px " + shadowColor; div.innerHTML = context.count; div.style.lineHeight = size + "px"; div.style.color = fontColor; div.style.fontSize = "14px"; div.style.textAlign = "center"; context.marker.setOffset(new AMap.Pixel(-size / 2, -size / 2)); context.marker.setContent(div); }; const _renderMarker = (context: any) => { let icon = new AMap.Icon({ image: this.option.style.image, imageSize: new AMap.Size( this.option.style.height, this.option.style.width ), size: new AMap.Size( this.option.style.height, this.option.style.width ), }); context.marker.setIcon(icon); }; return { id: option.id, position, gridSize: option.pixelRange, // 设置网格像素大小 clusterByZoomChange: true, renderClusterMarker: _renderClusterMarker, // 自定义聚合点样式 renderMarker: _renderMarker, // 自定义非聚合点样式 }; } setPosition(position: any) { deepMerge(this.option, { position: position }); this.config = this.formatConfig(this.option); this.layerEntity.setData(this.config.position); } destroy() { this.layerEntity.setMap(null); hnMap.map.layerList = hnMap.map.layerList.filter( (v: any) => v.id !== this.id ); } flyTo() { let totalLng = 0; let totalLat = 0; this.config.position.map((item: any) => { totalLng += item.lnglat.lng; totalLat += item.lnglat.lat; }); const centerLng = totalLng / this.config.position.length; const centerLat = totalLat / this.config.position.length; hnMap.map.map.setCenter([centerLng, centerLat]); } // 添加属性弹窗 addPopupByAttr() { if (!this.infoWindow) { this.infoWindow = new AMap.InfoWindow({ offset: new AMap.Pixel(0, -30), }); } this.layerEntity.on("click", (cluster: any) => { if (cluster.clusterData.length === 1) { let content = ""; const data = cluster.clusterData[0].extData; for (const key in data) { content += `
${key}: ${data[key]}
`; } this.infoWindow.setContent(content); this.infoWindow.open(hnMap.map.map, cluster.marker._position); } }); } // 添加自定义dom弹窗 addCustomPopup(getCustomDom: any) { if (!this.infoWindow) { this.infoWindow = new AMap.InfoWindow({ offset: new AMap.Pixel(0, -30), }); } this.layerEntity.on("click", (cluster: any) => { if (cluster.clusterData.length === 1) { let content = ""; const data = cluster.clusterData[0].extData; const dom = getCustomDom(data); this.infoWindow.setContent(dom); this.infoWindow.open(hnMap.map.map, cluster.marker._position); } }); } } class siji_class { type: any = "cluster"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config_layer: any = null; config_label: any = null; config_Image: any = null; layerEntity: any = null; // 创建全局信息窗口实例 infoWindow: any = null; event: any = {}; constructor(option: any) { this.id = option.id; deepMerge(this.option, option); hnMap.map.map.addSource(this.id, { type: "geojson", data: { type: "FeatureCollection", features: this.option.position.map((v: any) => ({ type: "Feature", geometry: { type: "Point", coordinates: wgs84ToGcj02Format(convertPosition(v.position)), }, properties: { ...v, lnglat: wgs84ToGcj02Format(convertPosition(v.position)), }, })), }, cluster: true, clusterMaxZoom: 12, // 最大聚类层级 clusterRadius: 100, // 聚合点半径,默认50 }); this.config_layer = this.formatConfigLayer(this.option); this.config_label = this.formatConfigLabel(this.option); this.config_Image = this.formatConfigImage(this.option); } formatConfigLayer(option: any) { return { id: "clusters_" + option.id, type: "circle", source: this.id, filter: ["has", "point_count"], paint: { // 使用step表达式,用于分段匹配圆点的颜色和半径 // 根据当前"point_count"值匹配对应的内容 // 默认为"#9faebf" // 当大于10小于30时,返回"#3583de" // 大于30小于55时,返回"#04b71e" "circle-color": [ "step", ["get", "point_count"], "#9faebf", 10, "#3583de", 30, "#04b71e", 55, "#ff9800", 100, "#f61402", 300, "#f61402", ], "circle-radius": [ "step", ["get", "point_count"], 20, 50, 30, 100, 35, 500, 35, 2000, 40, 5000, 40, ], "circle-opacity": 0.7, "circle-stroke-width": 3, "circle-stroke-color": "#ffffff", }, }; } formatConfigLabel(option: any) { return { id: "clusterCount_" + option.id, type: "symbol", source: this.id, filter: ["has", "point_count"], layout: { "text-field": "{point_count_abbreviated}", "text-font": ["Microsoft YaHei Regular"], "text-size": 14, }, paint: { "text-color": "#ffffff", }, }; } formatConfigImage(option: any) { return { id: "choicePoi_" + option.id, type: "symbol", source: this.id, filter: ["!has", "point_count"], layout: { "icon-image": option.id + "_poiImage", }, paint: { "text-color": "#555252", "text-halo-color": "#FFFFFF", "text-halo-width": 1.33333, }, }; } /** * 监听事件 * @param eventType 事件类型 * @param callback 事件回调函数 */ on(eventType: string, callback: (data: any) => void): void { this.off(eventType); switch (eventType) { case "click": this.event[eventType] = (e: any) => { const features = hnMap.map.map.queryRenderedFeatures(e.point); if (features.length > 0) { callback(features[0].properties); } }; break; } hnMap.map.map.on(eventType, this.event[eventType]); } /** * 移除事件监听 * @param eventType 事件类型 */ off(eventType: string): void { if (this.event[eventType]) { hnMap.map.map.off(eventType, this.event[eventType]); delete this.event[eventType]; } } // 添加属性弹窗 addPopupByAttr() { console.log("addPopupByAttr======", this.config_label); // 如果已有弹窗,先关闭 this.removePopup(); this.infoWindow = new SGMap.Popup({ offset: { bottom: [0, 0] }, className: "my-attrPopup-class", }); const handleClick = (e: any) => { const features = hnMap.map.map.queryRenderedFeatures(e.point); // console.log("e.features===", features); let data = features; // 创建弹窗内容 let content = ""; for (const key in data) { content += `
${key}: ${data[key]}
`; } this.infoWindow.setHTML(content); this.infoWindow.setLngLat(e.lngLat).addTo(hnMap.map.map); }; hnMap.map.map.on("click", "choicePoi_" + this.id, handleClick); } // 添加自定义dom弹窗 addCustomPopup(getCustomDom: any) { // 如果已有弹窗,先关闭 this.removePopup(); this.infoWindow = new SGMap.Popup({ offset: { bottom: [0, 0] }, className: "my-customPopup-class", }); const handleClick = (e: any) => { const features = hnMap.map.map.queryRenderedFeatures(e.point); const data = features; const dom = getCustomDom(data); this.infoWindow.setHTML(dom); this.infoWindow.setLngLat(e.lngLat).addTo(hnMap.map.map); }; hnMap.map.map.on("click", "choicePoi_" + this.id, handleClick); } // 弹窗删除 removePopup() { if (this.infoWindow) { this.infoWindow.remove(); } } destroy() { // 移除所有相关图层 if (hnMap.map.map) { if (hnMap.map.map.getLayer("clusters_" + this.id)) { hnMap.map.map.removeLayer("clusters_" + this.id); } if (hnMap.map.map.getLayer("clusterCount_" + this.id)) { hnMap.map.map.removeLayer("clusterCount_" + this.id); } if (hnMap.map.map.getLayer("choicePoi_" + this.id)) { hnMap.map.map.removeLayer("choicePoi_" + this.id); } // 移除数据源 if (hnMap.map.map.getSource(this.id)) { hnMap.map.map.removeSource(this.id); } } hnMap.map.layerList = hnMap.map.layerList.filter( (v: any) => v.id !== this.id ); } } // Cesium 聚合点类实现 class cesium_class extends Layer(hnMap) { type: any = "cluster"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; layerEntity: any = null; graphic: any = null; children: any = []; entities: any = []; // 存储所有实体 clusterDataSource: any = null; // 用于聚合的数据源 /** 事件监听器集合 */ event: Record = {}; /** 屏幕空间事件处理器 */ screenSpaceEventHandler: any = null; /** 弹窗实例 */ popup: any = null; /** 弹窗内容缓存 */ popupContent: string | null = null; /** 是否显示弹窗 */ showPopupOnClick: boolean = false; /** 弹窗样式配置 */ popupStyle: any = null; constructor(option: any) { super(option); this.id = option.id; deepMerge(this.option, option); // 创建自定义数据源用于聚合 this.clusterDataSource = new Cesium.CustomDataSource(this.id); // 添加到地图 if (hnMap.map.map) { hnMap.map.map.dataSources.add(this.clusterDataSource); } // 启用聚合 if (this.clusterDataSource.clustering) { this.clusterDataSource.clustering.enabled = this.option.cluster !== false; this.clusterDataSource.clustering.pixelRange = this.option.pixelRange || 20; // 确保聚合点有正确的显示设置 this.clusterDataSource.clustering.minimumClusterSize = this.option.minimumClusterSize || 2; this.clusterDataSource.clustering.clusterBillboards = true; // 自定义聚合点的显示 this.clusterDataSource.clustering.clusterEvent.addEventListener( this.onClusterEvent.bind(this) ); } this.layerEntity = this.clusterDataSource; // 创建弹窗实例 if (hnMap && hnMap.map && hnMap.map.map) { const PopupClass = CesiumPopup(hnMap); this.popup = new PopupClass(hnMap.map.map, { style: this.popupStyle }); } } // 聚合事件处理 onClusterEvent(entities: any, cluster: any) { // 确保聚合点对象有正确的结构 if (!cluster.billboard) { cluster.billboard = {}; } if (!cluster.label) { cluster.label = {}; } // 设置聚合点的标签样式 cluster.label.show = true; cluster.label.text = entities.length.toLocaleString(); cluster.label.fillColor = Cesium.Color.WHITE; // cluster.label.outlineColor = Cesium.Color.BLACK; // cluster.label.outlineWidth = 2; cluster.label.font = "14px sans-serif"; cluster.label.pixelOffset = new Cesium.Cartesian2(0, -10); cluster.label.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND; cluster.label.verticalOrigin = Cesium.VerticalOrigin.CENTER; cluster.label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER; cluster.label.disableDepthTestDistance = Number.POSITIVE_INFINITY; // 设置聚合点的点样式(使用billboard方式) let color, pixelSize; if (entities.length > 100) { color = Cesium.Color.RED.withAlpha(0.8); pixelSize = 50; } else if (entities.length > 50) { color = Cesium.Color.ORANGE.withAlpha(0.8); pixelSize = 45; } else if (entities.length > 10) { color = Cesium.Color.YELLOW.withAlpha(0.8); pixelSize = 40; } else { color = Cesium.Color.GREEN.withAlpha(0.8); pixelSize = 35; } // 通过创建一个小的圆形图片来表示聚合点 const canvas = document.createElement("canvas"); canvas.width = pixelSize; canvas.height = pixelSize; const ctx = canvas.getContext("2d"); if (ctx) { ctx.beginPath(); ctx.arc(pixelSize / 2, pixelSize / 2, pixelSize / 2, 0, 2 * Math.PI); ctx.fillStyle = color.toCssColorString(); ctx.fill(); // ctx.strokeStyle = Cesium.Color.BLACK.toCssColorString(); // ctx.lineWidth = 1; // ctx.stroke(); // 绘制外框 } cluster.billboard.image = canvas.toDataURL(); cluster.billboard.show = true; cluster.billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND; cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.CENTER; cluster.billboard.horizontalOrigin = Cesium.HorizontalOrigin.CENTER; cluster.billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY; cluster.billboard.pixelOffset = new Cesium.Cartesian2(0, -10); // 为聚合点添加cluster: true标识 cluster.cluster = true; } // 修改 setPosition 方法 setPosition(positions: any[]) { // 清除现有实体 - 确保完全清除 this.clearEntity(); // 添加新的实体 positions.forEach((item: any, index: any) => { const position = Cesium.Cartesian3.fromDegrees( item.position[0], item.position[1], item.position[2] || 0 ); // 创建唯一的实体ID const uniqueId = `${this.id}_point_${index}`; // 创建实体对象 const entity = new Cesium.Entity({ id: uniqueId, // 使用唯一ID position: position, billboard: { image: this.option.image || "/path/to/default/icon.png", // 添加默认图片 width: Number(this.option.width) || 20, height: Number(this.option.height) || 20, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, disableDepthTestDistance: Number.POSITIVE_INFINITY, }, properties: item.data || this.option.data || {}, }); // 为实体添加标识 entity.cluster = false; try { // 先添加到数据源 this.clusterDataSource.entities.add(entity); // 再添加到本地数组 this.entities.push(entity); } catch (error) { console.error("添加实体失败:", error); // 从数组中移除失败的实体 const entityIndex = this.entities.indexOf(entity); if (entityIndex > -1) { this.entities.splice(entityIndex, 1); } } }); } // 修改 clearEntity 方法 clearEntity() { // 从数据源中清除所有实体 if (this.clusterDataSource) { try { this.clusterDataSource.entities.removeAll(); } catch (error) { console.error("清除数据源实体失败:", error); } } // 清空本地数组 this.entities = []; } // 飞行到聚合点 flyTo(option: any = {}) { if (this.clusterDataSource && hnMap.map.map) { // 获取所有实体的位置 const entities = this.clusterDataSource.entities.values; if (entities && entities.length > 0) { const positions = entities .filter((entity: any) => entity.position) .map((entity: any) => entity.position.getValue(Cesium.JulianDate.now()) ) .filter(Boolean); if (positions.length > 0) { try { // 计算包围球 const boundingSphere = Cesium.BoundingSphere.fromPoints(positions); // 增加包围球半径以确保视野充足 const radiusMultiplier = option.radiusMultiplier || 3.0; hnMap.map.map.camera.flyToBoundingSphere(boundingSphere, { duration: option.duration || 2.0, offset: new Cesium.HeadingPitchRange( Cesium.Math.toRadians(option.heading || 0), Cesium.Math.toRadians(option.pitch || -45), boundingSphere.radius * radiusMultiplier ), complete: option.complete, cancel: option.cancel, }); return; } catch (error) { console.error("飞行定位到聚合点失败:", error); } } } // 如果没有实体或位置信息,回退到默认的flyTo方法 try { hnMap.map.map.flyTo(this.clusterDataSource, { duration: option.duration || 2.0, complete: option.complete, cancel: option.cancel, }); } catch (error) { console.error("默认飞行定位失败:", error); } } } // 销毁 destroy() { this.clearEntity(); // 从地图中移除数据源 if (hnMap.map.map && this.clusterDataSource) { hnMap.map.map.dataSources.remove(this.clusterDataSource, true); } // 移除所有事件监听 this.offAll(); hnMap.map.layerList = hnMap.map.layerList.filter( (v: any) => v.id !== this.id ); } /** * 监听事件 * @param eventType 事件类型 * @param callback 事件回调函数 */ on(eventType: string, callback: (data: any) => void): void { this.off(eventType); if (this.clusterDataSource && hnMap && hnMap.map && hnMap.map.map) { // 初始化屏幕空间事件处理器 if (!this.screenSpaceEventHandler) { this.screenSpaceEventHandler = new Cesium.ScreenSpaceEventHandler( hnMap.map.map.canvas ); // 创建屏幕空间事件处理器 } switch (eventType) { case "click": this.event[eventType] = (click: any) => { // 检查是否点击到了当前数据源中的实体 const pickedObject = hnMap.map.map.scene.pick(click.position); if (pickedObject && pickedObject.id) { const entity = pickedObject.id; // 检查实体是否属于当前数据源 const isEntityInDataSource = this.clusterDataSource.entities.contains(entity); if (isEntityInDataSource) { // 检查是否是聚合点,如果是聚合点则不触发事件 if (entity.cluster === true) { return; } const data = entity.properties || this.option.data || {}; callback(data); // 显示弹窗 if (this.showPopupOnClick && this.popupContent) { this.showPopupAtPosition(click.position); } } } }; this.screenSpaceEventHandler.setInputAction( this.event[eventType], Cesium.ScreenSpaceEventType.LEFT_CLICK ); break; case "mousemove": this.event[eventType] = (movement: any) => { const pickedObject = hnMap.map.map.scene.pick( movement.endPosition ); if (pickedObject && pickedObject.id) { const entity = pickedObject.id; const isEntityInDataSource = this.clusterDataSource.entities.contains(entity); if (isEntityInDataSource) { // 检查是否是聚合点 if (entity.cluster === true) { return; } const data = entity.properties || this.option.data || {}; callback(data); } } }; this.screenSpaceEventHandler.setInputAction( this.event[eventType], Cesium.ScreenSpaceEventType.MOUSE_MOVE ); break; } } } /** * 移除事件监听 * @param eventType 事件类型 */ off(eventType: string): void { if (this.event[eventType] && this.screenSpaceEventHandler) { try { switch (eventType) { case "click": this.screenSpaceEventHandler.removeInputAction( Cesium.ScreenSpaceEventType.LEFT_CLICK ); break; case "mousemove": this.screenSpaceEventHandler.removeInputAction( Cesium.ScreenSpaceEventType.MOUSE_MOVE ); break; } } catch (error) { console.warn("移除事件监听失败:", error); } delete this.event[eventType]; } } /** * 移除所有事件监听 */ private offAll(): void { // 清理所有事件监听器 Object.keys(this.event).forEach((eventType) => { this.off(eventType); }); // 销毁屏幕空间事件处理器 if (this.screenSpaceEventHandler) { try { this.screenSpaceEventHandler.destroy(); } catch (error) { console.warn("销毁屏幕空间事件处理器失败:", error); } this.screenSpaceEventHandler = null; } } // 属性弹窗 addPopupByAttr() { this.showPopupOnClick = true; if (this.option && this.option.data) { // 生成属性弹窗内容 let content = '
'; for (const key in this.option.data) { if (this.option.data.hasOwnProperty(key)) { content += `
${ key + ":" + this.option.data[key] }
`; } } content += "
"; this.popupContent = content; // 设置点击事件 this.bindClickEvent(); } } // 自定义弹窗 addCustomPopup(getCustomDom: any) { this.showPopupOnClick = true; const data = this.option && this.option.data ? this.option.data : {}; try { const customDom = getCustomDom(data); if (customDom instanceof Promise) { customDom .then((dom: string) => { this.popupContent = dom; this.bindClickEvent(); }) .catch((error: any) => { console.error("生成自定义弹窗DOM失败:", error); }); } else { this.popupContent = customDom; this.bindClickEvent(); } } catch (error) { console.error("生成自定义弹窗DOM失败:", error); } } /** * 绑定点击事件 */ bindClickEvent(): void { // 销毁已有的事件处理器 if (this.screenSpaceEventHandler) { try { this.screenSpaceEventHandler.destroy(); } catch (error) { console.warn("销毁原有事件处理器失败:", error); } } // 创建新的屏幕空间事件处理器 if (!hnMap.map.map || !hnMap.map.map.canvas) { console.warn("地图或画布不可用,无法绑定点击事件"); return; } this.screenSpaceEventHandler = new Cesium.ScreenSpaceEventHandler( hnMap.map.map.canvas ); this.screenSpaceEventHandler.setInputAction((movement: any) => { // 检查是否点击到了当前数据源中的实体 const pickedObject = hnMap.map.map.scene.pick(movement.position); if (pickedObject && pickedObject.id) { const entity = pickedObject.id; const isEntityInDataSource = this.clusterDataSource.entities.contains(entity); if (isEntityInDataSource) { // 检查是否是聚合点,如果是聚合点则不触发事件 if (entity.cluster === true) { return; } this.showPopupAtPosition(movement.position); } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } /** * 在指定位置显示弹窗 * @param position 屏幕坐标位置 */ showPopupAtPosition(position: any): void { if (!this.popup || !this.popupContent) return; // 获取点击的世界坐标 const ray = hnMap.map.map.camera.getPickRay(position); if (!ray) return; // 获取笛卡尔坐标 const cartesian = hnMap.map.map.scene.globe.pick( ray, hnMap.map.map.scene ); if (!cartesian) return; // 显示弹窗 this.popup.show({ cartesian }, this.popupContent); } /** * 设置弹窗样式 * @param style 弹窗样式配置 */ setPopupStyle(style: any): void { this.popupStyle = style; // 如果弹窗已存在,重新创建以应用新样式 if (this.popup && hnMap && hnMap.map && hnMap.map.map) { this.popup.destroy(); const PopupClass = CesiumPopup(hnMap); this.popup = new PopupClass(hnMap.map.map, { style: this.popupStyle, }); } } } const fn: any = { mars3d: mars3d_class, gaode: gaode_class, siji: siji_class, cesium: cesium_class, }; return fn[hnMap.mapType]; };