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];
};