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: "#ff0000", opacity: 1, outline: false, outlineWidth: 2, outlineColor: "#ffffff", outlineOpacity: 1, scaleByDistance: true, distanceDisplayCondition: false, distanceDisplayCondition_far: 1, distanceDisplayCondition_near: 18, data: null, }; class mars3d_class extends Mars3dEntity { type: any = "polygon"; 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.PolygonEntity(this.config); } formatConfig(option: any) { const distanceDisplayCondition_far = getLevelMiddleHeight( option.distanceDisplayCondition_far ); const distanceDisplayCondition_near = getLevelMiddleHeight( option.distanceDisplayCondition_near ); return { id: option.id, positions: option.position, style: { color: option.color, opacity: option.opacity, outline: option.outline, outlineColor: option.outlineColor, outlineWidth: option.outlineWidth, outlineOpacity: option.outlineOpacity, scaleByDistance: option.scaleByDistance, distanceDisplayCondition: option.distanceDisplayCondition, distanceDisplayCondition_far: distanceDisplayCondition_far, distanceDisplayCondition_near: distanceDisplayCondition_near, clampToGround: !(option.position[0] && option.position[0][2]), }, 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.Polygon(this.config); } formatConfig(option: any) { const amapPosition = wgs84ToGcj02Format(option.position); return { path: amapPosition, fillColor: option.color, fillOpacity: option.opacity, strokeColor: option.outlineColor, strokeOpacity: option.outline ? option.outlineOpacity : 0, strokeWeight: option.outline ? option.outlineWidth : 0, 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.setPath(this.config.path); } } class siji_class extends SijiEntity { type: any = "polygon"; 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 = { id: option.id, type: "fill", source: { type: "geojson", data: { type: "FeatureCollection", features: [ { type: "Feature", geometry: { type: "Polygon", coordinates: convertPosition(option.position), }, }, ], }, }, paint: { "fill-color": option.color, // 填充颜色覆盖drawColor设置的颜色,呈现绿色 "fill-opacity": Number(option.opacity), "fill-antialias": true, "fill-outline-color": option.outlineColor, }, }; 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: "Polygon", coordinates: convertPosition(this.option.position), //三层数组[[[0,0],[0,0]]] }, }, ], }); 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 = "polygon"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; graphic: any = null; polygonEntity: any = null; outlineEntity: any = null; // 新增:用于绘制宽边框的实体 show: boolean = true; constructor(option: any) { super(hnMap); this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.graphic = this.createPolygonEntity(); } // 标准化坐标数组,处理不同层级的嵌套结构 normalizePositions(positions: any[]): any[] { // 递归函数,找到最内层的坐标数组 const findInnermostArray = (arr: any[]): any[] => { if (Array.isArray(arr) && arr.length > 0 && Array.isArray(arr[0])) { // 检查是否是坐标点 [x, y] 或 [x, y, z] if ( (arr[0].length >= 2 && typeof arr[0][0] === "number") || typeof arr[0][0] === "string" ) { // 这已经是坐标点的数组,直接返回 return arr; } else { // 继续深入下一层 return findInnermostArray(arr[0]); } } // 如果不是嵌套数组,返回原数组 return arr; }; return findInnermostArray(positions); } formatConfig(option: any) { // 标准化位置坐标数组 const normalizedPositions = this.normalizePositions(option.position); // 转换位置坐标为 Cesium 格式 const positions = normalizedPositions.map((pos: any) => { if (Array.isArray(pos) && pos.length >= 2) { const height = pos.length >= 3 ? pos[2] : 0; return Cesium.Cartesian3.fromDegrees(pos[0], pos[1], height); } return pos; }); // 根据是否贴地设置高度 let height = 0; let perPositionHeight = false; let clampToGround = false; // 检查是否有高度信息 if (normalizedPositions[0] && normalizedPositions[0].length === 3) { perPositionHeight = true; } else { clampToGround = !(normalizedPositions[0] && normalizedPositions[0][2]); } // 处理距离显示条件 let distanceDisplayCondition = undefined; if (option.distanceDisplayCondition) { const distanceDisplayCondition_far = getLevelMiddleHeight( option.distanceDisplayCondition_far ); const distanceDisplayCondition_near = getLevelMiddleHeight( option.distanceDisplayCondition_near ); distanceDisplayCondition = new Cesium.DistanceDisplayCondition( distanceDisplayCondition_near, distanceDisplayCondition_far ); } // 创建多边形层级 const polygonHierarchy = new Cesium.PolygonHierarchy(positions); // 创建边框宽度控制 const outlineWidth = Number(option.outlineWidth); const useOutline = option.outline && outlineWidth > 0; return { id: option.id, polygon: { hierarchy: polygonHierarchy, material: Cesium.Color.fromCssColorString(option.color).withAlpha( Number(option.opacity) ), // 对于 <= 1px 的边框,使用原生边框 outline: useOutline && outlineWidth <= 1, outlineColor: useOutline && outlineWidth <= 1 ? Cesium.Color.fromCssColorString(option.outlineColor).withAlpha( Number(option.outlineOpacity) ) : Cesium.Color.TRANSPARENT, outlineWidth: 1, // Cesium 原生只支持 1px height: height, perPositionHeight: perPositionHeight, clampToGround: !(normalizedPositions[0] && normalizedPositions[0][2]), distanceDisplayCondition: distanceDisplayCondition, classificationType: Cesium.ClassificationType.BOTH, // scaleByDistance: option.scaleByDistance // ? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1) // : undefined, }, properties: option.data || {}, }; } // 将经纬度数组转换为 Cesium Cartesian3 数组 convertPositions(positions: any[]) { // 标准化位置坐标数组 const normalizedPositions = this.normalizePositions(positions); return normalizedPositions.map((pos) => { if (pos.length === 2) { return Cesium.Cartesian3.fromDegrees(pos[0], pos[1], 0); } else if (pos.length === 3) { return Cesium.Cartesian3.fromDegrees(pos[0], pos[1], pos[2]); } throw new Error("Invalid position format"); }); } createPolygonEntity() { this.polygonEntity = new Cesium.Entity(this.config); this.polygonEntity.customData = this.option.data; // 如果需要宽边框(>1px),创建额外的 Polyline 实体来模拟边框 const outlineWidth = Number(this.option.outlineWidth); if (this.option.outline && outlineWidth > 1) { this.createOutlineEntity(); } return this.polygonEntity; } // 创建边框实体(用于宽边框) createOutlineEntity() { if (!this.option.outline) { return; } const outlineWidth = Number(this.option.outlineWidth); if (outlineWidth <= 0) { return; } const positions = this.convertPositions(this.option.position); // 闭合多边形(将第一个点添加到末尾) const closedPositions = [...positions, positions[0]]; // 创建 Polyline 作为边框 this.outlineEntity = new Cesium.Entity({ polyline: { positions: closedPositions, width: outlineWidth, material: new Cesium.ColorMaterialProperty( Cesium.Color.fromCssColorString(this.option.outlineColor).withAlpha( Number(this.option.outlineOpacity) ) ), clampToGround: this.option.position[0] && !this.option.position[0][2], classificationType: Cesium.ClassificationType.BOTH, // 继承相同的距离显示条件 distanceDisplayCondition: this.polygonEntity.polygon.distanceDisplayCondition, }, id: `${this.id}_outline`, }); } set(option: any) { deepMerge(this.option, option); // 更新多边形实体 if (this.polygonEntity) { // 更新位置 const positions = this.convertPositions(this.option.position); const polygonHierarchy = new Cesium.PolygonHierarchy(positions); this.polygonEntity.polygon.hierarchy = polygonHierarchy; // 更新填充颜色 this.polygonEntity.polygon.material = new Cesium.ColorMaterialProperty( Cesium.Color.fromCssColorString(this.option.color).withAlpha( Number(this.option.opacity) ) ); // 处理边框逻辑 const outlineWidth = Number(this.option.outlineWidth); const useOutline = this.option.outline && outlineWidth > 0; if (useOutline) { if (outlineWidth <= 1) { // 使用 Cesium 原生的边框(1px) this.polygonEntity.polygon.outline = true; this.polygonEntity.polygon.outlineColor = Cesium.Color.fromCssColorString( this.option.outlineColor ).withAlpha(Number(this.option.outlineOpacity)); this.polygonEntity.polygon.outlineWidth = 1; // 移除自定义边框实体(如果有) if (this.outlineEntity) { if (hnMap.map.map && hnMap.map.map.entities) { hnMap.map.map.entities.remove(this.outlineEntity); } this.outlineEntity = null; } } else { // 使用自定义 Polyline 边框(>1px) this.polygonEntity.polygon.outline = false; // 创建或更新自定义边框实体 if (!this.outlineEntity) { this.createOutlineEntity(); hnMap.map.map.entities.add(this.outlineEntity); } else { // 更新自定义边框 const positions = this.convertPositions(this.option.position); const closedPositions = [...positions, positions[0]]; this.outlineEntity.polyline.positions = closedPositions; this.outlineEntity.polyline.width = outlineWidth; this.outlineEntity.polyline.material = new Cesium.ColorMaterialProperty( Cesium.Color.fromCssColorString( this.option.outlineColor ).withAlpha(Number(this.option.outlineOpacity)) ); } } } else { // 不显示边框 this.polygonEntity.polygon.outline = false; // 移除自定义边框实体(如果有) if (this.outlineEntity) { if (hnMap.map.map && hnMap.map.map.entities) { hnMap.map.map.entities.remove(this.outlineEntity); } this.outlineEntity = null; } } // 更新高度设置 let height = 0; let perPositionHeight = false; let clampToGround = false; const normalizedPosition = this.normalizePositions( this.option.position ); if (normalizedPosition[0] && normalizedPosition[0].length === 3) { perPositionHeight = true; } else { clampToGround = normalizedPosition[0] && !normalizedPosition[0][2]; } this.polygonEntity.polygon.height = height; this.polygonEntity.polygon.perPositionHeight = new Cesium.ConstantProperty(perPositionHeight); this.polygonEntity.polygon.clampToGround = clampToGround; // 更新距离显示条件 if (this.option.distanceDisplayCondition) { const distanceDisplayCondition_far = getLevelMiddleHeight( this.option.distanceDisplayCondition_far ); const distanceDisplayCondition_near = getLevelMiddleHeight( this.option.distanceDisplayCondition_near ); if ( distanceDisplayCondition_near !== undefined && distanceDisplayCondition_far !== undefined ) { this.polygonEntity.polygon.distanceDisplayCondition = new Cesium.DistanceDisplayCondition( distanceDisplayCondition_near, distanceDisplayCondition_far ); // 同步到边框实体 if (this.outlineEntity) { this.outlineEntity.polyline.distanceDisplayCondition = new Cesium.DistanceDisplayCondition( distanceDisplayCondition_near, distanceDisplayCondition_far ); } } else { this.polygonEntity.polygon.distanceDisplayCondition = undefined; if (this.outlineEntity) { this.outlineEntity.polyline.distanceDisplayCondition = undefined; } } } else { this.polygonEntity.polygon.distanceDisplayCondition = undefined; if (this.outlineEntity) { this.outlineEntity.polyline.distanceDisplayCondition = undefined; } } // 更新自定义数据 this.polygonEntity.customData = this.option.data; } } // 销毁多边形 destroy() { if (this.outlineEntity && hnMap.map.map && hnMap.map.map.entities) { hnMap.map.map.entities.remove(this.outlineEntity); } if (this.polygonEntity && hnMap.map.map && hnMap.map.map.entities) { hnMap.map.map.entities.remove(this.polygonEntity); } this.polygonEntity = null; this.outlineEntity = null; this.graphic = null; super.destroy() } } const fn: any = { mars3d: mars3d_class, gaode: gaode_class, siji: siji_class, cesium: cesium_class, }; return fn[hnMap.mapType]; };