import portEntityBillboardImage from "~/assets/images/map_bi/point/dianwei.png"; import branchOfficeEntityBillboardImage from "~/assets/images/map_bi/point/gongsidianwei.png"; import { BranchOfficePoint } from "~/pages/Container/Map/js/mock"; import edgeCMT from "./edge/cmt.js"; import edgeCSY from "./edge/csy.js"; import edgeCZKS from "./edge/czks.js"; import edgeQHD from "./edge/qhd.js"; import { addMergedEntityCollection, createEntityCollection, createId, getBillboard, getPosition, removeEntityCollection, } from "./mapUtils"; import mitt from "./mitt"; import { changeCoverMaskVisibleMittKey } from "./mittKey"; import { chunkedLoad, filterNull, formatPolygon } from "./utils"; import "./TrajectoryPolylineTrailLinkMaterialProperty.js"; import "./WallPolylineTrailLinkMaterialProperty"; const Cesium = window.Cesium; export default class MapMethods { #viewer; #defineCenterPoint = { longitude: 119.6486945226887, latitude: 39.93555616569192, height: 900000, }; // 默认中心点 #currentCenterPoint = { longitude: 119.6486945226887, latitude: 39.93555616569192, height: 900000, }; // 当前中心点 #previousCenterPoint = { longitude: 119.6486945226887, latitude: 39.93555616569192, height: 900000, }; // 上一次中心点 constructor(viewer) { this.#viewer = viewer; } // 设置中心点 flyTo = ({ longitude, latitude, height } = this.#defineCenterPoint) => { this.#viewer.camera.flyTo({ destination: getPosition(longitude, latitude, height), duration: 2 }); this.#previousCenterPoint = { ...this.#currentCenterPoint }; this.#currentCenterPoint = { longitude, latitude, height }; }; // 返回当前中心点 returnCurrentCenterPoint = () => { const { longitude, latitude, height } = this.#currentCenterPoint; this.#viewer.camera.flyTo({ destination: getPosition(longitude, latitude, height), duration: 2 }); }; // 返回上一次中心点 returnPreviousCenterPoint = () => { const { longitude, latitude, height } = this.#previousCenterPoint; this.#viewer.camera.flyTo({ destination: getPosition(longitude, latitude, height), duration: 2 }); this.#currentCenterPoint = { longitude, latitude, height }; }; // 切换场景模式 changeSceneMode = (type = "3d") => { this.#viewer.scene.mode = { "2d": Cesium.SceneMode.COLUMBUS_VIEW, "3d": Cesium.SceneMode.SCENE3D }[type]; }; // 添加港口点 addPortPoint = async () => { const portPoint = [ { id: "00002", name: "沧州黄骅港矿石港务有限公司", introduce: "公司现共有10个泊位(10-20万吨级),设计年通过能力6400万吨。堆场面积176万平米,堆存能力740万吨,大型装卸设备44台套。", position: { x: 117.91412, y: 38.35902 }, corpinfoId: "f8da1790b1034058ae2efefd69af3284", }, { id: "00003", name: "秦皇岛港", introduce: "秦皇岛港分为东、西两个港区,现有生产性泊位50个,年设计通过能力2.26亿吨,经营货类主要包括煤炭、金属矿石、油品及液体化工、集装箱及其他杂货等。", position: { x: 119.61254, y: 39.92572 }, }, { id: "00004", name: "曹妃甸实业港务", introduce: "公司现共有6个泊位(5-30万吨级),设计年通过能力6550万吨。堆场面积146万平米,堆存能力1350万吨,大型装卸设备23台套。", position: { x: 118.51022, y: 38.93503 }, corpinfoId: "8854edee3aa94be496cee676b6d4845a", }, { id: "00005", name: "曹妃甸煤炭港务", introduce: "公司现共有5个泊位(5-10万吨级),设计年通过能力5000万吨。堆场面积83万平米,堆存能力373.5万吨,大型装卸设备19台套。", position: { x: 118.43701, y: 38.9866 }, corpinfoId: "6aa255d41602497fa0f934a822820df4", }, ]; await chunkedLoad(portPoint, 10, async (item) => { const entityCollection = createEntityCollection("portEntityCollection"); entityCollection.entities.add( new Cesium.Entity({ id: item.id, name: item.name, position: getPosition(item.position.x, item.position.y), billboard: await getBillboard({ image: portEntityBillboardImage, name: item.name }), monitorItems: { data: { ...item, mapType: "港口" } }, }), ); this.#viewer.dataSources.add(entityCollection); }); await addMergedEntityCollection(this.#viewer, "portEntityCollection"); }; // 移除港口点 removePortPoint = () => { removeEntityCollection(this.#viewer, "portEntityCollectionMerged"); }; // 添加分公司点 addBranchOfficePoint = async (area = "", pointInfo = null) => { mitt.emit(changeCoverMaskVisibleMittKey, true); let branchOfficePoint = []; if (!pointInfo) { branchOfficePoint = filterNull(BranchOfficePoint); } else { branchOfficePoint = filterNull([pointInfo]); } await chunkedLoad(branchOfficePoint, 10, async (item) => { const entityCollection = createEntityCollection("branchOfficeEntityCollection"); entityCollection.entities.add( new Cesium.Entity({ id: item.corpinfoId, name: item.corpName, position: getPosition(item.longitude, item.latitude), billboard: await getBillboard({ image: branchOfficeEntityBillboardImage, name: item.corpName }), monitorItems: { data: { ...item, id: item.corpinfoId, mapType: "分公司" }, }, }), ); this.#viewer.dataSources.add(entityCollection); }); await addMergedEntityCollection(this.#viewer, "branchOfficeEntityCollection"); mitt.emit(changeCoverMaskVisibleMittKey, false); }; // 删除分公司点 removeBranchOfficePoint = () => { removeEntityCollection(this.#viewer, "branchOfficeEntityCollectionMerged"); }; // 添加四色图 addFourColorDiagram = (id, corpionId) => { const edgeMap = { "00003": edgeQHD, "00002": edgeCZKS, "00005": edgeCMT, "00004": edgeCSY, }; if (!edgeMap[id]) return; mitt.emit(changeCoverMaskVisibleMittKey, true); const currentEdge = edgeMap[id](); const entityCollection = createEntityCollection( "fourColorDiagramEntityCollection", ); // 先收集需要渲染的数据 const itemsToRender = []; for (const currentEdgeKey in currentEdge) { const currentEdgeItem = currentEdge[currentEdgeKey]; if (currentEdgeKey === "wallList") continue; for (let i = 0; i < currentEdgeItem.length; i++) { const item = currentEdgeItem[i]; // 如果有 corpionId,则只添加匹配的;否则全部添加 if (!corpionId || item.corpinfoId === corpionId) { itemsToRender.push(item); } if (!item.corpinfoId) { itemsToRender.push(item); } } } // 统一渲染 itemsToRender.forEach((item) => { const latitudeAndLongitude = formatPolygon(item); entityCollection.entities.add( new Cesium.Entity({ id: createId(), polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray(latitudeAndLongitude), extrudedHeight: item.stretchHeight, height: item.height, material: Cesium.Color.fromCssColorString(item.color), outline: !!item.strokeColor, outlineColor: Cesium.Color.fromCssColorString(item.strokeColor), }, }), ); }); this.#viewer.dataSources.add(entityCollection); mitt.emit(changeCoverMaskVisibleMittKey, false); }; // 删除四色图 removeFourColorDiagram = () => { removeEntityCollection(this.#viewer, "fourColorDiagramEntityCollection"); }; // 添加墙 addWall = (id, corpionId) => { const edgeMap = { "00003": edgeQHD, "00002": edgeCZKS, "00005": edgeCMT, "00004": edgeCSY, }; if (!edgeMap[id]) return; mitt.emit(changeCoverMaskVisibleMittKey, true); const currentEdge = edgeMap[id](); const entityCollection = createEntityCollection("wallEntityCollection"); const wallList = currentEdge.wallList; if (!Array.isArray(wallList)) return; // 筛选需要渲染的边界墙 const itemsToRender = wallList.filter(item => !corpionId || item.corpinfoId === corpionId); // 统一渲染 itemsToRender.forEach((item) => { const latitudeAndLongitude = formatPolygon(item); const positions = Cesium.Cartesian3.fromDegreesArray(latitudeAndLongitude); const pointCount = latitudeAndLongitude.length / 2; entityCollection.entities.add( new Cesium.Entity({ id: createId(), wall: { positions, material: new Cesium.WallPolylineTrailLinkMaterialProperty(this.#viewer), maximumHeights: Array.from({ length: pointCount }).fill(40), minimumHeights: Array.from({ length: pointCount }).fill(0), }, }), ); }); this.#viewer.dataSources.add(entityCollection); mitt.emit(changeCoverMaskVisibleMittKey, false); }; // 删除墙 removeWall = () => { removeEntityCollection(this.#viewer, "wallEntityCollection"); }; /** * desc: 添加点位 * @param {Array} pointList * @param options {Object: {mapIcon, type, subLabel}} 配置项 * @param options.mapIcon {String} 扎点图标 * @param options.mapType {String} 扎点类型 * @param options.subLabel {String} 二级标题(用于弹窗标题) */ addMarkPoint = async (pointList, options) => { if (!options.mapType) throw new Error("请传入mapType(扎点类型)"); if (!options.mapIcon) throw new Error("请传入mapIcon(扎点图标)"); mitt.emit(changeCoverMaskVisibleMittKey, true); await chunkedLoad(pointList, 10, async (item) => { const entityCollection = createEntityCollection( `markEntityCollection_${options.mapType}`, ); const name = item.MAP_POINT_NAME || item.AREA_NAME || ""; entityCollection.entities.add( new Cesium.Entity({ id: createId(), name, position: getPosition(item.LONGITUDE, item.LATITUDE), billboard: await getBillboard({ image: options.mapIcon, name }), monitorItems: { data: { ...item, mapType: `标记点_${options.mapType}`, subLabel: options.subLabel }, }, }), ); this.#viewer.dataSources.add(entityCollection); }); const dataSource = await addMergedEntityCollection( this.#viewer, "markEntityCollection", options.mapType, ); this.#enabledClustering(dataSource); mitt.emit(changeCoverMaskVisibleMittKey, false); }; // 删除点位 removeMarkPoint = (mapType) => { removeEntityCollection(this.#viewer, `markEntityCollectionMerged${mapType ? `_${mapType}` : ""}`); }; // 点位聚合 #enabledClustering = (dataSource) => { dataSource.clustering.enabled = true; // 聚合开启 dataSource.clustering.pixelRange = 50; // 设置像素范围,以扩展显示边框 dataSource.clustering.minimumClusterSize = 5; // 设置最小的聚合点数目,超过此数目才能聚合 let removeListener; // 按聚合层级创建对应图标 const pinBuilder = new Cesium.PinBuilder(); const pin100 = pinBuilder .fromText("100+", Cesium.Color.BLUE, 48) .toDataURL(); const pin50 = pinBuilder.fromText("50+", Cesium.Color.BLUE, 48).toDataURL(); const pin40 = pinBuilder.fromText("40+", Cesium.Color.RED, 48).toDataURL(); const pin30 = pinBuilder.fromText("30+", Cesium.Color.RED, 48).toDataURL(); const pin20 = pinBuilder.fromText("20+", Cesium.Color.RED, 48).toDataURL(); const pin10 = pinBuilder.fromText("10+", Cesium.Color.RED, 48).toDataURL(); // 10以内聚合图标 const singleDigitPins = Array.from({ length: 8 }); for (let i = 0; i < singleDigitPins.length; ++i) { singleDigitPins[i] = pinBuilder .fromText(`${i + 2}`, Cesium.Color.VIOLET, 48) .toDataURL(); } customStyle(); function customStyle() { if (Cesium.defined(removeListener)) { removeListener(); removeListener = undefined; } else { removeListener = dataSource.clustering.clusterEvent.addEventListener( (clusteredEntities, cluster) => { cluster.label.show = false; cluster.billboard.show = true; cluster.billboard.id = cluster.label.id; cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; cluster.billboard.horizontalOrigin = Cesium.HorizontalOrigin.CENTER; cluster.billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND; cluster.billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY; const thresholdMap = [ { threshold: 100, image: pin100 }, { threshold: 50, image: pin50 }, { threshold: 40, image: pin40 }, { threshold: 30, image: pin30 }, { threshold: 20, image: pin20 }, { threshold: 10, image: pin10 }, ]; const matched = thresholdMap.find( ({ threshold }) => clusteredEntities.length >= threshold, ); cluster.billboard.image = matched ? matched.image : singleDigitPins[clusteredEntities.length - 2]; }, ); } const pixelRange = dataSource.clustering.pixelRange; dataSource.clustering.pixelRange = 0; dataSource.clustering.pixelRange = pixelRange; } }; }