hn-map 1.1.15 → 1.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,8 +28,6 @@ export default (hnMap: any) => {
28
28
  }
29
29
 
30
30
  addEntity(entity: any) {
31
-
32
-
33
31
  if (this.children.find((v: any) => v.id === entity.id)) {
34
32
  console.error("已存在同名图形" + entity.id);
35
33
  } else {
@@ -48,6 +46,7 @@ export default (hnMap: any) => {
48
46
  if (entity.option.position && entity.option.position.length > 0) {
49
47
  setTimeout(() => {
50
48
  entity.setPosition(entity.option.position);
49
+ entity.flyTo();
51
50
  }, 100);
52
51
  }
53
52
  } else {
@@ -190,7 +189,6 @@ export default (hnMap: any) => {
190
189
  if (this.children.find((v: any) => v.id === entity.id)) {
191
190
  console.error("已存在同名图形" + entity.id);
192
191
  } else {
193
- alert(entity.id);
194
192
  this.children.push(entity);
195
193
  this.layerEntity.addOverlay(entity.graphic); // 添加图形
196
194
 
@@ -535,10 +533,186 @@ export default (hnMap: any) => {
535
533
  }
536
534
  }
537
535
 
536
+ class cesium_class {
537
+ type: any = "layer";
538
+ id: any = null;
539
+ option: any = JSON.parse(JSON.stringify(defaultOption));
540
+ config: any = null;
541
+ children: any = null;
542
+ layerEntity: any = null;
543
+ show: boolean = true;
544
+ constructor(option: any) {
545
+ this.id = option.id;
546
+ this.children = [];
547
+ deepMerge(this.option, option);
548
+ this.config = this.formatConfig(this.option);
549
+
550
+ // 创建数据源
551
+ this.layerEntity = new Cesium.CustomDataSource(this.id);
552
+ this.layerEntity.show = this.show;
553
+
554
+ // 添加到地图
555
+ hnMap.map.dataSources.add(this.layerEntity);
556
+ }
557
+ formatConfig(option: any) {
558
+ return option;
559
+ }
560
+ // 添加图形
561
+ addEntity(entity: any) {
562
+ if (this.children.find((v: any) => v.id === entity.id)) {
563
+ console.error(`已存在同名图形: ${entity.id}`);
564
+ return;
565
+ }
566
+
567
+ this.children.push(entity);
568
+
569
+ // 根据图形类型处理
570
+ if (entity.graphic) {
571
+ if (entity.type === "cluster") {
572
+ // 集群特殊处理
573
+ this.handleCluster(entity);
574
+ } else if (entity.type === "pointCloud") {
575
+ // 点云特殊处理
576
+ this.handlePointCloud(entity);
577
+ } else if (entity.type === "heatMap") {
578
+ // 热力图特殊处理
579
+ this.handleHeatMap(entity);
580
+ } else {
581
+ // 普通实体
582
+ this.layerEntity.entities.add(entity.graphic);
583
+ }
584
+ }
585
+ }
586
+
587
+ // 处理集群
588
+ handleCluster(entity: any) {
589
+ // 集群有自己的管理逻辑
590
+ entity.layer = this;
591
+ // 集群会自己管理添加到地图
592
+ }
593
+
594
+ // 处理点云
595
+ handlePointCloud(entity: any) {
596
+ // 点云有自己的图层管理
597
+ if (entity.layerEntity) {
598
+ hnMap.map.scene.primitives.add(entity.layerEntity);
599
+ }
600
+ }
601
+
602
+ // 处理热力图
603
+ handleHeatMap(entity: any) {
604
+ // 热力图有自己的图层管理
605
+ if (entity.layerEntity) {
606
+ hnMap.map.scene.primitives.add(entity.layerEntity);
607
+ }
608
+ }
609
+
610
+ // 移除图形
611
+ removeEntity(entityParam: string) {
612
+ const entity = this.getEntity(entityParam);
613
+ if (entity) {
614
+ this.children = this.children.filter((v: any) => v.id !== entity.id);
615
+
616
+ if (entity.graphic) {
617
+ if (entity.type === "cluster") {
618
+ entity.destroy();
619
+ } else if (
620
+ entity.type === "pointCloud" ||
621
+ entity.type === "heatMap"
622
+ ) {
623
+ if (entity.layerEntity) {
624
+ hnMap.map.scene.primitives.remove(entity.layerEntity);
625
+ }
626
+ } else {
627
+ this.layerEntity.entities.remove(entity.graphic);
628
+ }
629
+ }
630
+
631
+ if (entity.destroy) {
632
+ entity.destroy();
633
+ }
634
+ }
635
+ }
636
+
637
+ // 获取图形
638
+ getEntity(entityId: string) {
639
+ return this.children.find((v: any) => v.id === entityId);
640
+ }
641
+
642
+ // 清除所有图形
643
+ clearEntity() {
644
+ this.children.forEach((entity: any) => {
645
+ if (entity.destroy) entity.destroy();
646
+ if (entity.graphic) {
647
+ this.layerEntity.entities.remove(entity.graphic);
648
+ }
649
+ });
650
+ this.children = [];
651
+ }
652
+
653
+ // 销毁图层
654
+ destroy() {
655
+ this.clearEntity();
656
+ hnMap.map.dataSources.remove(this.layerEntity);
657
+
658
+ // 从图层列表中移除
659
+ const index = hnMap.map.layerList.findIndex((v: any) => v.id === this.id);
660
+ if (index > -1) {
661
+ hnMap.map.layerList.splice(index, 1);
662
+ }
663
+ }
664
+
665
+ // 飞向图层
666
+ flyTo() {
667
+ if (this.children.length > 0) {
668
+ // 计算所有实体的边界
669
+ const positions: any[] = [];
670
+ this.children.forEach((entity: any) => {
671
+ if (entity.option.position) {
672
+ positions.push(entity.option.position);
673
+ } else if (entity.option.positions) {
674
+ positions.push(...entity.option.positions);
675
+ }
676
+ });
677
+
678
+ if (positions.length > 0) {
679
+ // 飞向边界
680
+ const cartesians = positions.map((pos) =>
681
+ Cesium.Cartesian3.fromDegrees(pos[0], pos[1], pos[2] || 0)
682
+ );
683
+ const boundingSphere = Cesium.BoundingSphere.fromPoints(cartesians);
684
+
685
+ hnMap.map.flyToBoundingSphere(boundingSphere, {
686
+ duration: 2,
687
+ offset: new Cesium.HeadingPitchRange(0, -Cesium.Math.PI / 4, 0),
688
+ });
689
+ }
690
+ }
691
+ }
692
+
693
+ // 添加属性弹窗
694
+ addPopupByAttr() {
695
+ this.children.forEach((entity: any) => {
696
+ if (entity.addPopupByAttr) {
697
+ entity.addPopupByAttr();
698
+ }
699
+ });
700
+ }
701
+
702
+ // 添加自定义弹窗
703
+ addCustomPopup(getCustomDom: Function) {
704
+ this.children.forEach((entity: any) => {
705
+ if (entity.addCustomPopup) {
706
+ entity.addCustomPopup(getCustomDom);
707
+ }
708
+ });
709
+ }
710
+ }
538
711
  const fn: any = {
539
712
  mars3d: mars3d_class,
540
713
  gaode: gaode_class,
541
714
  siji: siji_class,
715
+ cesium: cesium_class,
542
716
  };
543
717
 
544
718
  return fn[hnMap.mapType];
package/src/map.ts CHANGED
@@ -22,6 +22,12 @@ export default (hnMap: any) => {
22
22
  sj_app_secret: "",
23
23
  sj_style: "aegis://styles/aegis/Streets-Raster512",
24
24
  sj_route_net: true,
25
+ // Cesium配置
26
+ cesium_accessToken: "",
27
+ cesium_baseUrl: "",
28
+ cesium_terrainProvider: null,
29
+ cesium_imageryProvider: null,
30
+ cesium_options: {},
25
31
  };
26
32
 
27
33
  class mars3d_map {
@@ -459,10 +465,405 @@ export default (hnMap: any) => {
459
465
  }
460
466
  }
461
467
 
468
+ class cesium_map {
469
+ map: any = null;
470
+ option: any = JSON.parse(JSON.stringify(defaultOption));
471
+ config: any = null;
472
+ layerList: any = [];
473
+ event: any = {};
474
+ level: any = null;
475
+ // 数据源集合
476
+ dataSources: any = new Cesium.CustomDataSource("hnMap_dataSources");
477
+ private constructor(id: any, option: any) {
478
+ this.layerList = [];
479
+ this.level = 10;
480
+ deepMerge(this.option, option);
481
+ this.config = this.formatConfig(this.option);
482
+ this.map = new Cesium.Viewer(id, this.config);
483
+
484
+ // 监听相机移动事件
485
+ this.map.camera.moveEnd.addEventListener(() => {
486
+ const camera = this.map.camera;
487
+ const cartographic = Cesium.Cartographic.fromCartesian(camera.position);
488
+ const height = cartographic.height;
489
+ this.level = getHeightToLevel(height);
490
+
491
+ // 触发cameraMoveEnd事件
492
+ if (this.event.cameraMoveEnd) {
493
+ this.event.cameraMoveEnd();
494
+ }
495
+ });
496
+ // 添加自定义数据源
497
+ this.map.dataSources.add(this.dataSources);
498
+
499
+ // 设置初始视图
500
+ const { lat, lng, level, heading, pitch, roll } = this.option;
501
+ const alt = getLevelMiddleHeight(level);
502
+
503
+ // 设置相机位置
504
+ const initialPosition = Cesium.Cartesian3.fromDegrees(lng, lat, alt);
505
+ const initialOrientation = new Cesium.HeadingPitchRoll(
506
+ Cesium.Math.toRadians(heading),
507
+ Cesium.Math.toRadians(pitch),
508
+ Cesium.Math.toRadians(roll)
509
+ );
510
+
511
+ this.map.camera.setView({
512
+ destination: initialPosition,
513
+ orientation: initialOrientation,
514
+ });
515
+ }
516
+ static async create(id: string, option: any) {
517
+ const instance = new cesium_map(id, option);
518
+
519
+ // 返回一个 Promise,等待地图的 'ready' 事件
520
+ await new Promise<void>((resolve) => {
521
+ resolve();
522
+ });
523
+
524
+ return instance;
525
+ }
526
+ // 格式化配置
527
+ formatConfig(option: any) {
528
+ const config: any = {
529
+ ...option.cesium_options,
530
+ // 设置不显示商标
531
+ imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
532
+ url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
533
+ enablePickFeatures: false,
534
+ }),
535
+ };
536
+
537
+ // 设置地形 - 兼容性处理
538
+ if (option.cesium_terrainProvider) {
539
+ config.terrainProvider = option.cesium_terrainProvider;
540
+ } else {
541
+ config.terrainProvider = this.createTerrainProvider();
542
+ }
543
+
544
+ // 设置影像 - 兼容性处理
545
+ if (option.cesium_imageryProvider) {
546
+ config.imageryProvider = option.cesium_imageryProvider;
547
+ } else {
548
+ config.imageryProvider = this.createImageryProvider();
549
+ }
550
+
551
+ return config;
552
+ }
553
+
554
+ // 创建地形提供者(兼容各版本)
555
+ createTerrainProvider() {
556
+ // 检查是否支持createWorldTerrain
557
+ if (typeof Cesium.createWorldTerrain === "function") {
558
+ // 1.107及以上版本
559
+ return Cesium.createWorldTerrain({
560
+ requestWaterMask: true,
561
+ requestVertexNormals: true,
562
+ });
563
+ } else if (Cesium.CesiumTerrainProvider) {
564
+ // 1.106及以下版本
565
+ const terrainUrl = this.getTerrainUrl();
566
+ return new Cesium.CesiumTerrainProvider({
567
+ url: terrainUrl,
568
+ requestWaterMask: true,
569
+ requestVertexNormals: true,
570
+ });
571
+ } else {
572
+ // 没有地形
573
+ console.warn("Cesium地形不可用,使用无地形模式");
574
+ return new Cesium.EllipsoidTerrainProvider();
575
+ }
576
+ }
577
+
578
+ // 获取地形URL(兼容处理)
579
+ getTerrainUrl() {
580
+ // 根据不同版本的API获取地形URL
581
+ if (Cesium.IonResource && Cesium.IonResource.fromAssetId) {
582
+ return Cesium.IonResource.fromAssetId(1);
583
+ } else if (Cesium.Ion && Cesium.Ion.defaultServer) {
584
+ return `${Cesium.Ion.defaultServer.url}/assets/1/quantized-mesh`;
585
+ } else {
586
+ // 使用Cesium官方的地形服务
587
+ return "https://assets.cesium.com/1/";
588
+ }
589
+ }
590
+
591
+ // 创建影像提供者(兼容各版本)
592
+ createImageryProvider() {
593
+ // 默认使用Bing地图或ArcGIS
594
+ try {
595
+ // 尝试创建Bing地图
596
+ if (Cesium.BingMapsImageryProvider) {
597
+ return new Cesium.BingMapsImageryProvider({
598
+ url: "https://dev.virtualearth.net",
599
+ key: this.option.cesium_bing_key || "", // 需要Bing Maps Key
600
+ mapStyle: Cesium.BingMapsStyle.AERIAL,
601
+ });
602
+ }
603
+ } catch (e) {
604
+ console.warn("Bing地图不可用,尝试其他影像源", e);
605
+ }
606
+
607
+ // 使用ArcGIS作为备选
608
+ if (Cesium.ArcGisMapServerImageryProvider) {
609
+ return new Cesium.ArcGisMapServerImageryProvider({
610
+ url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
611
+ });
612
+ }
613
+
614
+ // 使用OpenStreetMap作为最后备选
615
+ if (Cesium.OpenStreetMapImageryProvider) {
616
+ return new Cesium.OpenStreetMapImageryProvider({
617
+ url: "https://a.tile.openstreetmap.org/",
618
+ });
619
+ }
620
+
621
+ // 没有可用影像提供者
622
+ console.warn("没有可用的影像提供者");
623
+ return undefined;
624
+ }
625
+ // 添加图层
626
+ addLayer(layer: any) {
627
+ if (this.layerList.find((v: any) => v.id === layer.id)) {
628
+ console.error("已存在同名图层" + layer.id);
629
+ return null;
630
+ }
631
+
632
+ this.layerList.push(layer);
633
+
634
+ // 如果是数据源图层,添加到数据源集合
635
+ if (layer.layerEntity && layer.layerEntity.entities) {
636
+ this.map.dataSources.add(layer.layerEntity);
637
+ }
638
+
639
+ // 如果是Primitive图层,添加到Primitive集合
640
+ if (
641
+ layer.layerEntity &&
642
+ layer.layerEntity instanceof Cesium.PrimitiveCollection
643
+ ) {
644
+ this.map.scene.primitives.add(layer.layerEntity);
645
+ }
646
+
647
+ return layer;
648
+ }
649
+
650
+ // 获取图层
651
+ getLayer(layerId: any) {
652
+ return this.layerList.find((v: any) => v.id === layerId);
653
+ }
654
+
655
+ // 删除图层
656
+ removeLayer(layerId: any) {
657
+ const layer = this.getLayer(layerId);
658
+ if (layer) {
659
+ this.layerList = this.layerList.filter((v: any) => v.id !== layerId);
660
+ layer.destroy();
661
+ }
662
+ }
663
+
664
+ // 清空图层
665
+ clearLayer(layerId: any) {
666
+ const layer = this.getLayer(layerId);
667
+ if (layer) {
668
+ layer.children = [];
669
+ layer.clearEntity();
670
+ }
671
+ }
672
+
673
+ // 事件监听
674
+ on(eventType: any, callback: any) {
675
+ this.off(eventType);
676
+
677
+ switch (eventType) {
678
+ case "click":
679
+ this.event[eventType] = (movement: any) => {
680
+ // 获取点击位置
681
+ const ray = this.map.camera.getPickRay(movement.position);
682
+ if (!ray) return;
683
+
684
+ const cartesian = this.map.scene.globe.pick(ray, this.map.scene);
685
+ if (!cartesian) return;
686
+
687
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
688
+ const position = {
689
+ lng: Cesium.Math.toDegrees(cartographic.longitude),
690
+ lat: Cesium.Math.toDegrees(cartographic.latitude),
691
+ alt: cartographic.height,
692
+ };
693
+
694
+ callback(position);
695
+ };
696
+
697
+ // 使用屏幕空间事件处理器
698
+ this.map.screenSpaceEventHandler.setInputAction((movement: any) => {
699
+ this.event[eventType](movement);
700
+ }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
701
+ break;
702
+
703
+ case "cameraMoveEnd":
704
+ this.event[eventType] = () => {
705
+ callback();
706
+ };
707
+ break;
708
+
709
+ case "mouseMove":
710
+ this.event[eventType] = (movement: any) => {
711
+ callback(movement);
712
+ };
713
+
714
+ this.map.screenSpaceEventHandler.setInputAction((movement: any) => {
715
+ this.event[eventType](movement);
716
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
717
+ break;
718
+ }
719
+ }
720
+
721
+ // 取消事件监听
722
+ off(eventType: any) {
723
+ if (this.event[eventType]) {
724
+ // 移除事件处理器
725
+ this.map.screenSpaceEventHandler.removeInputAction(
726
+ Cesium.ScreenSpaceEventType.LEFT_CLICK
727
+ );
728
+ delete this.event[eventType];
729
+ }
730
+ }
731
+
732
+ /**
733
+ * 获取当前视口的经纬度范围
734
+ */
735
+ getExtent() {
736
+ const camera = this.map.camera;
737
+ const frustum = camera.frustum;
738
+
739
+ // 计算视锥体的四个角点
740
+ const corners = [
741
+ new Cesium.Cartesian2(0, 0),
742
+ new Cesium.Cartesian2(this.map.canvas.width, 0),
743
+ new Cesium.Cartesian2(this.map.canvas.width, this.map.canvas.height),
744
+ new Cesium.Cartesian2(0, this.map.canvas.height),
745
+ ];
746
+
747
+ let minLon = 180;
748
+ let maxLon = -180;
749
+ let minLat = 90;
750
+ let maxLat = -90;
751
+
752
+ corners.forEach((corner) => {
753
+ const ray = camera.getPickRay(corner);
754
+ if (!ray) return;
755
+
756
+ const cartesian = this.map.scene.globe.pick(ray, this.map.scene);
757
+ if (!cartesian) return;
758
+
759
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
760
+ const lon = Cesium.Math.toDegrees(cartographic.longitude);
761
+ const lat = Cesium.Math.toDegrees(cartographic.latitude);
762
+
763
+ minLon = Math.min(minLon, lon);
764
+ maxLon = Math.max(maxLon, lon);
765
+ minLat = Math.min(minLat, lat);
766
+ maxLat = Math.max(maxLat, lat);
767
+ });
768
+
769
+ return {
770
+ xmin: minLon,
771
+ xmax: maxLon,
772
+ ymin: minLat,
773
+ ymax: maxLat,
774
+ };
775
+ }
776
+
777
+ /**
778
+ * 获取当前相机视图
779
+ */
780
+ getCameraView() {
781
+ const camera = this.map.camera;
782
+ const position = camera.positionWC;
783
+ const cartographic = Cesium.Cartographic.fromCartesian(position);
784
+
785
+ return {
786
+ lng: Cesium.Math.toDegrees(cartographic.longitude),
787
+ lat: Cesium.Math.toDegrees(cartographic.latitude),
788
+ alt: cartographic.height,
789
+ heading: Cesium.Math.toDegrees(camera.heading),
790
+ pitch: Cesium.Math.toDegrees(camera.pitch),
791
+ roll: Cesium.Math.toDegrees(camera.roll),
792
+ };
793
+ }
794
+
795
+ /**
796
+ * 飞向指定点
797
+ */
798
+ flyToPoint(position: any) {
799
+ const [lng, lat, alt] = position;
800
+ const cartesian = Cesium.Cartesian3.fromDegrees(lng, lat, alt); // 创建经纬度坐标点
801
+
802
+ this.map.camera.flyTo({
803
+ destination: cartesian,
804
+ duration: 2,
805
+ complete: () => {
806
+ console.log("飞行动画完成");
807
+ },
808
+ });
809
+ }
810
+
811
+ /**
812
+ * 飞向指定区域
813
+ */
814
+ flyToExtent(extent: any) {
815
+ const rectangle = Cesium.Rectangle.fromDegrees(
816
+ extent.xmin,
817
+ extent.ymin,
818
+ extent.xmax,
819
+ extent.ymax
820
+ );
821
+
822
+ this.map.camera.flyTo({
823
+ destination: rectangle,
824
+ duration: 2,
825
+ });
826
+ }
827
+
828
+ /**
829
+ * 关闭所有弹窗
830
+ */
831
+ closePopup() {
832
+ this.map.selectedEntity = null;
833
+ this.map.trackedEntity = null;
834
+ }
835
+
836
+ /**
837
+ * 设置投影模式 2d/3d
838
+ */
839
+ setMode(mode: string) {
840
+ const modes: any = {
841
+ "2d": Cesium.SceneMode.SCENE2D,
842
+ "3d": Cesium.SceneMode.SCENE3D,
843
+ columbus: Cesium.SceneMode.COLUMBUS_VIEW,
844
+ };
845
+
846
+ if (modes[mode.toLowerCase()]) {
847
+ this.map.scene.mode = modes[mode.toLowerCase()];
848
+ }
849
+ }
850
+
851
+ /**
852
+ * 销毁地图
853
+ */
854
+ destroy() {
855
+ if (this.map) {
856
+ this.map.destroy();
857
+ this.map = null;
858
+ }
859
+ }
860
+ }
861
+
462
862
  const map: any = {
463
863
  mars3d: mars3d_map,
464
864
  gaode: gaode_map,
465
865
  siji: siji_map,
866
+ cesium: cesium_map,
466
867
  };
467
868
  return map[hnMap.mapType];
468
869
  };
@@ -1,6 +1,6 @@
1
1
  import { deepMerge, wgs84ToGcj02Format } from "../util";
2
2
 
3
- import siji_entity from "../base/siji_entity";
3
+ import SijiEntity from "../base/siji_entity";
4
4
  export default (hnMap: any) => {
5
5
  const defaultOption = {
6
6
  id: "",
@@ -242,7 +242,7 @@ export default (hnMap: any) => {
242
242
  }
243
243
  }
244
244
 
245
- class siji_class extends siji_entity {
245
+ class siji_class extends SijiEntity {
246
246
  type: any = "route";
247
247
  id: any = null;
248
248
  option: any = JSON.parse(JSON.stringify(defaultOption));