hn-map 1.1.18 → 1.1.19
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.
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/base/cesium_entity.ts +377 -368
- package/src/base/cesium_popup.ts +11 -3
- package/src/map.ts +26 -1
|
@@ -4,396 +4,405 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import CesiumPopup from "./cesium_popup"; // 导入弹窗类
|
|
6
6
|
export default class CesiumEntity {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
7
|
+
/** 配置选项 */
|
|
8
|
+
protected option: any = null;
|
|
9
|
+
/** 事件监听器集合 */
|
|
10
|
+
event: Record<string, Function> = {};
|
|
11
|
+
/** 图形实例 */
|
|
12
|
+
graphic: any = null;
|
|
13
|
+
/** 地图实例 */
|
|
14
|
+
protected hnMap: any = null;
|
|
15
|
+
/** 弹窗实例 */
|
|
16
|
+
private popup: any = null;
|
|
17
|
+
/** 弹窗内容缓存 */
|
|
18
|
+
private popupContent: string | null = null;
|
|
19
|
+
/** 是否显示弹窗 */
|
|
20
|
+
enablePopup: boolean = false;
|
|
21
|
+
/** 弹窗样式配置 */
|
|
22
|
+
private popupStyle: any = null;
|
|
23
|
+
|
|
24
|
+
private _popupClickHandler: ((movement: any) => void) | null = null;
|
|
25
|
+
private _userClickHandler: ((movement: any) => void) | null = null;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 构造函数
|
|
29
|
+
* @param hnMap 地图实例
|
|
30
|
+
*/
|
|
31
|
+
constructor(hnMap: any) {
|
|
32
|
+
this.hnMap = hnMap;
|
|
33
|
+
// 创建弹窗实例
|
|
34
|
+
if (hnMap && hnMap.map && hnMap.map.map) {
|
|
34
35
|
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 设置弹窗样式
|
|
41
|
+
* @param style 弹窗样式配置
|
|
42
|
+
*/
|
|
43
|
+
setPopupStyle(style: any): void {
|
|
44
|
+
this.popupStyle = style;
|
|
45
|
+
// 如果弹窗已存在,重新创建以应用新样式
|
|
46
|
+
if (this.popup && this.hnMap && this.hnMap.map && this.hnMap.map.map) {
|
|
47
|
+
this.popup.destroy();
|
|
48
|
+
const PopupClass = CesiumPopup(this.hnMap);
|
|
49
|
+
this.popup = new PopupClass(this.hnMap.map.map, {
|
|
50
|
+
style: this.popupStyle,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.showPopupOnClick = true;
|
|
60
|
-
|
|
61
|
-
if (this.option && this.option.data) {
|
|
62
|
-
// 生成属性弹窗内容
|
|
63
|
-
let content =
|
|
64
|
-
'<div style="background:#ffffff;color:#666;padding:12px;max-height: 300px; overflow-y: auto;">';
|
|
65
|
-
|
|
66
|
-
for (const key in this.option.data) {
|
|
67
|
-
if (this.option.data.hasOwnProperty(key)) {
|
|
68
|
-
content += `
|
|
69
|
-
<div>${key + ":" + this.option.data[key]}</div>
|
|
70
|
-
|
|
71
|
-
`;
|
|
54
|
+
|
|
55
|
+
// 新增方法:清理现有弹窗相关状态
|
|
56
|
+
private clearPopupState(): void {
|
|
57
|
+
// 销毁弹窗
|
|
58
|
+
if (this.popup) {
|
|
59
|
+
this.popup.destroy();
|
|
60
|
+
this.popup = null;
|
|
72
61
|
}
|
|
73
|
-
}
|
|
74
62
|
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
// 清理弹窗回调
|
|
64
|
+
if (this._popupClickHandler && this.graphic && this.hnMap?.map?.map) {
|
|
65
|
+
const handlers = this.hnMap.map.entityClickHandlers.get(this.graphic);
|
|
66
|
+
if (handlers) {
|
|
67
|
+
const index = handlers.indexOf(this._popupClickHandler);
|
|
68
|
+
if (index !== -1) {
|
|
69
|
+
handlers.splice(index, 1);
|
|
70
|
+
if (handlers.length === 0) {
|
|
71
|
+
this.hnMap.map.entityClickHandlers.delete(this.graphic);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this._popupClickHandler = null;
|
|
76
|
+
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
this.popupContent = null;
|
|
79
|
+
this.enablePopup = false;
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 添加属性弹窗
|
|
85
|
+
* 点击要素时显示包含要素属性信息的弹窗
|
|
86
|
+
*/
|
|
87
|
+
addPopupByAttr(): void {
|
|
88
|
+
this.clearPopupState();
|
|
89
|
+
|
|
90
|
+
if (!this.option?.data || !this.graphic || !this.hnMap?.map?.map) return;
|
|
91
|
+
// 构建内容
|
|
92
|
+
let content = '<div style="background:#ffffff;color:#666;padding:12px;max-height:300px;overflow-y:auto;">';
|
|
93
|
+
for (const key in this.option.data) {
|
|
94
|
+
if (this.option.data.hasOwnProperty(key)) {
|
|
95
|
+
content += `<div>${key}: ${this.option.data[key]}</div>`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
content += '</div>';
|
|
99
|
+
this.popupContent = content;
|
|
100
|
+
|
|
101
|
+
// 注册弹窗专用回调
|
|
102
|
+
const popupHandler = (movement: any) => {
|
|
103
|
+
this.showPopupAtPosition(movement.position);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// 存储以便清理
|
|
107
|
+
this._popupClickHandler = popupHandler;
|
|
108
|
+
|
|
109
|
+
// 👇 关键:添加到回调数组
|
|
110
|
+
if (!this.hnMap.map.entityClickHandlers.has(this.graphic)) {
|
|
111
|
+
this.hnMap.map.entityClickHandlers.set(this.graphic, []);
|
|
112
|
+
}
|
|
113
|
+
this.hnMap.map.entityClickHandlers.get(this.graphic)!.push(popupHandler);
|
|
111
114
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 添加自定义DOM弹窗
|
|
118
|
+
* 点击要素时显示自定义DOM结构的弹窗
|
|
119
|
+
* @param getCustomDom 自定义DOM生成函数,接收要素数据,返回DOM字符串
|
|
120
|
+
|
|
121
|
+
*/
|
|
122
|
+
addCustomPopup(getCustomDom: (data: any) => Promise<string> | string): void {
|
|
123
|
+
this.clearPopupState();
|
|
124
|
+
this.enablePopup = true;
|
|
125
|
+
|
|
126
|
+
const data = this.option && this.option.data ? this.option.data : {};
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const customDom = getCustomDom(data);
|
|
130
|
+
if (customDom instanceof Promise) {
|
|
131
|
+
customDom
|
|
132
|
+
.then((dom: string) => {
|
|
133
|
+
this.popupContent = dom;
|
|
134
|
+
})
|
|
135
|
+
.catch((error: any) => {
|
|
136
|
+
console.error("生成自定义弹窗DOM失败:", error);
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
this.popupContent = customDom;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 注册弹窗专用回调
|
|
143
|
+
const popupHandler = (movement: any) => {
|
|
144
|
+
this.showPopupAtPosition(movement.position);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// 存储以便清理
|
|
148
|
+
this._popupClickHandler = popupHandler;
|
|
149
|
+
|
|
150
|
+
// 👇 关键:添加到回调数组
|
|
151
|
+
if (!this.hnMap.map.entityClickHandlers.has(this.graphic)) {
|
|
152
|
+
this.hnMap.map.entityClickHandlers.set(this.graphic, []);
|
|
153
|
+
}
|
|
154
|
+
this.hnMap.map.entityClickHandlers.get(this.graphic)!.push(popupHandler);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error("生成自定义弹窗DOM失败:", error);
|
|
157
|
+
}
|
|
121
158
|
}
|
|
122
159
|
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
/**
|
|
161
|
+
* 在指定位置显示弹窗
|
|
162
|
+
* @param position 屏幕坐标位置
|
|
163
|
+
*/
|
|
164
|
+
public showPopupAtPosition(position: any): void {
|
|
165
|
+
if (!this.popupContent) return;
|
|
166
|
+
|
|
167
|
+
// 获取点击的世界坐标
|
|
168
|
+
const ray = this.hnMap.map.map.camera.getPickRay(position);
|
|
169
|
+
if (!ray) return;
|
|
170
|
+
|
|
171
|
+
// 获取笛卡尔坐标
|
|
172
|
+
const cartesian = this.hnMap.map.map.scene.globe.pick(
|
|
173
|
+
ray,
|
|
174
|
+
this.hnMap.map.map.scene
|
|
175
|
+
);
|
|
176
|
+
if (!cartesian) return;
|
|
177
|
+
const PopupClass = CesiumPopup(this.hnMap);
|
|
178
|
+
this.popup = new PopupClass(this.hnMap.map.map, {style: this.popupStyle});
|
|
179
|
+
// 显示弹窗
|
|
180
|
+
this.popup.show({cartesian}, this.popupContent);
|
|
125
181
|
}
|
|
126
182
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.screenSpaceEventHandler.setInputAction((movement: any) => {
|
|
132
|
-
// 检查是否点击到了当前实体
|
|
133
|
-
const pickedObject = this.hnMap.map.map.scene.pick(movement.position);
|
|
134
|
-
|
|
135
|
-
if (pickedObject && pickedObject.id === this.graphic) {
|
|
136
|
-
this.showPopupAtPosition(movement.position);
|
|
137
|
-
}
|
|
138
|
-
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 在指定位置显示弹窗
|
|
143
|
-
* @param position 屏幕坐标位置
|
|
144
|
-
*/
|
|
145
|
-
private showPopupAtPosition(position: any): void {
|
|
146
|
-
if (!this.popupContent) return;
|
|
147
|
-
|
|
148
|
-
// 获取点击的世界坐标
|
|
149
|
-
const ray = this.hnMap.map.map.camera.getPickRay(position);
|
|
150
|
-
if (!ray) return;
|
|
151
|
-
|
|
152
|
-
// 获取笛卡尔坐标
|
|
153
|
-
const cartesian = this.hnMap.map.map.scene.globe.pick(
|
|
154
|
-
ray,
|
|
155
|
-
this.hnMap.map.map.scene
|
|
156
|
-
);
|
|
157
|
-
if (!cartesian) return;
|
|
158
|
-
const PopupClass = CesiumPopup(this.hnMap);
|
|
159
|
-
this.popup = new PopupClass(this.hnMap.map.map, { style: this.popupStyle });
|
|
160
|
-
// 显示弹窗
|
|
161
|
-
this.popup.show({ cartesian }, this.popupContent);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* 飞行定位到要素
|
|
165
|
-
* @param option 飞行定位选项
|
|
166
|
-
*/
|
|
167
|
-
flyTo(option: any = {}): void {
|
|
168
|
-
if (this.graphic && this.hnMap && this.hnMap.map.map) {
|
|
169
|
-
try {
|
|
170
|
-
// 根据实体类型确定飞行目标
|
|
171
|
-
let target: any = null;
|
|
172
|
-
|
|
173
|
-
// 优先判断具体类型
|
|
174
|
-
if (this.graphic.polyline && this.graphic.polyline.positions) {
|
|
175
|
-
// 线实体
|
|
176
|
-
const positions = this.graphic.polyline.positions.getValue(
|
|
177
|
-
Cesium.JulianDate.now()
|
|
178
|
-
);
|
|
179
|
-
console.log("线实体的坐标:", positions);
|
|
180
|
-
if (positions && positions.length > 0) {
|
|
181
|
-
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions); // 计算包围球
|
|
182
|
-
// 增加包围球半径,确保有足够的视野
|
|
183
|
-
const radiusMultiplier = option.radiusMultiplier || 3.0;
|
|
184
|
-
this.hnMap.map.map.camera.flyToBoundingSphere(boundingSphere, {
|
|
185
|
-
duration: option.duration || 2.0,
|
|
186
|
-
offset: new Cesium.HeadingPitchRange(
|
|
187
|
-
Cesium.Math.toRadians(option.heading || 0),
|
|
188
|
-
Cesium.Math.toRadians(option.pitch || -90),
|
|
189
|
-
boundingSphere.radius * radiusMultiplier // 增加视野范围
|
|
190
|
-
),
|
|
191
|
-
}); // 飞行到包围球
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
} else if (this.graphic.polygon && this.graphic.polygon.hierarchy) {
|
|
195
|
-
// 面实体
|
|
196
|
-
const hierarchy = this.graphic.polygon.hierarchy.getValue(
|
|
197
|
-
Cesium.JulianDate.now()
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
if (hierarchy && hierarchy.positions) {
|
|
201
|
-
// console.log("面实体的坐标:", hierarchy.positions);
|
|
202
|
-
|
|
203
|
-
const boundingSphere = Cesium.BoundingSphere.fromPoints(
|
|
204
|
-
hierarchy.positions
|
|
205
|
-
);
|
|
206
|
-
// 增加包围球半径,确保有足够的视野
|
|
207
|
-
const radiusMultiplier = option.radiusMultiplier || 3.0;
|
|
208
|
-
this.hnMap.map.map.camera.flyToBoundingSphere(boundingSphere, {
|
|
209
|
-
duration: option.duration || 2.0,
|
|
210
|
-
offset: new Cesium.HeadingPitchRange(
|
|
211
|
-
Cesium.Math.toRadians(option.heading || 0),
|
|
212
|
-
Cesium.Math.toRadians(option.pitch || -90),
|
|
213
|
-
boundingSphere.radius * radiusMultiplier // 增加视野范围
|
|
214
|
-
),
|
|
215
|
-
});
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
} else if (
|
|
219
|
-
this.graphic.rectangle &&
|
|
220
|
-
this.graphic.rectangle.coordinates
|
|
221
|
-
) {
|
|
222
|
-
// 矩形实体
|
|
223
|
-
target = this.graphic.rectangle.coordinates.getValue(
|
|
224
|
-
Cesium.JulianDate.now()
|
|
225
|
-
);
|
|
226
|
-
if (target) {
|
|
227
|
-
// 为矩形增加一些边距
|
|
228
|
-
const west = target.west - 0.001;
|
|
229
|
-
const south = target.south - 0.001;
|
|
230
|
-
const east = target.east + 0.001;
|
|
231
|
-
const north = target.north + 0.001;
|
|
232
|
-
|
|
233
|
-
const expandedRectangle = new Cesium.Rectangle(
|
|
234
|
-
west,
|
|
235
|
-
south,
|
|
236
|
-
east,
|
|
237
|
-
north
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
this.hnMap.map.map.camera.flyTo({
|
|
241
|
-
destination: expandedRectangle,
|
|
242
|
-
duration: option.duration || 2.0,
|
|
243
|
-
orientation: {
|
|
244
|
-
heading: Cesium.Math.toRadians(option.heading || 0),
|
|
245
|
-
pitch: Cesium.Math.toRadians(option.pitch || -90),
|
|
246
|
-
roll: Cesium.Math.toRadians(option.roll || 0),
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
} else if (this.graphic.position) {
|
|
252
|
-
// 点实体或其他具有position属性的实体
|
|
253
|
-
target = this.graphic.position.getValue(Cesium.JulianDate.now());
|
|
254
|
-
// console.log("点实体的坐标:", target);
|
|
255
|
-
|
|
256
|
-
if (target) {
|
|
257
|
-
// 对于点实体,设置一个合适的高度以确保视野
|
|
258
|
-
const cartographic = Cesium.Cartographic.fromCartesian(target); // 转换为经纬度
|
|
259
|
-
// 调整默认高度和俯仰角,确保点在视图中央
|
|
260
|
-
const defaultHeight = option.height || 1000; // 减小默认高度到1000米
|
|
261
|
-
const finalHeight = Math.max(
|
|
262
|
-
cartographic.height + defaultHeight,
|
|
263
|
-
defaultHeight
|
|
264
|
-
);
|
|
265
|
-
const finalPosition = Cesium.Cartesian3.fromRadians(
|
|
266
|
-
cartographic.longitude,
|
|
267
|
-
cartographic.latitude,
|
|
268
|
-
finalHeight
|
|
269
|
-
); // 转换回笛卡尔坐标
|
|
270
|
-
|
|
271
|
-
this.hnMap.map.map.camera.flyTo({
|
|
272
|
-
destination: finalPosition,
|
|
273
|
-
duration: option.duration || 2.0,
|
|
274
|
-
orientation: {
|
|
275
|
-
heading: Cesium.Math.toRadians(option.heading || 0), // 默认朝向正北
|
|
276
|
-
// 调整俯仰角为-90度(垂直向下看),确保点在视图中央
|
|
277
|
-
pitch: Cesium.Math.toRadians(option.pitch || -90),
|
|
278
|
-
roll: Cesium.Math.toRadians(option.roll || 0), // 默认滚转角
|
|
279
|
-
},
|
|
280
|
-
});
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
183
|
+
// 新增方法:注册点击回调(由 map 统一调用)
|
|
184
|
+
public registerClick(handler: (movement: any) => void): void {
|
|
185
|
+
if (!this.graphic || !this.hnMap?.map?.map) return;
|
|
284
186
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
console.error("飞行定位失败:", error);
|
|
288
|
-
}
|
|
187
|
+
// 将回调注册到 map 的注册表中
|
|
188
|
+
this.hnMap.map.entityClickHandlers.set(this.graphic, handler);
|
|
289
189
|
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* 销毁要素
|
|
294
|
-
* 从地图中移除并销毁要素
|
|
295
|
-
*/
|
|
296
|
-
destroy(): void {
|
|
297
|
-
// 移除所有事件监听
|
|
298
|
-
this.offAll();
|
|
299
|
-
|
|
300
|
-
if (this.graphic && this.hnMap && this.hnMap.map) {
|
|
301
|
-
try {
|
|
302
|
-
// 从地图实体集合中移除
|
|
303
|
-
if (this.hnMap.map.entities) {
|
|
304
|
-
this.hnMap.map.entities.remove(this.graphic);
|
|
305
|
-
}
|
|
306
190
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
191
|
+
// 取消注册(用于销毁时)
|
|
192
|
+
public unregisterClick(): void {
|
|
193
|
+
if (this.graphic && this.hnMap?.map?.map) {
|
|
194
|
+
this.hnMap.map.entityClickHandlers.delete(this.graphic);
|
|
310
195
|
}
|
|
311
|
-
|
|
312
|
-
this.graphic = null;
|
|
313
|
-
} catch (error) {
|
|
314
|
-
console.error("销毁实体失败:", error);
|
|
315
|
-
}
|
|
316
196
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 飞行定位到要素
|
|
200
|
+
* @param option 飞行定位选项
|
|
201
|
+
*/
|
|
202
|
+
flyTo(option: any = {}): void {
|
|
203
|
+
if (this.graphic && this.hnMap && this.hnMap.map.map) {
|
|
204
|
+
try {
|
|
205
|
+
// 根据实体类型确定飞行目标
|
|
206
|
+
let target: any = null;
|
|
207
|
+
|
|
208
|
+
// 优先判断具体类型
|
|
209
|
+
if (this.graphic.polyline && this.graphic.polyline.positions) {
|
|
210
|
+
// 线实体
|
|
211
|
+
const positions = this.graphic.polyline.positions.getValue(
|
|
212
|
+
Cesium.JulianDate.now()
|
|
213
|
+
);
|
|
214
|
+
// console.log("线实体的坐标:", positions);
|
|
215
|
+
if (positions && positions.length > 0) {
|
|
216
|
+
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions); // 计算包围球
|
|
217
|
+
// 增加包围球半径,确保有足够的视野
|
|
218
|
+
const radiusMultiplier = option.radiusMultiplier || 3.0;
|
|
219
|
+
this.hnMap.map.map.camera.flyToBoundingSphere(boundingSphere, {
|
|
220
|
+
duration: option.duration || 2.0,
|
|
221
|
+
offset: new Cesium.HeadingPitchRange(
|
|
222
|
+
Cesium.Math.toRadians(option.heading || 0),
|
|
223
|
+
Cesium.Math.toRadians(option.pitch || -90),
|
|
224
|
+
boundingSphere.radius * radiusMultiplier // 增加视野范围
|
|
225
|
+
),
|
|
226
|
+
}); // 飞行到包围球
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
} else if (this.graphic.polygon && this.graphic.polygon.hierarchy) {
|
|
230
|
+
// 面实体
|
|
231
|
+
const hierarchy = this.graphic.polygon.hierarchy.getValue(
|
|
232
|
+
Cesium.JulianDate.now()
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
if (hierarchy && hierarchy.positions) {
|
|
236
|
+
// console.log("面实体的坐标:", hierarchy.positions);
|
|
237
|
+
|
|
238
|
+
const boundingSphere = Cesium.BoundingSphere.fromPoints(
|
|
239
|
+
hierarchy.positions
|
|
240
|
+
);
|
|
241
|
+
// 增加包围球半径,确保有足够的视野
|
|
242
|
+
const radiusMultiplier = option.radiusMultiplier || 3.0;
|
|
243
|
+
this.hnMap.map.map.camera.flyToBoundingSphere(boundingSphere, {
|
|
244
|
+
duration: option.duration || 2.0,
|
|
245
|
+
offset: new Cesium.HeadingPitchRange(
|
|
246
|
+
Cesium.Math.toRadians(option.heading || 0),
|
|
247
|
+
Cesium.Math.toRadians(option.pitch || -90),
|
|
248
|
+
boundingSphere.radius * radiusMultiplier // 增加视野范围
|
|
249
|
+
),
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
} else if (
|
|
254
|
+
this.graphic.rectangle &&
|
|
255
|
+
this.graphic.rectangle.coordinates
|
|
256
|
+
) {
|
|
257
|
+
// 矩形实体
|
|
258
|
+
target = this.graphic.rectangle.coordinates.getValue(
|
|
259
|
+
Cesium.JulianDate.now()
|
|
260
|
+
);
|
|
261
|
+
if (target) {
|
|
262
|
+
// 为矩形增加一些边距
|
|
263
|
+
const west = target.west - 0.001;
|
|
264
|
+
const south = target.south - 0.001;
|
|
265
|
+
const east = target.east + 0.001;
|
|
266
|
+
const north = target.north + 0.001;
|
|
267
|
+
|
|
268
|
+
const expandedRectangle = new Cesium.Rectangle(
|
|
269
|
+
west,
|
|
270
|
+
south,
|
|
271
|
+
east,
|
|
272
|
+
north
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
this.hnMap.map.map.camera.flyTo({
|
|
276
|
+
destination: expandedRectangle,
|
|
277
|
+
duration: option.duration || 2.0,
|
|
278
|
+
orientation: {
|
|
279
|
+
heading: Cesium.Math.toRadians(option.heading || 0),
|
|
280
|
+
pitch: Cesium.Math.toRadians(option.pitch || -90),
|
|
281
|
+
roll: Cesium.Math.toRadians(option.roll || 0),
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
} else if (this.graphic.position) {
|
|
287
|
+
// 点实体或其他具有position属性的实体
|
|
288
|
+
target = this.graphic.position.getValue(Cesium.JulianDate.now());
|
|
289
|
+
// console.log("点实体的坐标:", target);
|
|
290
|
+
|
|
291
|
+
if (target) {
|
|
292
|
+
// 对于点实体,设置一个合适的高度以确保视野
|
|
293
|
+
const cartographic = Cesium.Cartographic.fromCartesian(target); // 转换为经纬度
|
|
294
|
+
// 调整默认高度和俯仰角,确保点在视图中央
|
|
295
|
+
const defaultHeight = option.height || 1000; // 减小默认高度到1000米
|
|
296
|
+
const finalHeight = Math.max(
|
|
297
|
+
cartographic.height + defaultHeight,
|
|
298
|
+
defaultHeight
|
|
299
|
+
);
|
|
300
|
+
const finalPosition = Cesium.Cartesian3.fromRadians(
|
|
301
|
+
cartographic.longitude,
|
|
302
|
+
cartographic.latitude,
|
|
303
|
+
finalHeight
|
|
304
|
+
); // 转换回笛卡尔坐标
|
|
305
|
+
|
|
306
|
+
this.hnMap.map.map.camera.flyTo({
|
|
307
|
+
destination: finalPosition,
|
|
308
|
+
duration: option.duration || 2.0,
|
|
309
|
+
orientation: {
|
|
310
|
+
heading: Cesium.Math.toRadians(option.heading || 0), // 默认朝向正北
|
|
311
|
+
// 调整俯仰角为-90度(垂直向下看),确保点在视图中央
|
|
312
|
+
pitch: Cesium.Math.toRadians(option.pitch || -90),
|
|
313
|
+
roll: Cesium.Math.toRadians(option.roll || 0), // 默认滚转角
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
console.warn("无法确定实体类型或实体没有有效的位置信息", this.graphic);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error("飞行定位失败:", error);
|
|
345
323
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
this.screenSpaceEventHandler.setInputAction(
|
|
349
|
-
this.event[eventType],
|
|
350
|
-
Cesium.ScreenSpaceEventType.LEFT_CLICK
|
|
351
|
-
);
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
324
|
+
}
|
|
354
325
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* 销毁要素
|
|
329
|
+
* 从地图中移除并销毁要素
|
|
330
|
+
*/
|
|
331
|
+
destroy(): void {
|
|
332
|
+
// 清理所有事件监听器
|
|
333
|
+
Object.keys(this.event).forEach((eventType) => {
|
|
334
|
+
this.off(eventType);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
this.clearPopupState();
|
|
338
|
+
|
|
339
|
+
if (this.graphic && this.hnMap && this.hnMap.map) {
|
|
340
|
+
try {
|
|
341
|
+
// 从地图实体集合中移除
|
|
342
|
+
if (this.hnMap.map.entities) {
|
|
343
|
+
this.hnMap.map.entities.remove(this.graphic);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// 如果是数据源中的实体
|
|
347
|
+
if (this.graphic.dataSource) {
|
|
348
|
+
this.graphic.dataSource.entities.remove(this.graphic);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.graphic = null;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error("销毁实体失败:", error);
|
|
354
|
+
}
|
|
370
355
|
}
|
|
371
|
-
|
|
372
|
-
console.warn("移除事件监听失败:", error);
|
|
373
|
-
}
|
|
356
|
+
}
|
|
374
357
|
|
|
375
|
-
|
|
358
|
+
/**
|
|
359
|
+
* 监听事件
|
|
360
|
+
* @param eventType 事件类型
|
|
361
|
+
* @param callback 事件回调函数
|
|
362
|
+
*/
|
|
363
|
+
on(eventType: string, callback: (data: any) => void): void {
|
|
364
|
+
this.off(eventType);
|
|
365
|
+
|
|
366
|
+
if (!this.graphic || !this.hnMap?.map?.map) return;
|
|
367
|
+
|
|
368
|
+
if (eventType === "click") {
|
|
369
|
+
// 包装回调(与之前一致)
|
|
370
|
+
const handler = (movement: any) => {
|
|
371
|
+
const data = this.option?.data || {};
|
|
372
|
+
callback(data);
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// 存储以便 off 使用
|
|
376
|
+
this._userClickHandler = handler;
|
|
377
|
+
|
|
378
|
+
// 添加到回调数组
|
|
379
|
+
if (!this.hnMap.map.entityClickHandlers.has(this.graphic)) {
|
|
380
|
+
this.hnMap.map.entityClickHandlers.set(this.graphic, []);
|
|
381
|
+
}
|
|
382
|
+
this.hnMap.map.entityClickHandlers.get(this.graphic)!.push(handler);
|
|
383
|
+
this.event[eventType] = handler;
|
|
384
|
+
}
|
|
385
|
+
// 其他事件类型(如 mouseover)暂不处理,或按需扩展
|
|
376
386
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* 移除事件监听
|
|
390
|
+
* @param eventType 事件类型
|
|
391
|
+
*/
|
|
392
|
+
off(eventType: string): void {
|
|
393
|
+
if (eventType === 'click' && this._userClickHandler && this.graphic && this.hnMap?.map?.map) {
|
|
394
|
+
const handlers = this.hnMap.map.entityClickHandlers.get(this.graphic);
|
|
395
|
+
if (handlers) {
|
|
396
|
+
const index = handlers.indexOf(this._userClickHandler);
|
|
397
|
+
if (index !== -1) {
|
|
398
|
+
handlers.splice(index, 1);
|
|
399
|
+
if (handlers.length === 0) {
|
|
400
|
+
this.hnMap.map.entityClickHandlers.delete(this.graphic);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
this._userClickHandler = null;
|
|
405
|
+
}
|
|
396
406
|
}
|
|
397
|
-
}
|
|
398
407
|
|
|
399
408
|
}
|