hn-map 1.1.16 → 1.1.17

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.
@@ -0,0 +1,98 @@
1
+ /**
2
+ * mars3d地图实体基类
3
+ * 提供mars3d地图要素的通用功能,如弹窗管理、事件处理、飞行定位等
4
+ */
5
+ export default class Mars3dEntity {
6
+ /** 配置选项 */
7
+ protected option: any = null;
8
+ /** 事件监听器集合 */
9
+ private event: Record<string, Function> = {};
10
+ /** 图形实例 */
11
+ protected graphic: any = null;
12
+
13
+ /**
14
+ * 构造函数
15
+ * @param hnMap 地图实例
16
+ */
17
+ constructor(hnMap: any) {
18
+ this.event = {};
19
+ }
20
+
21
+ /**
22
+ * 添加属性弹窗
23
+ * 点击要素时显示包含要素属性信息的弹窗
24
+ */
25
+ addPopupByAttr(): void {
26
+ this.graphic.bindPopup((event: any) => {
27
+ const data = event.graphic.attr;
28
+ return mars3d.Util.getTemplateHtml({
29
+ title: "详情",
30
+ template: "all",
31
+ attr: data,
32
+ });
33
+ });
34
+ }
35
+
36
+ /**
37
+ * 添加自定义DOM弹窗
38
+ * 点击要素时显示自定义DOM结构的弹窗
39
+ * @param getCustomDom 自定义DOM生成函数,接收要素数据,返回DOM字符串
40
+ */
41
+ addCustomPopup(getCustomDom: (data: any) => Promise<string> | string): void {
42
+ this.graphic.bindPopup(
43
+ async (event: any) => {
44
+ if (event.graphic.attr) {
45
+ const data = event.graphic.attr || {};
46
+ return await getCustomDom(data);
47
+ }
48
+ },
49
+ { offsetY: -20 }
50
+ );
51
+ }
52
+
53
+ /**
54
+ * 飞行定位到要素
55
+ * @param option 飞行定位选项
56
+ */
57
+ flyTo(option: any = {}): void {
58
+ this.graphic.flyTo(option);
59
+ }
60
+
61
+ /**
62
+ * 销毁要素
63
+ * 从地图中移除并销毁要素
64
+ */
65
+ destroy(): void {
66
+ this.graphic.destroy();
67
+ }
68
+
69
+ /**
70
+ * 监听事件
71
+ * @param eventType 事件类型
72
+ * @param callback 事件回调函数
73
+ */
74
+ on(eventType: string, callback: (data: any) => void): void {
75
+ this.off(eventType);
76
+
77
+ switch (eventType) {
78
+ case "click":
79
+ this.event[eventType] = () => {
80
+ callback(this.option.data);
81
+ };
82
+ break;
83
+ }
84
+
85
+ this.graphic.on(eventType, this.event[eventType]);
86
+ }
87
+
88
+ /**
89
+ * 移除事件监听
90
+ * @param eventType 事件类型
91
+ */
92
+ off(eventType: string): void {
93
+ if (this.event[eventType]) {
94
+ this.graphic.off(eventType, this.event[eventType]);
95
+ delete this.event[eventType];
96
+ }
97
+ }
98
+ }
@@ -7,6 +7,7 @@ import {
7
7
  import Mars3dEntity from "../base/mars3d_entity";
8
8
  import GaodeEntity from "../base/gaode_entity";
9
9
  import SijiEntity from "../base/siji_entity";
10
+ import CesiumEntity from "../base/cesium_entity";
10
11
 
11
12
  export default (hnMap: any) => {
12
13
  const defaultOption = {
@@ -22,8 +23,8 @@ export default (hnMap: any) => {
22
23
  dashColor: "#00ff00",
23
24
  dashLength: 16,
24
25
  image: "",
25
- repeat: [1, 1],
26
- speed: 5,
26
+ repeat: [1, 1], // 闪烁线重复次数
27
+ speed: 5, // 闪烁线速度
27
28
  scaleByDistance: true,
28
29
  distanceDisplayCondition: false,
29
30
  distanceDisplayCondition_far: 1,
@@ -84,7 +85,7 @@ export default (hnMap: any) => {
84
85
  outlineColor: option.outlineColor,
85
86
  outlineWidth: option.outlineWidth,
86
87
  clampToGround: !option.position[0][2],
87
- scaleByDistance: option.scaleByDistance,
88
+ scaleByDistance: option.scaleByDistance, // 缩放
88
89
  distanceDisplayCondition: option.distanceDisplayCondition,
89
90
  distanceDisplayCondition_far: distanceDisplayCondition_far,
90
91
  distanceDisplayCondition_near: distanceDisplayCondition_near,
@@ -363,10 +364,341 @@ export default (hnMap: any) => {
363
364
  }
364
365
  }
365
366
 
367
+ class cesium_class extends CesiumEntity {
368
+ type: any = "line";
369
+ id: any = null;
370
+ option: any = JSON.parse(JSON.stringify(defaultOption));
371
+ config: any = null;
372
+ graphic: any = null;
373
+ entity: any = null;
374
+ flickerInterval: any = null;
375
+
376
+ constructor(option: any) {
377
+ super(hnMap);
378
+ this.id = option.id;
379
+ deepMerge(this.option, option);
380
+ this.config = this.formatConfig(this.option);
381
+ this.createGraphic();
382
+
383
+ // 确保graphic正确指向entity
384
+ this.graphic = this.entity;
385
+ }
386
+
387
+ formatConfig(option: any) {
388
+ // 转换位置坐标为 Cesium 格式
389
+ const positions = option.position.map((pos: any) => {
390
+ if (Array.isArray(pos) && pos.length >= 2) {
391
+ const height = pos.length >= 3 ? pos[2] : 0;
392
+ return Cesium.Cartesian3.fromDegrees(pos[0], pos[1], height);
393
+ }
394
+ return pos;
395
+ });
396
+
397
+ return {
398
+ id: option.id,
399
+ positions: positions,
400
+ width: option.width || 2,
401
+ color: option.color || "#ffffff",
402
+ opacity: option.opacity || 1,
403
+ type: option.type || "line",
404
+ dashColor: option.dashColor || "#00ff00",
405
+ dashLength: option.dashLength || 16,
406
+ // dashPattern: option.dashPattern,
407
+ speed: option.speed || 5,
408
+ image: option.image,
409
+ repeat: option.repeat || [1, 1],
410
+ data: option.data,
411
+ clampToGround: option.clampToGround !== false,
412
+ distanceDisplayCondition: option.distanceDisplayCondition,
413
+ distanceDisplayCondition_far: option.distanceDisplayCondition_far,
414
+ distanceDisplayCondition_near: option.distanceDisplayCondition_near,
415
+ scaleByDistance: option.scaleByDistance,
416
+ };
417
+ }
418
+
419
+ createGraphic() {
420
+ const option = this.option;
421
+ const config = this.config;
422
+
423
+ // 根据线条类型创建不同的材质
424
+ let material: any;
425
+ switch (option.type) {
426
+ case "dash":
427
+ material = new Cesium.PolylineDashMaterialProperty({
428
+ color: Cesium.Color.fromCssColorString(option.color).withAlpha(
429
+ option.opacity
430
+ ),
431
+ gapColor: Cesium.Color.TRANSPARENT,
432
+ dashPattern: parseInt("1111111100000000", 2),
433
+ });
434
+ break;
435
+
436
+ case "flicker":
437
+ material = new Cesium.ColorMaterialProperty(
438
+ Cesium.Color.fromCssColorString(option.color).withAlpha(
439
+ option.opacity
440
+ )
441
+ );
442
+ this.setupFlickerEffect();
443
+ break;
444
+
445
+ case "flow":
446
+ material = new Cesium.PolylineArrowMaterialProperty(
447
+ Cesium.Color.fromCssColorString(option.color).withAlpha(
448
+ option.opacity
449
+ )
450
+ );
451
+ break;
452
+
453
+ case "arrow":
454
+ material = new Cesium.PolylineArrowMaterialProperty(
455
+ Cesium.Color.fromCssColorString(option.color).withAlpha(
456
+ option.opacity
457
+ )
458
+ );
459
+ break;
460
+
461
+ case "line":
462
+ default:
463
+ material = new Cesium.ColorMaterialProperty(
464
+ Cesium.Color.fromCssColorString(option.color).withAlpha(
465
+ option.opacity
466
+ )
467
+ );
468
+ break;
469
+ }
470
+
471
+ // 创建实体配置
472
+ const entityConfig: any = {
473
+ id: config.id,
474
+ name: config.id,
475
+ polyline: {
476
+ positions: new Cesium.ConstantProperty(config.positions),
477
+ width: new Cesium.ConstantProperty(config.width),
478
+ material: material,
479
+ clampToGround: config.clampToGround,
480
+ arcType: Cesium.ArcType.RHUMB,
481
+ show: true,
482
+ },
483
+ };
484
+
485
+ // // 添加距离显示条件
486
+ // if (option.distanceDisplayCondition) {
487
+ // const far = getLevelMiddleHeight(option.distanceDisplayCondition_far);
488
+ // const near = getLevelMiddleHeight(option.distanceDisplayCondition_near);
489
+ // entityConfig.polyline.distanceDisplayCondition =
490
+ // new Cesium.ConstantProperty(
491
+ // new Cesium.DistanceDisplayCondition(near, far)
492
+ // );
493
+ // }
494
+
495
+ // 创建 Cesium 实体
496
+ this.entity = new Cesium.Entity(entityConfig);
497
+ this.graphic = this.entity; // 确保graphic指向entity
498
+ }
499
+
500
+ // 设置闪烁效果
501
+ setupFlickerEffect() {
502
+ if (
503
+ this.option.type === "flicker" &&
504
+ this.entity &&
505
+ this.entity.polyline
506
+ ) {
507
+ let visible = true;
508
+ const toggleVisibility = () => {
509
+ if (this.entity && this.entity.polyline) {
510
+ visible = !visible;
511
+ this.entity.polyline.show = visible;
512
+ }
513
+ };
514
+
515
+ // 设置定时器
516
+ this.flickerInterval = setInterval(
517
+ toggleVisibility,
518
+ 1000 / this.option.speed
519
+ );
520
+ }
521
+ }
522
+
523
+ // 清理闪烁效果
524
+ cleanupFlickerEffect() {
525
+ if (this.flickerInterval) {
526
+ clearInterval(this.flickerInterval);
527
+ this.flickerInterval = null;
528
+ }
529
+ }
530
+ set(option: any) {
531
+ // 清理之前的特效
532
+ this.cleanupFlickerEffect();
533
+
534
+ deepMerge(this.option, option);
535
+ this.config = this.formatConfig(this.option);
536
+
537
+ // 重新创建图形
538
+ this.createGraphic();
539
+
540
+ // 注意:这里不需要手动添加到地图
541
+ // 图层会通过layer.set()或重新addEntity来更新
542
+ }
543
+
544
+ // 飞行到线条位置
545
+ flyTo(options: any = {}) {
546
+ if (this.entity && this.entity.polyline) {
547
+ const positions = this.entity.polyline.positions.getValue(
548
+ Cesium.JulianDate.now()
549
+ );
550
+ if (positions && positions.length > 0) {
551
+ // 计算包围盒
552
+ const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
553
+
554
+ // 飞行到目标
555
+ hnMap.map.map.camera.flyToBoundingSphere(boundingSphere, {
556
+ duration: options.duration || 2.0,
557
+ offset: new Cesium.HeadingPitchRange(
558
+ Cesium.Math.toRadians(0),
559
+ Cesium.Math.toRadians(-45),
560
+ boundingSphere.radius * 2.0
561
+ ),
562
+ });
563
+ }
564
+ }
565
+ }
566
+
567
+ // 打开弹窗(如果需要)
568
+ openPopup(htmlContent: string) {
569
+ if (this.entity && hnMap.map.map) {
570
+ // 设置实体的描述属性
571
+ this.entity.description = htmlContent;
572
+
573
+ // 选中实体以显示弹窗
574
+ hnMap.map.map.selectedEntity = this.entity;
575
+ }
576
+ }
577
+
578
+ // 判断点是否在线条附近
579
+ isInPoly(lng: number, lat: number) {
580
+ if (this.entity && this.entity.polyline) {
581
+ const positions = this.entity.polyline.positions.getValue(
582
+ Cesium.JulianDate.now()
583
+ );
584
+ if (positions && positions.length > 0) {
585
+ const point = Cesium.Cartesian3.fromDegrees(lng, lat);
586
+ // 检查点到线段的距离
587
+ for (let i = 0; i < positions.length - 1; i++) {
588
+ const start = positions[i];
589
+ const end = positions[i + 1];
590
+ const distance = Cesium.Cartesian3.distance(point, start);
591
+ if (distance < 1000) {
592
+ // 1公里范围内认为在线上
593
+ return true;
594
+ }
595
+ }
596
+ }
597
+ }
598
+ return false;
599
+ }
600
+
601
+ // 更新位置
602
+ setPosition(position: any[][]) {
603
+ if (this.entity && this.entity.polyline) {
604
+ const positions = position.map((pos: any) => {
605
+ if (Array.isArray(pos) && pos.length >= 2) {
606
+ const height = pos.length >= 3 ? pos[2] : 0;
607
+ return Cesium.Cartesian3.fromDegrees(pos[0], pos[1], height);
608
+ }
609
+ return pos;
610
+ });
611
+ this.entity.polyline.positions = new Cesium.CallbackProperty(
612
+ () => positions,
613
+ false
614
+ );
615
+ }
616
+ }
617
+
618
+ // 获取位置
619
+ getPosition() {
620
+ if (this.entity && this.entity.polyline) {
621
+ const positions = this.entity.polyline.positions.getValue(
622
+ Cesium.JulianDate.now()
623
+ );
624
+ return positions.map((cartesian: any) => {
625
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
626
+ return [
627
+ Cesium.Math.toDegrees(cartographic.longitude),
628
+ Cesium.Math.toDegrees(cartographic.latitude),
629
+ cartographic.height,
630
+ ];
631
+ });
632
+ }
633
+ return [];
634
+ }
635
+
636
+ // 设置颜色
637
+ setColor(color: string) {
638
+ if (
639
+ this.entity &&
640
+ this.entity.polyline &&
641
+ this.entity.polyline.material
642
+ ) {
643
+ const cesiumColor = Cesium.Color.fromCssColorString(color).withAlpha(
644
+ this.option.opacity
645
+ );
646
+ if (this.entity.polyline.material.color) {
647
+ this.entity.polyline.material.color = cesiumColor;
648
+ } else if (this.entity.polyline.material.evenColor) {
649
+ this.entity.polyline.material.evenColor = cesiumColor;
650
+ }
651
+ }
652
+ }
653
+
654
+ // 设置透明度
655
+ setOpacity(opacity: number) {
656
+ if (
657
+ this.entity &&
658
+ this.entity.polyline &&
659
+ this.entity.polyline.material
660
+ ) {
661
+ this.option.opacity = opacity;
662
+ const currentColor = Cesium.Color.fromCssColorString(this.option.color);
663
+ const newColor = currentColor.withAlpha(opacity);
664
+
665
+ if (this.entity.polyline.material.color) {
666
+ this.entity.polyline.material.color = newColor;
667
+ } else if (this.entity.polyline.material.evenColor) {
668
+ this.entity.polyline.material.evenColor = newColor;
669
+ }
670
+ }
671
+ }
672
+
673
+ // 设置线宽
674
+ setWidth(width: number) {
675
+ if (this.entity && this.entity.polyline) {
676
+ this.option.width = width;
677
+ this.entity.polyline.width = width;
678
+ }
679
+ }
680
+
681
+ // 销毁实体
682
+ destroy() {
683
+ // 清理特效
684
+ this.cleanupFlickerEffect();
685
+
686
+ if (this.entity) {
687
+ // 从图层移除实体
688
+ if (hnMap.map.map && hnMap.map.map.entities) {
689
+ hnMap.map.entities.remove(this.entity);
690
+ }
691
+ this.entity = null;
692
+ this.graphic = null;
693
+ }
694
+ }
695
+ }
696
+
366
697
  const fn: any = {
367
698
  mars3d: mars3d_class,
368
699
  gaode: gaode_class,
369
700
  siji: siji_class,
701
+ cesium: cesium_class,
370
702
  };
371
703
 
372
704
  return fn[hnMap.mapType];
@@ -180,11 +180,7 @@ export default (hnMap: any) => {
180
180
  ],
181
181
  },
182
182
  },
183
- layout: {
184
- "text-field": "{name}", // 文本
185
- "text-size": Number(option.fontSize),
186
- "text-offset": convertPosition(option.fontOffset),
187
- },
183
+
188
184
  paint: {
189
185
  "circle-opacity": Number(option.opacity),
190
186
  "circle-radius": Number(option.size),
@@ -198,7 +194,6 @@ export default (hnMap: any) => {
198
194
  "circle-stroke-opacity": option.outline
199
195
  ? Number(option.outlineOpacity)
200
196
  : 1, // 边框样式
201
-
202
197
  }, // 填充样式
203
198
  };
204
199
 
package/src/index.ts CHANGED
@@ -40,7 +40,6 @@ interface MapOption {
40
40
  cesium_baseUrl: string; // Cesium静态资源基础路径
41
41
  cesium_terrainProvider: any; // 地形提供者配置
42
42
  cesium_imageryProvider: any; // 影像提供者配置
43
- cesium_options: {};
44
43
  }
45
44
 
46
45
  /**
@@ -252,17 +251,18 @@ export default class HnMap {
252
251
  ): Promise<void> {
253
252
  // 加载Cesium CSS
254
253
  // await loadResource(basePath + "lib/Cesium/Widgets/widgets.css", "css");
255
- await loadResource(
256
- "https://cesium.com/downloads/cesiumjs/releases/1.107/Build/Cesium/Widgets/widgets.css",
257
- "css"
258
- );
259
-
260
- // 加载Cesium JS
261
- await loadResource(
262
- "https://cesium.com/downloads/cesiumjs/releases/1.107/Build/Cesium/Cesium.js",
263
- "js"
264
- );
254
+ // await loadResource(
255
+ // "https://cesium.com/downloads/cesiumjs/releases/1.107/Build/Cesium/Widgets/widgets.css",
256
+ // "css"
257
+ // );
265
258
 
259
+ // // 加载Cesium JS
260
+ // await loadResource(
261
+ // "https://cesium.com/downloads/cesiumjs/releases/1.107/Build/Cesium/Cesium.js",
262
+ // "js"
263
+ // );
264
+ await loadResource(basePath + "lib/Cesium/Widgets/widgets.css", "css");
265
+ await loadResource(basePath + "lib/Cesium/Cesium.js", "js");
266
266
  // 设置Cesium访问令牌(如果有)
267
267
  if (option.cesium_accessToken) {
268
268
  Cesium.Ion.defaultAccessToken = option.cesium_accessToken;
@@ -331,7 +331,7 @@ export default (hnMap: any) => {
331
331
  layerEntity: any = null;
332
332
  // 创建全局信息窗口实例
333
333
  infoWindow: any = null;
334
- event:any = {}
334
+ event: any = {};
335
335
 
336
336
  constructor(option: any) {
337
337
  this.id = option.id;
@@ -347,7 +347,7 @@ export default (hnMap: any) => {
347
347
  coordinates: convertPosition(v.position),
348
348
  },
349
349
  properties: {
350
- name: v.data.name,
350
+ ...option.data,
351
351
  },
352
352
  })),
353
353
  },
@@ -468,63 +468,10 @@ export default (hnMap: any) => {
468
468
  */
469
469
  off(eventType: string): void {
470
470
  if (this.event[eventType]) {
471
- hnMap.map.map.off(eventType,this.event[eventType]);
471
+ hnMap.map.map.off(eventType, this.event[eventType]);
472
472
  delete this.event[eventType];
473
473
  }
474
474
  }
475
-
476
- //
477
- // // 添加属性弹窗
478
- // addPopupByAttr() {
479
- // // 如果已有弹窗,先关闭
480
- // this.removePopup();
481
- // this.infoWindow = new SGMap.Popup({
482
- // offset: { bottom: [0, 0] },
483
- // className: "my-attrPopup-class",
484
- // });
485
- //
486
- // const handleClick = (e: any) => {
487
- // let data = e.features[0].properties;
488
- //
489
- // // 创建弹窗内容
490
- // let content = "";
491
- // for (const key in data) {
492
- // content += `<div>${key}: ${data[key]}</div>`;
493
- // }
494
- //
495
- // this.infoWindow.setHTML(content);
496
- // this.infoWindow.setLngLat(e.lngLat).addTo(hnMap.map.map);
497
- // };
498
- //
499
- // hnMap.map.map.on("click", this.config.id, handleClick);
500
- // }
501
- //
502
- // // 添加自定义dom弹窗
503
- // addCustomPopup(getCustomDom: any) {
504
- // // 如果已有弹窗,先关闭
505
- // this.removePopup();
506
- // this.infoWindow = new SGMap.Popup({
507
- // offset: { bottom: [0, 0] },
508
- // className: "my-customPopup-class",
509
- // });
510
- //
511
- // const handleClick = (e: any) => {
512
- // const data = e.features[0].properties;
513
- // const dom = getCustomDom(data);
514
- // this.infoWindow.setHTML(dom);
515
- // this.infoWindow.setLngLat(e.lngLat).addTo(hnMap.map.map);
516
- // };
517
- //
518
- // hnMap.map.map.on("click", this.config.id, handleClick);
519
- // }
520
- //
521
- // // 弹窗删除
522
- // removePopup() {
523
- // if (this.infoWindow) {
524
- // this.infoWindow.remove();
525
- // }
526
- // }
527
-
528
475
  }
529
476
 
530
477
  const fn: any = {