import { deepMerge, getLevelMiddleHeight, wgs84ToGcj02Format, convertPosition, } from "../util"; import Mars3dEntity from "../base/mars3d_entity"; import GaodeEntity from "../base/gaode_entity"; import SijiEntity from "../base/siji_entity"; import CesiumEntity from "../base/cesium_entity"; export default (hnMap: any) => { const defaultOption = { id: "", position: [], color: "#ffffff", opacity: 1, size: 6, text: "", fontSize: 12, fontColor: "#ffffff", fontOpacity: 1, fontOffset: [0, 0], outline: false, outlineColor: "#ffffff", outlineWidth: 20, outlineOpacity: 0.5, textOutline: false, textOutlineColor: "#000000", textOutlineOpacity: 0.6, textOutlineWidth: 2, textBackgroundColor: "", textBackgroundOpacity: 0.5, scaleByDistance: true, distanceDisplayCondition: false, distanceDisplayCondition_far: 1, distanceDisplayCondition_near: 18, data: null, }; class mars3d_class extends Mars3dEntity { type: any = "point"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; graphic: any = null; constructor(option: any) { super(hnMap); this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.graphic = new mars3d.graphic.PointEntity(this.config); } formatConfig(option: any) { const distanceDisplayCondition_far = getLevelMiddleHeight( option.distanceDisplayCondition_far ); const distanceDisplayCondition_near = getLevelMiddleHeight( option.distanceDisplayCondition_near ); return { id: option.id, position: option.position, style: { color: option.color, opacity: option.opacity, pixelSize: option.size, outline: option.outline, outlineColor: option.outlineColor, outlineWidth: option.outlineWidth, outlineOpacity: option.outlineOpacity, clampToGround: !option.position[2], scaleByDistance: option.scaleByDistance, distanceDisplayCondition: option.distanceDisplayCondition, distanceDisplayCondition_far: distanceDisplayCondition_far, distanceDisplayCondition_near: distanceDisplayCondition_near, label: { text: option.text, font_size: option.fontSize, color: option.fontColor, opacity: option.fontOpacity, outline: option.textOutline, outlineColor: option.textOutlineColor, outlineOpacity: option.textOutlineOpacity, outlineWidth: option.textOutlineWidth, background: !!option.textBackgroundColor, backgroundColor: option.textBackgroundColor, backgroundOpacity: option.textBackgroundOpacity, pixelOffset: option.fontOffset, scaleByDistance: option.scaleByDistance, distanceDisplayCondition: option.distanceDisplayCondition, distanceDisplayCondition_far: distanceDisplayCondition_far, distanceDisplayCondition_near: distanceDisplayCondition_near, }, }, attr: option.data, }; } set(option: any) { deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.graphic.setOptions(this.config); } } class gaode_class extends GaodeEntity { id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; graphic: any = null; constructor(option: any) { super(hnMap); this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.graphic = new AMap.CircleMarker(this.config); } formatConfig(option: any) { let amapPosition = wgs84ToGcj02Format(option.position); return { center: amapPosition, radius: option.size / 2, strokeColor: option.outlineColor, strokeOpacity: option.outlineOpacity, strokeWeight: option.outlineWidth, fillColor: option.color, fillOpacity: option.opacity, extData: { id: option.id, data: option.data, }, }; } set(option: any) { deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.graphic.setOptions(this.config); this.graphic.setCenter(this.config.center); } } class siji_class extends SijiEntity { type: any = "point"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; constructor(option: any) { super(hnMap); this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); } formatConfig(option: any) { let config: any = {}; config = { id: option.id, type: "circle", source: { type: "geojson", data: { type: "FeatureCollection", features: [ { type: "Feature", geometry: { type: "Point", coordinates: convertPosition(option.position), }, properties: { ...option.data, }, }, ], }, }, paint: { "circle-opacity": Number(option.opacity), "circle-radius": Number(option.size), "circle-color": option.color, "circle-stroke-color": option.outline ? option.outlineColor : "transparent", "circle-stroke-width": option.outline ? Number(option.outlineWidth) : 0, "circle-stroke-opacity": option.outline ? Number(option.outlineOpacity) : 1, // 边框样式 }, // 填充样式 }; return config; } /** * 将 pixelOffset 转换为 text-offset (ems) * @param {Array} pixelOffset - [x, y] 像素偏移 * @param {number} textSizePx - 字体大小(px) * @returns {Array} text-offset in ems */ pixelOffsetToTextOffset(pixelOffset: any, textSizePx: any): Array { return [pixelOffset[0] / textSizePx, pixelOffset[1] / textSizePx]; } set(option: any) { deepMerge(this.option, option); this.config = this.formatConfig(this.option); let mySource = hnMap.map.map.getSource(this.config.id); mySource.setData({ type: "FeatureCollection", features: [ { type: "Feature", properties: {name: this.option.text}, geometry: { type: "Point", coordinates: convertPosition(this.option.position), }, }, ], }); for (let key in this.config) { if (this.config.hasOwnProperty(key)) { if (key == "paint") { for (let key2 in this.config[key]) { if (this.config[key].hasOwnProperty(key2)) { // 遍历 paint 属性 hnMap.map.map.setPaintProperty( this.config.id, key2, key2 == "circle-opacity" || key2 == "circle-radius" || key2 == "circle-stroke-opacity" || key2 == "circle-stroke-width" || key2 == "text-opacity" ? Number(this.config[key][key2]) : this.config[key][key2] ); } } } } } } } class cesium_class extends CesiumEntity { type: any = "point"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; graphic: any = null; constructor(option: any) { super(hnMap); this.id = option.id; deepMerge(this.option, option); this.createPoint() } async createPoint() { this.config = this.formatConfig(this.option); // 创建 Cesium 实体 this.graphic = new Cesium.Entity(this.config); // 添加自定义属性 this.graphic.userData = { type: "point", originalData: this.option.data || {}, }; } formatConfig(option: any) { // const height = await super.getHeightByTerrain(option.position[0], option.position[1]) // 转换位置坐标为 Cesium 格式 const position = Cesium.Cartesian3.fromDegrees( Number(option.position[0]), Number(option.position[1]), Number(0) ); const config: any = { id: option.id, position: position, point: { pixelSize: Number(option.size) || 10, color: Cesium.Color.fromCssColorString(option.color).withAlpha( Number(option.opacity) || 1 ), outlineColor: Cesium.Color.fromCssColorString( option.outlineColor || "#ffffff" ).withAlpha(Number(option.outlineOpacity) || 1), outlineWidth: option.outline ? Number(option.outlineWidth) || 1 : 0, scaleByDistance: option.scaleByDistance ? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1) : undefined, show: true, clampToGround: !option.position[2], }, label: { text: option.text, font: `${option.fontWeight || "normal"} ${Number( option.fontSize )}px ${option.fontFamily || "sans-serif"}`, fillColor: Cesium.Color.fromCssColorString( option.fontColor ).withAlpha(Number(option.fontOpacity) || 1), style: Cesium.LabelStyle.FILL_AND_OUTLINE, outlineColor: Cesium.Color.fromCssColorString( option.textOutlineColor || "#ffffff" ).withAlpha(Number(option.textOutlineOpacity) || 1), outlineWidth: option.textOutline ? option.textOutlineWidth : 0, pixelOffset: new Cesium.Cartesian2( Number(option.fontOffset[0]) || 0, Number(option.fontOffset[1]) || 0 ), showBackground: !!option.textBackgroundColor, backgroundColor: option.textBackgroundColor ? Cesium.Color.fromCssColorString( option.textBackgroundColor ).withAlpha(Number(option.textBackgroundOpacity) || 1) : Cesium.Color.BLACK.withAlpha(0.5), show: true, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平居中 verticalOrigin: Cesium.VerticalOrigin.CENTER, // 垂直居中 clampToGround: !option.position[2], disableDepthTestDistance: Number.POSITIVE_INFINITY, // 禁用深度测试 heightReference: Cesium.HeightReference.NONE, // 高度参考 scaleByDistance: option.scaleByDistance ? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1) : undefined, }, properties: option.data || {}, // 添加自定义数据 }; // 添加距离显示条件 if (option.distanceDisplayCondition) { const near = getLevelMiddleHeight(option.distanceDisplayCondition_near); const far = getLevelMiddleHeight(option.distanceDisplayCondition_far); config.point.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); } return config; } // 设置方法 set(option: any) { deepMerge(this.option, option); // 更新实体 if (this.graphic) { // 更新位置 if (option.position !== undefined) { this.graphic.position = Cesium.Cartesian3.fromDegrees( Number(option.position[0]), Number(option.position[1]), Number(option.position[2]) || 0 ); } // 更新点属性 if (this.graphic.point) { const point = this.graphic.point; if (option.size !== undefined) { point.pixelSize = option.size; } if (option.color !== undefined || option.opacity !== undefined) { point.color = Cesium.Color.fromCssColorString( option.color ).withAlpha(Number(option.opacity)); } if (option.outline) { point.outlineWidth = option.outline ? option.outlineWidth : 0; point.outlineColor = Cesium.Color.fromCssColorString( option.outlineColor ).withAlpha(Number(option.outlineOpacity)); } else { point.outlineWidth = 0; } if (option.scaleByDistance) { point.scaleByDistance = new Cesium.NearFarScalar( 1.0e2, 1.0, 1.0e7, 0.1 ); } } // 更新标签属性 if (this.graphic.label) { const label = this.graphic.label; if (option.text !== undefined) { label.text = option.text; } label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER; label.verticalOrigin = Cesium.VerticalOrigin.CENTER; label.disableDepthTestDistance = Number.POSITIVE_INFINITY; label.heightReference = Cesium.HeightReference.NONE; if (option.fontSize !== undefined) { label.font = `${option.fontWeight || "normal"} ${ option.fontSize }px ${option.fontFamily || "sans-serif"}`; } if ( option.fontColor !== undefined || option.fontOpacity !== undefined ) { label.fillColor = Cesium.Color.fromCssColorString( option.fontColor ).withAlpha(Number(option.fontOpacity)); } if (option.textOutline) { label.outlineWidth = option.textOutlineWidth ? option.textOutlineWidth : 0; label.outlineColor = Cesium.Color.fromCssColorString( option.textOutlineColor ).withAlpha(Number(option.textOutlineOpacity)); } else { label.outlineWidth = 0; } if ( option.fontOffset[0] !== undefined || option.fontOffset[1] !== undefined ) { label.pixelOffset = new Cesium.Cartesian2( Number(option.fontOffset[0]) || 0, Number(option.fontOffset[1]) || 0 ); } if (option.textBackgroundColor !== undefined) { label.showBackground = !!option.textBackgroundColor; if (option.textBackgroundColor) { label.backgroundColor = Cesium.Color.fromCssColorString( option.textBackgroundColor ).withAlpha(Number(option.textBackgroundOpacity)); } } if (option.scaleByDistance) { label.scaleByDistance = new Cesium.NearFarScalar( 1.0e2, 1.0, 1.0e7, 0.1 ); } else { label.scaleByDistance = undefined; } } // 更新距离显示条件 if (option.distanceDisplayCondition) { const near = getLevelMiddleHeight( option.distanceDisplayCondition_near ); const far = getLevelMiddleHeight(option.distanceDisplayCondition_far); if (this.graphic.point) { this.graphic.point.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); } if (this.graphic.label) { this.graphic.label.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); } } else { if (this.graphic.point) { this.graphic.point.distanceDisplayCondition = undefined; } if (this.graphic.label) { this.graphic.label.distanceDisplayCondition = undefined; } } } } // 销毁方法 destroy() { if (this.graphic && hnMap.map.map && hnMap.map.map.entities) { hnMap.map.map.entities.remove(this.graphic); } } // 打开弹窗 openPopup(htmlContent: string) { if (this.graphic && hnMap.map) { this.graphic.description = htmlContent; hnMap.map.selectedEntity = this.graphic; } } } const fn: any = { mars3d: mars3d_class, gaode: gaode_class, siji: siji_class, cesium: cesium_class, }; return fn[hnMap.mapType]; };