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"; const HorizontalOrigin: any = { center: 0, left: 1, right: -1, }; const VerticalOrigin: any = { center: 0, top: -1, bottom: 1, }; export default (hnMap: any) => { const defaultOption = { id: "", position: [], image: "", height: 30, width: 30, rotation: 0, horizontalOrigin: "center", verticalOrigin: "center", text: "", fontSize: 12, color: "#000000", offset: [0, 0], scaleByDistance: true, distanceDisplayCondition: false, distanceDisplayCondition_far: 1, distanceDisplayCondition_near: 18, data: null, }; class mars3d_class extends Mars3dEntity { 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.BillboardEntity(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: { width: option.width, height: option.height, image: option.image, label: { text: option.text, font_size: option.fontSize, color: option.color, pixelOffset: option.offset, scaleByDistance: option.scaleByDistance, distanceDisplayCondition: option.distanceDisplayCondition, distanceDisplayCondition_far: distanceDisplayCondition_far, distanceDisplayCondition_near: distanceDisplayCondition_near, visibleDepth: false, }, scaleByDistance: option.scaleByDistance, distanceDisplayCondition: option.distanceDisplayCondition, distanceDisplayCondition_far: option.distanceDisplayCondition_far, distanceDisplayCondition_near: option.distanceDisplayCondition_near, clampToGround: !option.position[2], rotationDegree: option.rotation, horizontalOrigin: HorizontalOrigin[option.horizontalOrigin], verticalOrigin: VerticalOrigin[option.verticalOrigin], visibleDepth: true, }, attr: option.data, }; } set(option: any) { deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.graphic.setOptions(this.config); } // flyTo(option = {}) { // let config = {} // if(option.height){ // config.radius = option.height // } // // this.graphic.flyTo(config); // } openPopup() { this.graphic.openPopup(); } } class gaode_class extends GaodeEntity { type: any = "imagePoint"; 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.Marker(this.config); } formatConfig(option: any) { let amapPosition = wgs84ToGcj02Format(option.position); const content = `
${option.text}
`; return { extData: { id: option.id, data: option.data, }, position: new AMap.LngLat(amapPosition[0], amapPosition[1]), icon: new AMap.Icon({ image: option.image, imageSize: new AMap.Size(option.height, option.width), size: new AMap.Size(option.height, option.width), }), angle: 360 - option.rotation, anchor: "center", label: { direction: "center", offset: new AMap.Pixel(option.offset[0], option.offset[1]), //设置文本标注偏移量 content: content, }, }; } } class siji_class extends SijiEntity { type: any = "imagePoint"; 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); } formatConfig(option: any) { let config: any = {}; config = { id: option.id, type: "symbol", source: { type: "geojson", data: { type: "FeatureCollection", features: [ { type: "Feature", geometry: { type: "Point", coordinates: convertPosition(option.position), }, properties: { name: option.text, }, }, ], }, }, layout: { "icon-image": option.id + "_image", // "icon-size": 1, "icon-ignore-placement": true, // "icon-offset": convertPosition(option.offset), "text-ignore-placement": true, // "text-field": "{name}", // 文本 "text-size": Number(option.fontSize), "text-anchor": option.verticalOrigin, "icon-anchor": option.verticalOrigin, "text-offset": convertPosition(option.offset), }, paint: { "text-color": option.color, }, // 填充样式 }; return config; } 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", geometry: { type: "Point", coordinates: convertPosition(this.option.position), }, properties: { name: this.option.text, }, }, ], }); for (let key in this.config) { if (this.config.hasOwnProperty(key)) { if (key == "layout") { for (let key2 in this.config[key]) { if (this.config[key].hasOwnProperty(key2)) { // 遍历 layout 属性 hnMap.map.map.setLayoutProperty( this.config.id, key2, key2 == "text-size" ? Number(this.config[key][key2]) : this.config[key][key2] ); } } } } } 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, this.config[key][key2] ); } } } } } } } class cesium_class extends CesiumEntity { type: any = "imagePoint"; 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); // 创建cesium实体 this.graphic = new Cesium.Entity(this.config); // 添加自定义属性 this.graphic.userData = { type: "billboard", originalData: this.option.data || {}, }; } formatConfig(option: any) { // 转换位置坐标为 Cesium 格式 const position = Cesium.Cartesian3.fromDegrees( Number(option.position[0]), Number(option.position[1]), Number(option.position[2]) || 0 ); // 映射水平和垂直原点 const horizontalOriginMap: any = { left: Cesium.HorizontalOrigin.LEFT, center: Cesium.HorizontalOrigin.CENTER, right: Cesium.HorizontalOrigin.RIGHT, }; const verticalOriginMap: any = { top: Cesium.VerticalOrigin.TOP, center: Cesium.VerticalOrigin.CENTER, bottom: Cesium.VerticalOrigin.BOTTOM, }; const config: any = { id: option.id, position: position, billboard: { image: option.image, width: Number(option.width), height: Number(option.height), horizontalOrigin: horizontalOriginMap[option.horizontalOrigin], verticalOrigin: verticalOriginMap[option.verticalOrigin], pixelOffset: new Cesium.Cartesian2( Number(option.offset[0]) || 0, Number(option.offset[1]) || 0 ), rotation: Cesium.Math.toRadians(option.rotation || 0), clampToGround: !option.position[2], scaleByDistance: option.scaleByDistance ? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1) : undefined, show: true, visibleDepth: true, }, label: { text: option.text, font: `${option.fontSize || 16}px sans-serif`, fillColor: Cesium.Color.fromCssColorString(option.color || "#000000"), style: Cesium.LabelStyle.FILL_AND_OUTLINE, // horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // verticalOrigin: Cesium.VerticalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2( Number(option.offset[0]) || 0, -Number(option.offset[1]) || 0 ), scaleByDistance: option.scaleByDistance ? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1) : undefined, disableDepthTestDistance: Number.POSITIVE_INFINITY, heightReference: Cesium.HeightReference.NONE, // 高度参考 show: true, visibleDepth: true, }, properties: option.data || {}, // 添加自定义数据 }; // 添加距离显示条件 if (option.distanceDisplayCondition) { const near = getLevelMiddleHeight(option.distanceDisplayCondition_near); const far = getLevelMiddleHeight(option.distanceDisplayCondition_far); config.label.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); config.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); } return config; } // 添加 set 方法用于动态更新 set(option: any) { deepMerge(this.option, option); this.config = this.formatConfig(this.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 ); } // 更新 billboard 属性 if (this.graphic.billboard) { const billboard = this.graphic.billboard; if (option.image !== undefined) { billboard.image = option.image; } if (option.width !== undefined) { billboard.width = Number(option.width); } if (option.height !== undefined) { billboard.height = Number(option.height); } if (option.rotation !== undefined) { billboard.rotation = Cesium.Math.toRadians(option.rotation); } // if (option.offset !== undefined) { // billboard.pixelOffset = new Cesium.Cartesian2( // Number(option.offset[0]) || 0, // Number(option.offset[1]) || 0 // ); // } // 更新原点 if (option.horizontalOrigin !== undefined) { const horizontalOriginMap: any = { left: Cesium.HorizontalOrigin.LEFT, center: Cesium.HorizontalOrigin.CENTER, right: Cesium.HorizontalOrigin.RIGHT, }; billboard.horizontalOrigin = horizontalOriginMap[option.horizontalOrigin] || Cesium.HorizontalOrigin.CENTER; } if (option.verticalOrigin !== undefined) { const verticalOriginMap: any = { top: Cesium.VerticalOrigin.TOP, center: Cesium.VerticalOrigin.CENTER, bottom: Cesium.VerticalOrigin.BOTTOM, }; billboard.verticalOrigin = verticalOriginMap[option.verticalOrigin] || Cesium.VerticalOrigin.CENTER; } if (option.scaleByDistance) { billboard.scaleByDistance = new Cesium.NearFarScalar( 1.0e2, 1.0, 1.0e7, 0.1 ); } else { billboard.scaleByDistance = undefined; } } // 更新 label 属性 if (this.graphic.label) { const label = this.graphic.label; label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER; label.verticalOrigin = Cesium.VerticalOrigin.CENTER; label.disableDepthTestDistance = Number.POSITIVE_INFINITY; label.heightReference = Cesium.HeightReference.NONE; if (option.text !== undefined) { label.text = String(option.text); } if (option.fontSize !== undefined || option.color !== undefined) { label.font = `${option.fontSize || 12}px sans-serif`; label.fillColor = Cesium.Color.fromCssColorString( option.color || "#000000" ); } if (option.offset !== undefined) { label.pixelOffset = new Cesium.Cartesian2( Number(option.offset[0]) || 0, -Number(option.offset[1]) || 0 ); } if (option.scaleByDistance) { label.scaleByDistance = new Cesium.NearFarScalar( 1.0e2, 1.0, 1.0e7, 0.1 ); } else { label.scaleByDistance = undefined; } } // 更新距离显示条件 if(option.distanceDisplayCondition!==undefined){ if (option.distanceDisplayCondition) { const near = getLevelMiddleHeight( option.distanceDisplayCondition_near ); const far = getLevelMiddleHeight(option.distanceDisplayCondition_far); if (this.graphic.billboard) { this.graphic.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); } if (this.graphic.label) { this.graphic.label.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(near, far); } } else { if (this.graphic.billboard) { this.graphic.billboard.distanceDisplayCondition = false; } if (this.graphic.label) { this.graphic.label.distanceDisplayCondition = false; } } } } } // 销毁方法 destroy() { if (this.graphic && hnMap.map.map && hnMap.map.map.entities) { hnMap.map.map.entities.remove(this.graphic); } } } const fn: any = { mars3d: mars3d_class, gaode: gaode_class, siji: siji_class, cesium: cesium_class, }; return fn[hnMap.mapType]; };