@hzab/map-combine 0.4.2-alpha.3 → 0.4.2-alpha.5
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/CHANGELOG.md +1 -0
- package/package.json +4 -3
- package/src/amap/AMap.ts +313 -306
- package/src/amap/AMapPoint.ts +77 -89
- package/src/cesium/CesiumMap.ts +2 -32
- package/src/utils/index.ts +3 -0
- package/src/utils/points-viewer.ts +27 -1
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzab/map-combine",
|
|
3
|
-
"version": "0.4.2-alpha.
|
|
3
|
+
"version": "0.4.2-alpha.5",
|
|
4
4
|
"description": "地图组件",
|
|
5
5
|
"main": "src",
|
|
6
6
|
"scripts": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@amap/amap-jsapi-loader": "^1.0.1",
|
|
30
30
|
"@hzab/permissions": "0.1.1",
|
|
31
31
|
"@hzab/webpack-config": "^0.2.1",
|
|
32
|
-
"@turf/turf": "6.5",
|
|
32
|
+
"@turf/turf": "6.5.0",
|
|
33
33
|
"@types/amap-js-api": "^1.4.16",
|
|
34
34
|
"@types/react": "^17.0.62",
|
|
35
35
|
"@types/react-dom": "^17.0.20",
|
|
@@ -51,8 +51,9 @@
|
|
|
51
51
|
"lib": "lib"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@turf/turf": "6.5",
|
|
54
|
+
"@turf/turf": "6.5.0",
|
|
55
55
|
"coordtransform": "^2.1.2",
|
|
56
|
+
"nanoid": "^3.3.7",
|
|
56
57
|
"lodash": ">=4.17.21",
|
|
57
58
|
"react-dom": "^17.0.2",
|
|
58
59
|
"zrender": "^5.4.4"
|
package/src/amap/AMap.ts
CHANGED
|
@@ -1,306 +1,313 @@
|
|
|
1
|
-
import { MapCombine } from "../basic/MapCombine";
|
|
2
|
-
import { PointOption, Point } from "../basic/Point";
|
|
3
|
-
import { PointAggregationOption, PointAggregation } from "../basic/PointAggregation";
|
|
4
|
-
import { ReactPointOption, ReactPoint, drawReactPoint } from "../basic/ReactPoint";
|
|
5
|
-
import { PolylineOption, Polyline } from "../basic/Polyline";
|
|
6
|
-
import { PolygonOption, Polygon } from "../basic/Polygon";
|
|
7
|
-
import { Tile3DOption, Tile3D } from "../basic/Tile3D";
|
|
8
|
-
|
|
9
|
-
import AMapLoader from "./loader";
|
|
10
|
-
import { bindEvent } from "./AMapEvent";
|
|
11
|
-
import { drawPoint } from "./AMapPoint";
|
|
12
|
-
import { drawPolyline } from "./AMapPolyline";
|
|
13
|
-
import { drawPolygon } from "./AMapPolygon";
|
|
14
|
-
|
|
15
|
-
export interface IAMapOption {
|
|
16
|
-
container: HTMLDivElement;
|
|
17
|
-
url?: string | string[];
|
|
18
|
-
center?: number[];
|
|
19
|
-
zoom?: number;
|
|
20
|
-
maxZoom?: number;
|
|
21
|
-
minZoom?: number;
|
|
22
|
-
/** 地图瓦片转换规则 GCJ02 转 WGS84 */
|
|
23
|
-
proj?: "GCJ02->WGS84";
|
|
24
|
-
/** 高德地图 key */
|
|
25
|
-
key: string;
|
|
26
|
-
/** 高德地图 securityJsCode */
|
|
27
|
-
securityJsCode: string;
|
|
28
|
-
/** 加载的插件列表 */
|
|
29
|
-
plugins?: [string];
|
|
30
|
-
/** loader 配置参数 */
|
|
31
|
-
loaderOpt?: Object;
|
|
32
|
-
/** 地图初始化 配置参数 */
|
|
33
|
-
mapOpt?: Object;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface IFlyToViewerOpt {
|
|
37
|
-
/**
|
|
38
|
-
* 立即缩放到指定位置
|
|
39
|
-
*/
|
|
40
|
-
immediately?: boolean;
|
|
41
|
-
/**
|
|
42
|
-
* (Array<number> = [0,0,0,0]) 距离边框的内边距,顺序:上、下、左、右
|
|
43
|
-
*/
|
|
44
|
-
avoid?: [number, number, number, number];
|
|
45
|
-
/**
|
|
46
|
-
* 最大缩放级别
|
|
47
|
-
*/
|
|
48
|
-
maxZoom?: number;
|
|
49
|
-
/**
|
|
50
|
-
* 动画时间
|
|
51
|
-
*/
|
|
52
|
-
duration?: number;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class AMap extends MapCombine {
|
|
56
|
-
viewer: any;
|
|
57
|
-
container: HTMLDivElement = null;
|
|
58
|
-
option: any = {};
|
|
59
|
-
offset: number[];
|
|
60
|
-
fov = 0.9272952180016121;
|
|
61
|
-
isFromLonLat = true;
|
|
62
|
-
LbsAMap: any;
|
|
63
|
-
get cursor(): string {
|
|
64
|
-
return this.container.style.cursor;
|
|
65
|
-
}
|
|
66
|
-
set cursor(val: string) {
|
|
67
|
-
this.container.style.cursor = val;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
get moveable(): boolean {
|
|
71
|
-
return this.viewer?.getStatus()?.dragEnable;
|
|
72
|
-
}
|
|
73
|
-
set moveable(val: boolean) {
|
|
74
|
-
this.viewer?.setStatus({ dragEnable: val });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.viewer?.
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return [
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return [
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
*
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
1
|
+
import { MapCombine } from "../basic/MapCombine";
|
|
2
|
+
import { PointOption, Point } from "../basic/Point";
|
|
3
|
+
import { PointAggregationOption, PointAggregation } from "../basic/PointAggregation";
|
|
4
|
+
import { ReactPointOption, ReactPoint, drawReactPoint } from "../basic/ReactPoint";
|
|
5
|
+
import { PolylineOption, Polyline } from "../basic/Polyline";
|
|
6
|
+
import { PolygonOption, Polygon } from "../basic/Polygon";
|
|
7
|
+
import { Tile3DOption, Tile3D } from "../basic/Tile3D";
|
|
8
|
+
|
|
9
|
+
import AMapLoader from "./loader";
|
|
10
|
+
import { bindEvent } from "./AMapEvent";
|
|
11
|
+
import { drawPoint } from "./AMapPoint";
|
|
12
|
+
import { drawPolyline } from "./AMapPolyline";
|
|
13
|
+
import { drawPolygon } from "./AMapPolygon";
|
|
14
|
+
|
|
15
|
+
export interface IAMapOption {
|
|
16
|
+
container: HTMLDivElement;
|
|
17
|
+
url?: string | string[];
|
|
18
|
+
center?: number[];
|
|
19
|
+
zoom?: number;
|
|
20
|
+
maxZoom?: number;
|
|
21
|
+
minZoom?: number;
|
|
22
|
+
/** 地图瓦片转换规则 GCJ02 转 WGS84 */
|
|
23
|
+
proj?: "GCJ02->WGS84";
|
|
24
|
+
/** 高德地图 key */
|
|
25
|
+
key: string;
|
|
26
|
+
/** 高德地图 securityJsCode */
|
|
27
|
+
securityJsCode: string;
|
|
28
|
+
/** 加载的插件列表 */
|
|
29
|
+
plugins?: [string];
|
|
30
|
+
/** loader 配置参数 */
|
|
31
|
+
loaderOpt?: Object;
|
|
32
|
+
/** 地图初始化 配置参数 */
|
|
33
|
+
mapOpt?: Object;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface IFlyToViewerOpt {
|
|
37
|
+
/**
|
|
38
|
+
* 立即缩放到指定位置
|
|
39
|
+
*/
|
|
40
|
+
immediately?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* (Array<number> = [0,0,0,0]) 距离边框的内边距,顺序:上、下、左、右
|
|
43
|
+
*/
|
|
44
|
+
avoid?: [number, number, number, number];
|
|
45
|
+
/**
|
|
46
|
+
* 最大缩放级别
|
|
47
|
+
*/
|
|
48
|
+
maxZoom?: number;
|
|
49
|
+
/**
|
|
50
|
+
* 动画时间
|
|
51
|
+
*/
|
|
52
|
+
duration?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class AMap extends MapCombine {
|
|
56
|
+
viewer: any;
|
|
57
|
+
container: HTMLDivElement = null;
|
|
58
|
+
option: any = {};
|
|
59
|
+
offset: number[];
|
|
60
|
+
fov = 0.9272952180016121;
|
|
61
|
+
isFromLonLat = true;
|
|
62
|
+
LbsAMap: any;
|
|
63
|
+
get cursor(): string {
|
|
64
|
+
return this.container.style.cursor;
|
|
65
|
+
}
|
|
66
|
+
set cursor(val: string) {
|
|
67
|
+
this.container.style.cursor = val;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get moveable(): boolean {
|
|
71
|
+
return this.viewer?.getStatus()?.dragEnable;
|
|
72
|
+
}
|
|
73
|
+
set moveable(val: boolean) {
|
|
74
|
+
this.viewer?.setStatus({ dragEnable: val });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
_center;
|
|
78
|
+
|
|
79
|
+
get center(): number[] {
|
|
80
|
+
return this.viewer?.getCenter();
|
|
81
|
+
}
|
|
82
|
+
set center(val: number[]) {
|
|
83
|
+
this._center = val;
|
|
84
|
+
this.viewer?.setCenter(val);
|
|
85
|
+
}
|
|
86
|
+
get zoom(): number {
|
|
87
|
+
return this.viewer?.getZoom();
|
|
88
|
+
}
|
|
89
|
+
set zoom(val: number) {
|
|
90
|
+
this.viewer?.setZoom(val);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
constructor(viewer = undefined) {
|
|
94
|
+
super();
|
|
95
|
+
viewer && this._initParamsEvent(viewer);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private _initParamsEvent(viewer) {
|
|
99
|
+
if (!viewer) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.viewer = viewer;
|
|
103
|
+
|
|
104
|
+
this.container = this.viewer.getContainer();
|
|
105
|
+
// this.markers = this.viewer.scene.primitives.add(new Cesium.BillboardCollection());
|
|
106
|
+
|
|
107
|
+
bindEvent(this);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
init(opt: IAMapOption) {
|
|
111
|
+
this.option = opt;
|
|
112
|
+
const {
|
|
113
|
+
container,
|
|
114
|
+
center = [120.2288892, 30.2349677, 0],
|
|
115
|
+
zoom = 13,
|
|
116
|
+
url,
|
|
117
|
+
maxZoom,
|
|
118
|
+
minZoom,
|
|
119
|
+
proj,
|
|
120
|
+
key,
|
|
121
|
+
securityJsCode,
|
|
122
|
+
plugins,
|
|
123
|
+
} = opt || {};
|
|
124
|
+
|
|
125
|
+
this.loadPromise = new Promise((resolve, reject) => {
|
|
126
|
+
AMapLoader({
|
|
127
|
+
...opt.loaderOpt,
|
|
128
|
+
key,
|
|
129
|
+
securityJsCode,
|
|
130
|
+
plugins,
|
|
131
|
+
})
|
|
132
|
+
.then((LbsAMap: any) => {
|
|
133
|
+
this.LbsAMap = LbsAMap;
|
|
134
|
+
let _urls = Array.isArray(url) ? url : [url];
|
|
135
|
+
this.viewer = new LbsAMap.Map(container, {
|
|
136
|
+
...opt.mapOpt,
|
|
137
|
+
zoom: zoom || 14,
|
|
138
|
+
// _center 解决异步初始化 导致设置 center 无效的问题
|
|
139
|
+
center: this._center || center || [120.160217, 30.243861],
|
|
140
|
+
doubleClickZoom: false,
|
|
141
|
+
zooms: minZoom && maxZoom && [minZoom, maxZoom],
|
|
142
|
+
layers: url
|
|
143
|
+
? _urls.map((it: any) => {
|
|
144
|
+
let opt = { tileUrl: "", getTileUrl: undefined };
|
|
145
|
+
if (typeof it === "string") {
|
|
146
|
+
opt.tileUrl = it;
|
|
147
|
+
} else {
|
|
148
|
+
opt = it;
|
|
149
|
+
}
|
|
150
|
+
// 使用 getTileUrl 解决接口地址强制改为 https 的问题
|
|
151
|
+
opt.getTileUrl = function (x, y, z) {
|
|
152
|
+
return opt.tileUrl.replace("{x}", x).replace("{y}", y).replace("{z}", z);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return new LbsAMap.TileLayer(opt);
|
|
156
|
+
})
|
|
157
|
+
: undefined,
|
|
158
|
+
});
|
|
159
|
+
this.viewer.on("complete", () => {
|
|
160
|
+
resolve(this);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
this._initParamsEvent(this.viewer);
|
|
164
|
+
return this;
|
|
165
|
+
})
|
|
166
|
+
.catch(reject);
|
|
167
|
+
});
|
|
168
|
+
this.loadPromise.then(() => {
|
|
169
|
+
this.container.appendChild(this.htmllayer);
|
|
170
|
+
});
|
|
171
|
+
return this.loadPromise;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
createPoint<K>(option?: Partial<PointOption<K>>): Point<K> {
|
|
175
|
+
const e = new Point(this, option);
|
|
176
|
+
this.loadPromise.then(() => {
|
|
177
|
+
drawPoint(this, e);
|
|
178
|
+
});
|
|
179
|
+
return e;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
createPointAggregation(option?: PointAggregationOption): PointAggregation {
|
|
183
|
+
const e = new PointAggregation(this, option);
|
|
184
|
+
return e;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
createReactPoint<K>(option?: Partial<ReactPointOption<K>>): ReactPoint<K> {
|
|
188
|
+
const e = new ReactPoint(this, option);
|
|
189
|
+
this.loadPromise.then(() => {
|
|
190
|
+
drawReactPoint(this, e);
|
|
191
|
+
});
|
|
192
|
+
return e;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
createPolyline<K>(option?: Partial<PolylineOption<K>>): Polyline<K> {
|
|
196
|
+
const e = new Polyline(this, option);
|
|
197
|
+
this.loadPromise.then(() => {
|
|
198
|
+
drawPolyline(this, e);
|
|
199
|
+
});
|
|
200
|
+
return e;
|
|
201
|
+
}
|
|
202
|
+
createPolygon<K>(option?: Partial<PolygonOption<K>>): Polygon<K> {
|
|
203
|
+
const e = new Polygon(this, option);
|
|
204
|
+
this.loadPromise.then(() => {
|
|
205
|
+
drawPolygon(this, e);
|
|
206
|
+
});
|
|
207
|
+
return e;
|
|
208
|
+
}
|
|
209
|
+
createTile3D(option?: Partial<Tile3DOption>): Tile3D {
|
|
210
|
+
throw new Error("Method not implemented.");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 将高德地图 Canvas 像素坐标转换为经纬度
|
|
215
|
+
* @param {Array} p - canvas 点位数组 [x, y]
|
|
216
|
+
* @returns {Array} p - 经纬度数组 [lng, lat]
|
|
217
|
+
*/
|
|
218
|
+
canvasTgeography(p: number[]) {
|
|
219
|
+
const mapInstance = this.viewer;
|
|
220
|
+
if (!mapInstance) {
|
|
221
|
+
this.loadPromise.then(() => {
|
|
222
|
+
this.canvasTgeography(p);
|
|
223
|
+
});
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const lngLat = this.viewer.lngLatToContainer(p);
|
|
228
|
+
return [lngLat.x, lngLat.y];
|
|
229
|
+
} catch (error) {
|
|
230
|
+
console.error("canvasPixelToLngLat 转换出错:", error);
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 经纬度转换为高德地图 Canvas 像素坐标
|
|
237
|
+
* @param {Array} p - 经纬度数组 [lng, lat]
|
|
238
|
+
* @returns {Array} Canvas 像素坐标 [x, y]
|
|
239
|
+
*/
|
|
240
|
+
geographyTcanvas(p: number[]): number[] {
|
|
241
|
+
const mapInstance = this.viewer;
|
|
242
|
+
if (!mapInstance) {
|
|
243
|
+
this.loadPromise.then(() => {
|
|
244
|
+
this.geographyTcanvas(p);
|
|
245
|
+
});
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const containerPixel = this.viewer.lngLatToContainer(p);
|
|
250
|
+
return [containerPixel.x, containerPixel.y];
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error("lngLatToCanvasPixel 转换出错:", error);
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* 所有点位移动至视口,调整位置及层级
|
|
258
|
+
* @param points
|
|
259
|
+
* @param opt
|
|
260
|
+
* @param {Array<number> = [0,0,0,0]} opt.avoid 距离边框的内边距,顺序:上、下、左、右
|
|
261
|
+
*/
|
|
262
|
+
flyToViewer(points: number[][], opt: IFlyToViewerOpt = { avoid: [0, 0, 0, 0], immediately: true }): void {
|
|
263
|
+
this.loadPromise.then(() => {
|
|
264
|
+
const [zoom, center] = this.viewer.getFitZoomAndCenterByBounds(
|
|
265
|
+
this.getBounds(points, { canvas: this.viewer.canvas, ...opt }),
|
|
266
|
+
opt?.avoid,
|
|
267
|
+
opt.maxZoom,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
this.viewer.setZoomAndCenter(zoom, center, opt?.immediately, opt?.duration);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* 将点集视野调整至容器内,支持相对边距(百分比)
|
|
276
|
+
* @param {number[][]} points - 经纬度数组 [[lng, lat], ...]
|
|
277
|
+
* @param {Object} opt
|
|
278
|
+
* @param {number[]} opt.avoid - 相对边距 [上, 下, 左, 右],取值范围 0~1,默认 [0,0,0,0]
|
|
279
|
+
* @param {boolean} opt.immediately - 是否立即跳转,默认 false(带动画)
|
|
280
|
+
*/
|
|
281
|
+
flyToViewerPercent(points: number[][], opt = { avoid: [0, 0, 0, 0], immediately: false }) {
|
|
282
|
+
if (!points?.length) return;
|
|
283
|
+
|
|
284
|
+
// 计算原始经纬度范围
|
|
285
|
+
let west = Infinity,
|
|
286
|
+
east = -Infinity,
|
|
287
|
+
south = Infinity,
|
|
288
|
+
north = -Infinity;
|
|
289
|
+
points.forEach(([lng, lat]) => {
|
|
290
|
+
west = Math.min(west, lng);
|
|
291
|
+
east = Math.max(east, lng);
|
|
292
|
+
south = Math.min(south, lat);
|
|
293
|
+
north = Math.max(north, lat);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// 应用相对边距
|
|
297
|
+
const [top, bottom, left, right] = opt.avoid;
|
|
298
|
+
const lngSpan = east - west;
|
|
299
|
+
const latSpan = north - south;
|
|
300
|
+
|
|
301
|
+
const bounds = this.LbsAMap.Bounds(
|
|
302
|
+
[west - lngSpan * left, south - latSpan * bottom],
|
|
303
|
+
[east + lngSpan * right, north + latSpan * top],
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
this.viewer.setBounds(bounds, opt.immediately);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
flyTo(point: number[], opt?: { immediately: false; duration: undefined }) {
|
|
310
|
+
const { immediately, duration } = opt || {};
|
|
311
|
+
this.viewer.setCenter(point, immediately, duration);
|
|
312
|
+
}
|
|
313
|
+
}
|
package/src/amap/AMapPoint.ts
CHANGED
|
@@ -1,89 +1,76 @@
|
|
|
1
1
|
import { Point } from "../basic/Point";
|
|
2
2
|
import { AMap } from "./AMap";
|
|
3
3
|
|
|
4
|
-
const RD = 0.017453292519943295;
|
|
5
|
-
|
|
6
4
|
export function drawPoint(map: AMap, point: Point<unknown>) {
|
|
7
5
|
const { viewer, event, LbsAMap } = map;
|
|
8
6
|
let status = 0;
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
point.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
onPointerUp() {
|
|
31
|
-
if (point.editable && status == 3) {
|
|
32
|
-
status = 2;
|
|
33
|
-
map.moveable = true;
|
|
34
|
-
point.coordinates = [event.geography[0], event.geography[1], point.coordinates[2] ?? point.height];
|
|
35
|
-
point.event.trigger("data-update");
|
|
36
|
-
}
|
|
7
|
+
let skip = 0;
|
|
8
|
+
|
|
9
|
+
const { size, center } = point;
|
|
10
|
+
const pointOffset = [-size[0] * center[0], -size[1] * center[1]];
|
|
11
|
+
const marker = new LbsAMap.Marker({
|
|
12
|
+
position: new LbsAMap.LngLat(0, 0),
|
|
13
|
+
height: point.height,
|
|
14
|
+
title: point._option.name,
|
|
15
|
+
icon: new LbsAMap.Icon({
|
|
16
|
+
image: point.src,
|
|
17
|
+
size: point.size,
|
|
18
|
+
imageSize: point.size,
|
|
19
|
+
}),
|
|
20
|
+
angle: point.rotation,
|
|
21
|
+
anchor: point.center,
|
|
22
|
+
draggable: point.editable,
|
|
23
|
+
extData: {
|
|
24
|
+
cursor: point.cursor,
|
|
25
|
+
silent: point.silent,
|
|
37
26
|
},
|
|
38
|
-
|
|
27
|
+
offset: pointOffset,
|
|
28
|
+
});
|
|
29
|
+
setIcon();
|
|
30
|
+
viewer.add([marker]);
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
if (point.coordinates) {
|
|
33
|
+
status = 2;
|
|
34
|
+
marker.setPosition(point.coordinates);
|
|
35
|
+
if (point.show) {
|
|
36
|
+
marker.show();
|
|
37
|
+
} else {
|
|
38
|
+
marker.hide();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
46
41
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
bindEvent(marker);
|
|
65
|
-
viewer.add([marker]);
|
|
42
|
+
const onMouseMove = () => {
|
|
43
|
+
switch (status) {
|
|
44
|
+
case 0:
|
|
45
|
+
status = 1;
|
|
46
|
+
marker.setPosition(event.geography);
|
|
47
|
+
if (point.show) {
|
|
48
|
+
marker.show();
|
|
49
|
+
} else {
|
|
50
|
+
marker.hide();
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
case 1:
|
|
54
|
+
case 3:
|
|
55
|
+
marker.setPosition(event.geography);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
66
58
|
};
|
|
67
59
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
const onClick = () => {
|
|
61
|
+
if (status == 1) {
|
|
62
|
+
status = 2;
|
|
63
|
+
skip++;
|
|
64
|
+
point.coordinates = event.geography;
|
|
65
|
+
point.event.trigger("pointer-in");
|
|
66
|
+
}
|
|
74
67
|
};
|
|
75
68
|
|
|
76
|
-
if (point.coordinates) {
|
|
77
|
-
darwMarker({
|
|
78
|
-
position: new LbsAMap.LngLat(point.coordinates[0], point.coordinates[1]),
|
|
79
|
-
height: point.coordinates[2] ?? point.height,
|
|
80
|
-
});
|
|
81
|
-
} else {
|
|
82
|
-
viewer.on("click", eventMarker);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
69
|
const onUpdate = (e: Set<string>) => {
|
|
86
|
-
|
|
70
|
+
if (skip) {
|
|
71
|
+
skip--;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
87
74
|
e.forEach((key) => {
|
|
88
75
|
switch (key) {
|
|
89
76
|
case "show":
|
|
@@ -110,40 +97,41 @@ export function drawPoint(map: AMap, point: Point<unknown>) {
|
|
|
110
97
|
}
|
|
111
98
|
break;
|
|
112
99
|
case "src":
|
|
113
|
-
|
|
100
|
+
setIcon();
|
|
114
101
|
break;
|
|
115
102
|
case "size":
|
|
116
|
-
|
|
103
|
+
setIcon();
|
|
117
104
|
break;
|
|
118
105
|
case "center":
|
|
119
106
|
marker.setAnchor(point.center);
|
|
120
107
|
break;
|
|
121
108
|
case "rotation":
|
|
122
|
-
marker.setAngle(point.rotation
|
|
109
|
+
marker.setAngle(point.rotation);
|
|
123
110
|
break;
|
|
124
111
|
default:
|
|
125
112
|
throw new Error(`${key} 还不支持修改`);
|
|
126
113
|
}
|
|
127
114
|
});
|
|
128
|
-
|
|
129
|
-
keys.forEach((e) => {
|
|
130
|
-
switch (e) {
|
|
131
|
-
case "icon":
|
|
132
|
-
marker.setIcon(
|
|
133
|
-
new LbsAMap.Icon({
|
|
134
|
-
image: point.src,
|
|
135
|
-
size: point.size,
|
|
136
|
-
imageSize: point.size,
|
|
137
|
-
}),
|
|
138
|
-
);
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
115
|
};
|
|
143
116
|
|
|
117
|
+
function setIcon() {
|
|
118
|
+
marker.setIcon(
|
|
119
|
+
new LbsAMap.Icon({
|
|
120
|
+
image: point.src,
|
|
121
|
+
size: point.size,
|
|
122
|
+
imageSize: point.size,
|
|
123
|
+
}),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
144
127
|
const onDestroy = () => {
|
|
145
128
|
marker.remove();
|
|
146
129
|
point.event.off("update", onUpdate);
|
|
147
130
|
point.event.off("destroy", onDestroy);
|
|
148
131
|
};
|
|
132
|
+
|
|
133
|
+
event.on("pointer-move", onMouseMove);
|
|
134
|
+
event.on("left-click", onClick);
|
|
135
|
+
point.event.on("update", onUpdate);
|
|
136
|
+
point.event.on("destroy", onDestroy);
|
|
149
137
|
}
|
package/src/cesium/CesiumMap.ts
CHANGED
|
@@ -16,10 +16,6 @@ import { drawTile3D } from "./CesiumTile3D";
|
|
|
16
16
|
import { CesiumModel } from "./CesiumModel";
|
|
17
17
|
|
|
18
18
|
const $m = 20037508.34278924;
|
|
19
|
-
/**
|
|
20
|
-
* flyToViewer 最小判断半径(米)
|
|
21
|
-
*/
|
|
22
|
-
const MIN_RADIUS = 500;
|
|
23
19
|
/**
|
|
24
20
|
* flyToViewer 最大缩放层级
|
|
25
21
|
*/
|
|
@@ -280,10 +276,6 @@ export class CesiumMap extends MapCombine {
|
|
|
280
276
|
opt = {
|
|
281
277
|
avoid: [0, 0, 0, 0],
|
|
282
278
|
|
|
283
|
-
/**
|
|
284
|
-
* flyToViewer 最小判断半径(米)
|
|
285
|
-
*/
|
|
286
|
-
minRadius: MIN_RADIUS,
|
|
287
279
|
/**
|
|
288
280
|
* flyToViewer 最大缩放层级
|
|
289
281
|
*/
|
|
@@ -294,32 +286,10 @@ export class CesiumMap extends MapCombine {
|
|
|
294
286
|
return this.flyTo(points[0], opt);
|
|
295
287
|
}
|
|
296
288
|
// 创建矩形
|
|
297
|
-
const
|
|
298
|
-
...this.getBounds(points, { canvas: this.viewer.scene.canvas, ...opt }),
|
|
289
|
+
const destination = Cesium.Rectangle.fromDegrees(
|
|
290
|
+
...this.getBounds(points, { canvas: this.viewer.scene.canvas, maxZoom: MAX_ZOOM, ...opt }),
|
|
299
291
|
);
|
|
300
292
|
|
|
301
|
-
// 将经纬度转换为笛卡尔坐标
|
|
302
|
-
const positions = points.map((coord) => {
|
|
303
|
-
return Cesium.Cartesian3.fromDegrees(coord[0], coord[1]);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
// 计算所有点位的包围球
|
|
307
|
-
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
|
|
308
|
-
|
|
309
|
-
// 计算包围球半径
|
|
310
|
-
const radius = boundingSphere.radius;
|
|
311
|
-
|
|
312
|
-
let destination = rectangle;
|
|
313
|
-
// 点位距离小于指定范围使用固定高度
|
|
314
|
-
if (radius < MIN_RADIUS || (opt?.minRadius && radius < opt.minRadius)) {
|
|
315
|
-
const center = Cesium.Rectangle.center(rectangle);
|
|
316
|
-
destination = Cesium.Cartesian3.fromRadians(
|
|
317
|
-
center.longitude,
|
|
318
|
-
center.latitude,
|
|
319
|
-
this.zoomTdistance(opt?.maxZoom ?? MAX_ZOOM),
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
293
|
// 设置相机视角
|
|
324
294
|
this.viewer.camera.flyTo({
|
|
325
295
|
destination,
|
package/src/utils/index.ts
CHANGED
|
@@ -43,5 +43,31 @@ export const getBounds = function (points, opt) {
|
|
|
43
43
|
minLat -= avoid[1] * latPixelRatio;
|
|
44
44
|
maxLat += avoid[0] * latPixelRatio;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
// 根据 maxZoom 计算最小矩形范围
|
|
47
|
+
const minRange = getMinRangeFromZoom(opt.maxZoom);
|
|
48
|
+
const centerLon = (minLon + maxLon) / 2;
|
|
49
|
+
const centerLat = (minLat + maxLat) / 2;
|
|
50
|
+
|
|
51
|
+
// 确保矩形范围不小于最小值 解决点位距离过近导致异常缩放问题
|
|
52
|
+
let finalWest = Math.min(minLon, centerLon - minRange / 2);
|
|
53
|
+
let finalEast = Math.max(maxLon, centerLon + minRange / 2);
|
|
54
|
+
let finalSouth = Math.min(minLat, centerLat - minRange / 2);
|
|
55
|
+
let finalNorth = Math.max(maxLat, centerLat + minRange / 2);
|
|
56
|
+
|
|
57
|
+
return [finalWest, finalSouth, finalEast, finalNorth];
|
|
47
58
|
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 根据 maxZoom 计算出一个“最小”的经纬度跨度
|
|
62
|
+
* @param zoom
|
|
63
|
+
* @returns
|
|
64
|
+
*/
|
|
65
|
+
export function getMinRangeFromZoom(zoom) {
|
|
66
|
+
// 每个瓦片覆盖的经度范围
|
|
67
|
+
const lonPerTile = 360 / Math.pow(2, zoom);
|
|
68
|
+
// 每个瓦片覆盖的纬度范围(近似)
|
|
69
|
+
const latPerTile = 180 / Math.pow(2, zoom);
|
|
70
|
+
|
|
71
|
+
// 返回一个足够小的范围,比如一个瓦片范围的一半
|
|
72
|
+
return Math.max(lonPerTile, latPerTile) / 2;
|
|
73
|
+
}
|