@hzab/map-combine 0.3.0-beta1 → 0.3.1-alpha.1
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 -1
- package/package.json +9 -2
- package/src/amap/AMap.ts +58 -6
- package/src/cesium/CesiumMap.ts +341 -341
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzab/map-combine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1-alpha.1",
|
|
4
4
|
"description": "地图组件",
|
|
5
5
|
"main": "src",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "npm run prepare && webpack serve -c ./config/webpack.config.js --env local",
|
|
8
8
|
"build": "webpack -c ./config/webpack.config.js --env production",
|
|
9
|
-
"
|
|
9
|
+
"version:alpha": "npm version prerelease --preid=alpha",
|
|
10
|
+
"publish:alpha": "npm publish --tag alpha",
|
|
11
|
+
"version:beta": "npm version prerelease --preid=beta",
|
|
12
|
+
"publish:beta": "npm publish --tag beta",
|
|
13
|
+
"version:patch": "npm version patch",
|
|
14
|
+
"version:minior": "npm version minor",
|
|
15
|
+
"version:major": "npm version major",
|
|
16
|
+
"publish:stable": "npm publish --access public",
|
|
10
17
|
"publish-patch": "npm version patch && npm publish --access public",
|
|
11
18
|
"publish-minor": "npm version minor && npm publish --access public",
|
|
12
19
|
"publish-major": "npm version major && npm publish --access public",
|
package/src/amap/AMap.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { drawPolyline } from "./AMapPolyline";
|
|
|
12
12
|
import { drawPolygon } from "./AMapPolygon";
|
|
13
13
|
|
|
14
14
|
export interface IAMapOption {
|
|
15
|
-
container;
|
|
15
|
+
container: HTMLDivElement;
|
|
16
16
|
url?: string | string[];
|
|
17
17
|
center?: number[];
|
|
18
18
|
zoom?: number;
|
|
@@ -26,6 +26,10 @@ export interface IAMapOption {
|
|
|
26
26
|
securityJsCode: string;
|
|
27
27
|
/** 加载的插件列表 */
|
|
28
28
|
plugins?: [string];
|
|
29
|
+
/** loader 配置参数 */
|
|
30
|
+
loaderOpt?: Object;
|
|
31
|
+
/** 地图初始化 配置参数 */
|
|
32
|
+
mapOpt?: Object;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
export interface IFlyToViewerOpt {
|
|
@@ -37,16 +41,24 @@ export interface IFlyToViewerOpt {
|
|
|
37
41
|
* (Array<number> = [0,0,0,0]) 距离边框的内边距,顺序:上、下、左、右
|
|
38
42
|
*/
|
|
39
43
|
avoid?: [number, number, number, number];
|
|
44
|
+
/**
|
|
45
|
+
* 最大缩放级别
|
|
46
|
+
*/
|
|
47
|
+
maxZoom?: number;
|
|
48
|
+
/**
|
|
49
|
+
* 动画时间
|
|
50
|
+
*/
|
|
51
|
+
duration?: number;
|
|
40
52
|
}
|
|
41
53
|
|
|
42
54
|
export class AMap extends MapCombine {
|
|
43
55
|
viewer: any;
|
|
44
|
-
container: HTMLDivElement;
|
|
45
|
-
option;
|
|
56
|
+
container: HTMLDivElement = null;
|
|
57
|
+
option: any = {};
|
|
46
58
|
offset: number[];
|
|
47
59
|
fov = 0.9272952180016121;
|
|
48
60
|
isFromLonLat = true;
|
|
49
|
-
LbsAMap;
|
|
61
|
+
LbsAMap: any;
|
|
50
62
|
get cursor(): string {
|
|
51
63
|
return this.container.style.cursor;
|
|
52
64
|
}
|
|
@@ -108,6 +120,7 @@ export class AMap extends MapCombine {
|
|
|
108
120
|
|
|
109
121
|
this.loadPromise = new Promise((resolve, reject) => {
|
|
110
122
|
AMapLoader({
|
|
123
|
+
...opt.loaderOpt,
|
|
111
124
|
key,
|
|
112
125
|
securityJsCode,
|
|
113
126
|
plugins,
|
|
@@ -116,6 +129,7 @@ export class AMap extends MapCombine {
|
|
|
116
129
|
this.LbsAMap = LbsAMap;
|
|
117
130
|
let _urls = Array.isArray(url) ? url : [url];
|
|
118
131
|
this.viewer = new LbsAMap.Map(container, {
|
|
132
|
+
...opt.mapOpt,
|
|
119
133
|
zoom: zoom || 14,
|
|
120
134
|
center: center || [120.160217, 30.243861],
|
|
121
135
|
doubleClickZoom: false,
|
|
@@ -237,12 +251,50 @@ export class AMap extends MapCombine {
|
|
|
237
251
|
*/
|
|
238
252
|
flyToViewer(points: number[][], opt: IFlyToViewerOpt = { avoid: [0, 0, 0, 0], immediately: true }): void {
|
|
239
253
|
this.loadPromise.then(() => {
|
|
240
|
-
this.viewer.
|
|
254
|
+
const [zoom, center] = this.viewer.getFitZoomAndCenterByBounds(
|
|
241
255
|
this.getBounds(points, { canvas: this.viewer.canvas, ...opt }),
|
|
242
|
-
opt?.immediately,
|
|
243
256
|
opt?.avoid,
|
|
257
|
+
opt.maxZoom,
|
|
244
258
|
);
|
|
259
|
+
|
|
260
|
+
this.viewer.setZoomAndCenter(zoom, center, opt?.immediately, opt?.duration);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 将点集视野调整至容器内,支持相对边距(百分比)
|
|
266
|
+
* @param {number[][]} points - 经纬度数组 [[lng, lat], ...]
|
|
267
|
+
* @param {Object} opt
|
|
268
|
+
* @param {number[]} opt.avoid - 相对边距 [上, 下, 左, 右],取值范围 0~1,默认 [0,0,0,0]
|
|
269
|
+
* @param {boolean} opt.immediately - 是否立即跳转,默认 false(带动画)
|
|
270
|
+
*/
|
|
271
|
+
flyToViewerPercent(points: number[][], opt = { avoid: [0, 0, 0, 0], immediately: false }) {
|
|
272
|
+
if (!points?.length) return;
|
|
273
|
+
|
|
274
|
+
// 计算原始经纬度范围
|
|
275
|
+
let west = Infinity,
|
|
276
|
+
east = -Infinity,
|
|
277
|
+
south = Infinity,
|
|
278
|
+
north = -Infinity;
|
|
279
|
+
points.forEach(([lng, lat]) => {
|
|
280
|
+
west = Math.min(west, lng);
|
|
281
|
+
east = Math.max(east, lng);
|
|
282
|
+
south = Math.min(south, lat);
|
|
283
|
+
north = Math.max(north, lat);
|
|
245
284
|
});
|
|
285
|
+
|
|
286
|
+
// 应用相对边距
|
|
287
|
+
const [top, bottom, left, right] = opt.avoid;
|
|
288
|
+
const lngSpan = east - west;
|
|
289
|
+
const latSpan = north - south;
|
|
290
|
+
|
|
291
|
+
const bounds = this.LbsAMap.Bounds(
|
|
292
|
+
[west - lngSpan * left, south - latSpan * bottom],
|
|
293
|
+
[east + lngSpan * right, north + latSpan * top],
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
this.viewer.setBounds(bounds, opt.immediately);
|
|
246
297
|
}
|
|
298
|
+
|
|
247
299
|
flyTo() {}
|
|
248
300
|
}
|
package/src/cesium/CesiumMap.ts
CHANGED
|
@@ -1,341 +1,341 @@
|
|
|
1
|
-
import { AMapImageryProvider } from "./cesium-tile-covert";
|
|
2
|
-
|
|
3
|
-
import { MapCombine } from "../basic/MapCombine";
|
|
4
|
-
import { PointOption, Point } from "../basic/Point";
|
|
5
|
-
import { PolygonOption, Polygon } from "../basic/Polygon";
|
|
6
|
-
import { PolylineOption, Polyline } from "../basic/Polyline";
|
|
7
|
-
import { Tile3DOption, Tile3D } from "../basic/Tile3D";
|
|
8
|
-
|
|
9
|
-
import { bindEvent } from "./CesiumEvent";
|
|
10
|
-
import { drawPoint } from "./CesiumPoint";
|
|
11
|
-
import { drawPolygon } from "./CesiumPolygon";
|
|
12
|
-
import { drawPolyline } from "./CesiumPolyline";
|
|
13
|
-
import { drawTile3D } from "./CesiumTile3D";
|
|
14
|
-
|
|
15
|
-
const $m = 20037508.34278924;
|
|
16
|
-
/**
|
|
17
|
-
* flyToViewer 最小判断半径(米)
|
|
18
|
-
*/
|
|
19
|
-
const MIN_RADIUS = 500;
|
|
20
|
-
/**
|
|
21
|
-
* flyToViewer 最大缩放层级
|
|
22
|
-
*/
|
|
23
|
-
const MAX_ZOOM = 18;
|
|
24
|
-
|
|
25
|
-
export class CesiumMap extends MapCombine {
|
|
26
|
-
viewer: any;
|
|
27
|
-
markers: any;
|
|
28
|
-
option;
|
|
29
|
-
|
|
30
|
-
container: HTMLDivElement;
|
|
31
|
-
|
|
32
|
-
get cursor(): string {
|
|
33
|
-
return this.container.style.cursor;
|
|
34
|
-
}
|
|
35
|
-
set cursor(val: string) {
|
|
36
|
-
this.container.style.cursor = val;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get moveable(): boolean {
|
|
40
|
-
return this.viewer.scene.screenSpaceCameraController.enableRotate;
|
|
41
|
-
}
|
|
42
|
-
set moveable(val: boolean) {
|
|
43
|
-
this.viewer.scene.screenSpaceCameraController.enableRotate = val;
|
|
44
|
-
}
|
|
45
|
-
get center(): number[] {
|
|
46
|
-
const { viewer, container } = this;
|
|
47
|
-
const width = container.offsetWidth;
|
|
48
|
-
const height = container.offsetHeight;
|
|
49
|
-
const position = viewer.scene.camera.pickEllipsoid(
|
|
50
|
-
new Cesium.Cartesian2(width / 2, height / 2),
|
|
51
|
-
viewer.scene.globe.ellipsoid,
|
|
52
|
-
);
|
|
53
|
-
const cartographic = Cesium.Cartographic.fromCartesian(position);
|
|
54
|
-
return [Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)];
|
|
55
|
-
}
|
|
56
|
-
set center(val: number[]) {
|
|
57
|
-
const { viewer, container } = this;
|
|
58
|
-
const width = container.offsetWidth;
|
|
59
|
-
const height = container.offsetHeight;
|
|
60
|
-
const position = viewer.scene.camera.pickEllipsoid(
|
|
61
|
-
new Cesium.Cartesian2(width / 2, height / 2),
|
|
62
|
-
viewer.scene.globe.ellipsoid,
|
|
63
|
-
);
|
|
64
|
-
const target = Cesium.Cartesian3.fromDegrees(...val);
|
|
65
|
-
Cesium.Cartesian3.subtract(target, position, target);
|
|
66
|
-
Cesium.Cartesian3.add(this.viewer.camera.position, target, this.viewer.camera.position);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
get zoom(): number {
|
|
70
|
-
const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
|
|
71
|
-
return this.distanceTzoom(cartographic.height);
|
|
72
|
-
}
|
|
73
|
-
set zoom(val: number) {
|
|
74
|
-
const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
|
|
75
|
-
cartographic.height = this.zoomTdistance(val);
|
|
76
|
-
this.viewer.camera.position = Cesium.Cartesian3.fromRadians(
|
|
77
|
-
cartographic.longitude,
|
|
78
|
-
cartographic.latitude,
|
|
79
|
-
cartographic.height,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
fov = 0.9695385667699215;
|
|
84
|
-
distanceTzoom(distance: number) {
|
|
85
|
-
const height = this.container.offsetHeight;
|
|
86
|
-
return Math.log2(($m * height) / (256 * Math.tan(this.fov / 2) * distance));
|
|
87
|
-
}
|
|
88
|
-
zoomTdistance(zoom: number): number {
|
|
89
|
-
const height = this.container.offsetHeight;
|
|
90
|
-
return ($m * height) / (256 * Math.tan(this.fov / 2) * Math.pow(2, zoom));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
constructor(viewer?: any) {
|
|
94
|
-
super();
|
|
95
|
-
this._initParamsEvent(viewer);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
init(opt) {
|
|
99
|
-
this.option = opt;
|
|
100
|
-
const { container, center = [120.2288892, 30.2349677, 0], zoom = 13, url } = opt || {};
|
|
101
|
-
const viewer = new Cesium.Viewer(container, {
|
|
102
|
-
vrButton: false,
|
|
103
|
-
// 检索
|
|
104
|
-
geocoder: false,
|
|
105
|
-
// home
|
|
106
|
-
homeButton: false,
|
|
107
|
-
// 切换3d地图
|
|
108
|
-
sceneModePicker: false,
|
|
109
|
-
// 底图切换按钮
|
|
110
|
-
baseLayerPicker: false,
|
|
111
|
-
// 问号
|
|
112
|
-
navigationHelpButton: false,
|
|
113
|
-
// 动画控制
|
|
114
|
-
animation: false,
|
|
115
|
-
// 版权信息
|
|
116
|
-
creditContainer: document.createElement("div"),
|
|
117
|
-
// 时间轴
|
|
118
|
-
timeline: false,
|
|
119
|
-
// 全屏按钮
|
|
120
|
-
fullscreenButton: false,
|
|
121
|
-
selectionIndicator: false,
|
|
122
|
-
// 打开动画
|
|
123
|
-
shouldAnimate: false,
|
|
124
|
-
infoBox: false,
|
|
125
|
-
// 只进行3d渲染,没有2d,2.5d,提高性能
|
|
126
|
-
scene3DOnly: true,
|
|
127
|
-
// 初始设置一个纯色瓦片,避免报错影响后续瓦片加载
|
|
128
|
-
imageryProvider: new Cesium.SingleTileImageryProvider({
|
|
129
|
-
url: createColorCanvas("#333"),
|
|
130
|
-
rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
|
|
131
|
-
}),
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// viewer.cesiumWidget.creditContainer.remove();
|
|
135
|
-
|
|
136
|
-
// viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
|
137
|
-
|
|
138
|
-
this._initParamsEvent(viewer);
|
|
139
|
-
|
|
140
|
-
// 处理瓦片
|
|
141
|
-
this._createLayer();
|
|
142
|
-
|
|
143
|
-
const map = this;
|
|
144
|
-
const d = Cesium.Cartesian3.fromDegrees(...center);
|
|
145
|
-
map.setView([d.x, d.y, d.z, 6.283185307179586, -1.5691285980481942, 0]);
|
|
146
|
-
map.center = center;
|
|
147
|
-
map.zoom = zoom;
|
|
148
|
-
|
|
149
|
-
return map;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
private _initParamsEvent(viewer) {
|
|
153
|
-
if (!viewer) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
this.viewer = viewer;
|
|
157
|
-
|
|
158
|
-
this.container = viewer?.container;
|
|
159
|
-
this.container.appendChild(this.htmllayer);
|
|
160
|
-
this.cursor = "default";
|
|
161
|
-
this.markers = this.viewer.scene.primitives.add(new Cesium.BillboardCollection());
|
|
162
|
-
|
|
163
|
-
bindEvent(this);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private _createLayer() {
|
|
167
|
-
const { url, subdomains, proj, minZoomLevel, maxZoomLevel } = this.option;
|
|
168
|
-
let layer: any;
|
|
169
|
-
let options = {
|
|
170
|
-
...this.option,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
switch (proj) {
|
|
174
|
-
case "GCJ02->WGS84":
|
|
175
|
-
options = {
|
|
176
|
-
...options,
|
|
177
|
-
crs: "WGS84", // 使用84坐标系,默认为:GCJ02
|
|
178
|
-
};
|
|
179
|
-
layer = this.viewer.imageryLayers.addImageryProvider(new AMapImageryProvider(options));
|
|
180
|
-
|
|
181
|
-
break;
|
|
182
|
-
default:
|
|
183
|
-
options = {
|
|
184
|
-
...options,
|
|
185
|
-
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
186
|
-
};
|
|
187
|
-
layer = this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider(options));
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
this.viewer.imageryLayers.add(layer);
|
|
192
|
-
|
|
193
|
-
return layer;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
getView() {
|
|
197
|
-
const { camera } = this.viewer;
|
|
198
|
-
return [camera.position.x, camera.position.y, camera.position.z, camera.heading, camera.pitch, camera.roll];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
setView(e: number[]) {
|
|
202
|
-
const { camera } = this.viewer;
|
|
203
|
-
camera.setView({
|
|
204
|
-
destination: new Cesium.Cartesian3(e[0], e[1], e[2]),
|
|
205
|
-
orientation: new Cesium.HeadingPitchRoll(e[3], e[4], e[5]),
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
createPoint<K>(option?: Partial<PointOption<K>>): Point<K> {
|
|
210
|
-
const e = new Point(this, option);
|
|
211
|
-
drawPoint(this, e);
|
|
212
|
-
return e;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
createPolyline<K>(option?: Partial<PolylineOption<K>>): Polyline<K> {
|
|
216
|
-
const e = new Polyline(this, option);
|
|
217
|
-
drawPolyline(this, e);
|
|
218
|
-
return e;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
createPolygon<K>(option?: Partial<PolygonOption<K>>): Polygon<K> {
|
|
222
|
-
const e = new Polygon(this, option);
|
|
223
|
-
drawPolygon(this, e);
|
|
224
|
-
return e;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
createTile3D(option?: Partial<Tile3DOption>): Tile3D {
|
|
228
|
-
const e = new Tile3D(this, option);
|
|
229
|
-
drawTile3D(this, e);
|
|
230
|
-
return e;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
canvasTgeography(p: number[]): number[] {
|
|
234
|
-
const { viewer } = this;
|
|
235
|
-
const cartesian2 = new Cesium.Cartesian2(...p);
|
|
236
|
-
const ray = viewer.camera.getPickRay(cartesian2);
|
|
237
|
-
const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
|
|
238
|
-
|
|
239
|
-
if (cartesian) {
|
|
240
|
-
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
|
|
241
|
-
return [
|
|
242
|
-
Cesium.Math.toDegrees(cartographic.longitude),
|
|
243
|
-
Cesium.Math.toDegrees(cartographic.latitude),
|
|
244
|
-
cartographic.height,
|
|
245
|
-
];
|
|
246
|
-
} else {
|
|
247
|
-
return [0, 0, 0];
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
geographyTcanvas(p: number[]): number[] {
|
|
251
|
-
const res = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, Cesium.Cartesian3.fromDegrees(...p));
|
|
252
|
-
if (!res) {
|
|
253
|
-
return [-1, -1];
|
|
254
|
-
}
|
|
255
|
-
return [res.x, res.y];
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* 所有点位移动至视口,调整位置及层级
|
|
260
|
-
* @param points
|
|
261
|
-
* @param opt
|
|
262
|
-
* @param {Array<number> = [0,0,0,0]} opt.avoid 距离边框的内边距,顺序:上、下、左、右
|
|
263
|
-
* @param {Array<number> = [0,0,0,0]} opt.minRadius flyToViewer 最小范围(米)
|
|
264
|
-
* @param {Array<number> = [0,0,0,0]} opt.maxZoom flyToViewer 最大缩放层级
|
|
265
|
-
*/
|
|
266
|
-
flyToViewer(
|
|
267
|
-
points,
|
|
268
|
-
opt = {
|
|
269
|
-
avoid: [0, 0, 0, 0],
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* flyToViewer 最小判断半径(米)
|
|
273
|
-
*/
|
|
274
|
-
minRadius: MIN_RADIUS,
|
|
275
|
-
/**
|
|
276
|
-
* flyToViewer 最大缩放层级
|
|
277
|
-
*/
|
|
278
|
-
maxZoom: MAX_ZOOM,
|
|
279
|
-
},
|
|
280
|
-
) {
|
|
281
|
-
if (points?.length === 0) {
|
|
282
|
-
return this.flyTo(points[0], opt);
|
|
283
|
-
}
|
|
284
|
-
// 创建矩形
|
|
285
|
-
const rectangle = Cesium.Rectangle.fromDegrees(
|
|
286
|
-
...this.getBounds(points, { canvas: this.viewer.scene.canvas, ...opt }),
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
// 将经纬度转换为笛卡尔坐标
|
|
290
|
-
const positions = points.map((coord) => {
|
|
291
|
-
return Cesium.Cartesian3.fromDegrees(coord[0], coord[1]);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// 计算所有点位的包围球
|
|
295
|
-
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
|
|
296
|
-
|
|
297
|
-
// 计算包围球半径
|
|
298
|
-
const radius = boundingSphere.radius;
|
|
299
|
-
|
|
300
|
-
let destination = rectangle;
|
|
301
|
-
// 点位距离小于指定范围使用固定高度
|
|
302
|
-
if (radius < MIN_RADIUS || (opt?.minRadius && radius < opt.minRadius)) {
|
|
303
|
-
const center = Cesium.Rectangle.center(rectangle);
|
|
304
|
-
destination = Cesium.Cartesian3.fromRadians(
|
|
305
|
-
center.longitude,
|
|
306
|
-
center.latitude,
|
|
307
|
-
this.zoomTdistance(opt?.maxZoom ?? MAX_ZOOM),
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// 设置相机视角
|
|
312
|
-
this.viewer.camera.flyTo({
|
|
313
|
-
destination,
|
|
314
|
-
...opt,
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* 移动点位到中心点
|
|
320
|
-
* @param point
|
|
321
|
-
*/
|
|
322
|
-
flyTo(point, opt = {}) {
|
|
323
|
-
// 设置相机视角
|
|
324
|
-
this.viewer.camera.flyTo({
|
|
325
|
-
destination: point,
|
|
326
|
-
...opt,
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function createColorCanvas(color) {
|
|
332
|
-
var width = 1,
|
|
333
|
-
height = 1;
|
|
334
|
-
var canvas = document.createElement("canvas");
|
|
335
|
-
canvas.width = width;
|
|
336
|
-
canvas.height = height;
|
|
337
|
-
var ctx = canvas.getContext("2d");
|
|
338
|
-
ctx.fillStyle = color;
|
|
339
|
-
ctx.fillRect(0, 0, width, height);
|
|
340
|
-
return canvas.toDataURL();
|
|
341
|
-
}
|
|
1
|
+
import { AMapImageryProvider } from "./cesium-tile-covert";
|
|
2
|
+
|
|
3
|
+
import { MapCombine } from "../basic/MapCombine";
|
|
4
|
+
import { PointOption, Point } from "../basic/Point";
|
|
5
|
+
import { PolygonOption, Polygon } from "../basic/Polygon";
|
|
6
|
+
import { PolylineOption, Polyline } from "../basic/Polyline";
|
|
7
|
+
import { Tile3DOption, Tile3D } from "../basic/Tile3D";
|
|
8
|
+
|
|
9
|
+
import { bindEvent } from "./CesiumEvent";
|
|
10
|
+
import { drawPoint } from "./CesiumPoint";
|
|
11
|
+
import { drawPolygon } from "./CesiumPolygon";
|
|
12
|
+
import { drawPolyline } from "./CesiumPolyline";
|
|
13
|
+
import { drawTile3D } from "./CesiumTile3D";
|
|
14
|
+
|
|
15
|
+
const $m = 20037508.34278924;
|
|
16
|
+
/**
|
|
17
|
+
* flyToViewer 最小判断半径(米)
|
|
18
|
+
*/
|
|
19
|
+
const MIN_RADIUS = 500;
|
|
20
|
+
/**
|
|
21
|
+
* flyToViewer 最大缩放层级
|
|
22
|
+
*/
|
|
23
|
+
const MAX_ZOOM = 18;
|
|
24
|
+
|
|
25
|
+
export class CesiumMap extends MapCombine {
|
|
26
|
+
viewer: any;
|
|
27
|
+
markers: any;
|
|
28
|
+
option;
|
|
29
|
+
|
|
30
|
+
container: HTMLDivElement;
|
|
31
|
+
|
|
32
|
+
get cursor(): string {
|
|
33
|
+
return this.container.style.cursor;
|
|
34
|
+
}
|
|
35
|
+
set cursor(val: string) {
|
|
36
|
+
this.container.style.cursor = val;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get moveable(): boolean {
|
|
40
|
+
return this.viewer.scene.screenSpaceCameraController.enableRotate;
|
|
41
|
+
}
|
|
42
|
+
set moveable(val: boolean) {
|
|
43
|
+
this.viewer.scene.screenSpaceCameraController.enableRotate = val;
|
|
44
|
+
}
|
|
45
|
+
get center(): number[] {
|
|
46
|
+
const { viewer, container } = this;
|
|
47
|
+
const width = container.offsetWidth;
|
|
48
|
+
const height = container.offsetHeight;
|
|
49
|
+
const position = viewer.scene.camera.pickEllipsoid(
|
|
50
|
+
new Cesium.Cartesian2(width / 2, height / 2),
|
|
51
|
+
viewer.scene.globe.ellipsoid,
|
|
52
|
+
);
|
|
53
|
+
const cartographic = Cesium.Cartographic.fromCartesian(position);
|
|
54
|
+
return [Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)];
|
|
55
|
+
}
|
|
56
|
+
set center(val: number[]) {
|
|
57
|
+
const { viewer, container } = this;
|
|
58
|
+
const width = container.offsetWidth;
|
|
59
|
+
const height = container.offsetHeight;
|
|
60
|
+
const position = viewer.scene.camera.pickEllipsoid(
|
|
61
|
+
new Cesium.Cartesian2(width / 2, height / 2),
|
|
62
|
+
viewer.scene.globe.ellipsoid,
|
|
63
|
+
);
|
|
64
|
+
const target = Cesium.Cartesian3.fromDegrees(...val);
|
|
65
|
+
Cesium.Cartesian3.subtract(target, position, target);
|
|
66
|
+
Cesium.Cartesian3.add(this.viewer.camera.position, target, this.viewer.camera.position);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get zoom(): number {
|
|
70
|
+
const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
|
|
71
|
+
return this.distanceTzoom(cartographic.height);
|
|
72
|
+
}
|
|
73
|
+
set zoom(val: number) {
|
|
74
|
+
const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
|
|
75
|
+
cartographic.height = this.zoomTdistance(val);
|
|
76
|
+
this.viewer.camera.position = Cesium.Cartesian3.fromRadians(
|
|
77
|
+
cartographic.longitude,
|
|
78
|
+
cartographic.latitude,
|
|
79
|
+
cartographic.height,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fov = 0.9695385667699215;
|
|
84
|
+
distanceTzoom(distance: number) {
|
|
85
|
+
const height = this.container.offsetHeight;
|
|
86
|
+
return Math.log2(($m * height) / (256 * Math.tan(this.fov / 2) * distance));
|
|
87
|
+
}
|
|
88
|
+
zoomTdistance(zoom: number): number {
|
|
89
|
+
const height = this.container.offsetHeight;
|
|
90
|
+
return ($m * height) / (256 * Math.tan(this.fov / 2) * Math.pow(2, zoom));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
constructor(viewer?: any) {
|
|
94
|
+
super();
|
|
95
|
+
this._initParamsEvent(viewer);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
init(opt) {
|
|
99
|
+
this.option = opt;
|
|
100
|
+
const { container, center = [120.2288892, 30.2349677, 0], zoom = 13, url } = opt || {};
|
|
101
|
+
const viewer = new Cesium.Viewer(container, {
|
|
102
|
+
vrButton: false,
|
|
103
|
+
// 检索
|
|
104
|
+
geocoder: false,
|
|
105
|
+
// home
|
|
106
|
+
homeButton: false,
|
|
107
|
+
// 切换3d地图
|
|
108
|
+
sceneModePicker: false,
|
|
109
|
+
// 底图切换按钮
|
|
110
|
+
baseLayerPicker: false,
|
|
111
|
+
// 问号
|
|
112
|
+
navigationHelpButton: false,
|
|
113
|
+
// 动画控制
|
|
114
|
+
animation: false,
|
|
115
|
+
// 版权信息
|
|
116
|
+
creditContainer: document.createElement("div"),
|
|
117
|
+
// 时间轴
|
|
118
|
+
timeline: false,
|
|
119
|
+
// 全屏按钮
|
|
120
|
+
fullscreenButton: false,
|
|
121
|
+
selectionIndicator: false,
|
|
122
|
+
// 打开动画
|
|
123
|
+
shouldAnimate: false,
|
|
124
|
+
infoBox: false,
|
|
125
|
+
// 只进行3d渲染,没有2d,2.5d,提高性能
|
|
126
|
+
scene3DOnly: true,
|
|
127
|
+
// 初始设置一个纯色瓦片,避免报错影响后续瓦片加载
|
|
128
|
+
imageryProvider: new Cesium.SingleTileImageryProvider({
|
|
129
|
+
url: createColorCanvas("#333"),
|
|
130
|
+
rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// viewer.cesiumWidget.creditContainer.remove();
|
|
135
|
+
|
|
136
|
+
// viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
|
137
|
+
|
|
138
|
+
this._initParamsEvent(viewer);
|
|
139
|
+
|
|
140
|
+
// 处理瓦片
|
|
141
|
+
this._createLayer();
|
|
142
|
+
|
|
143
|
+
const map = this;
|
|
144
|
+
const d = Cesium.Cartesian3.fromDegrees(...center);
|
|
145
|
+
map.setView([d.x, d.y, d.z, 6.283185307179586, -1.5691285980481942, 0]);
|
|
146
|
+
map.center = center;
|
|
147
|
+
map.zoom = zoom;
|
|
148
|
+
|
|
149
|
+
return map;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private _initParamsEvent(viewer) {
|
|
153
|
+
if (!viewer) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this.viewer = viewer;
|
|
157
|
+
|
|
158
|
+
this.container = viewer?.container;
|
|
159
|
+
this.container.appendChild(this.htmllayer);
|
|
160
|
+
this.cursor = "default";
|
|
161
|
+
this.markers = this.viewer.scene.primitives.add(new Cesium.BillboardCollection());
|
|
162
|
+
|
|
163
|
+
bindEvent(this);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private _createLayer() {
|
|
167
|
+
const { url, subdomains, proj, minZoomLevel, maxZoomLevel } = this.option;
|
|
168
|
+
let layer: any;
|
|
169
|
+
let options = {
|
|
170
|
+
...this.option,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
switch (proj) {
|
|
174
|
+
case "GCJ02->WGS84":
|
|
175
|
+
options = {
|
|
176
|
+
...options,
|
|
177
|
+
crs: "WGS84", // 使用84坐标系,默认为:GCJ02
|
|
178
|
+
};
|
|
179
|
+
layer = this.viewer.imageryLayers.addImageryProvider(new AMapImageryProvider(options));
|
|
180
|
+
|
|
181
|
+
break;
|
|
182
|
+
default:
|
|
183
|
+
options = {
|
|
184
|
+
...options,
|
|
185
|
+
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
186
|
+
};
|
|
187
|
+
layer = this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider(options));
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.viewer.imageryLayers.add(layer);
|
|
192
|
+
|
|
193
|
+
return layer;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getView() {
|
|
197
|
+
const { camera } = this.viewer;
|
|
198
|
+
return [camera.position.x, camera.position.y, camera.position.z, camera.heading, camera.pitch, camera.roll];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
setView(e: number[]) {
|
|
202
|
+
const { camera } = this.viewer;
|
|
203
|
+
camera.setView({
|
|
204
|
+
destination: new Cesium.Cartesian3(e[0], e[1], e[2]),
|
|
205
|
+
orientation: new Cesium.HeadingPitchRoll(e[3], e[4], e[5]),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
createPoint<K>(option?: Partial<PointOption<K>>): Point<K> {
|
|
210
|
+
const e = new Point(this, option);
|
|
211
|
+
drawPoint(this, e);
|
|
212
|
+
return e;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
createPolyline<K>(option?: Partial<PolylineOption<K>>): Polyline<K> {
|
|
216
|
+
const e = new Polyline(this, option);
|
|
217
|
+
drawPolyline(this, e);
|
|
218
|
+
return e;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
createPolygon<K>(option?: Partial<PolygonOption<K>>): Polygon<K> {
|
|
222
|
+
const e = new Polygon(this, option);
|
|
223
|
+
drawPolygon(this, e);
|
|
224
|
+
return e;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
createTile3D(option?: Partial<Tile3DOption>): Tile3D {
|
|
228
|
+
const e = new Tile3D(this, option);
|
|
229
|
+
drawTile3D(this, e);
|
|
230
|
+
return e;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
canvasTgeography(p: number[]): number[] {
|
|
234
|
+
const { viewer } = this;
|
|
235
|
+
const cartesian2 = new Cesium.Cartesian2(...p);
|
|
236
|
+
const ray = viewer.camera.getPickRay(cartesian2);
|
|
237
|
+
const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
|
|
238
|
+
|
|
239
|
+
if (cartesian) {
|
|
240
|
+
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
|
|
241
|
+
return [
|
|
242
|
+
Cesium.Math.toDegrees(cartographic.longitude),
|
|
243
|
+
Cesium.Math.toDegrees(cartographic.latitude),
|
|
244
|
+
cartographic.height,
|
|
245
|
+
];
|
|
246
|
+
} else {
|
|
247
|
+
return [0, 0, 0];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
geographyTcanvas(p: number[]): number[] {
|
|
251
|
+
const res = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, Cesium.Cartesian3.fromDegrees(...p));
|
|
252
|
+
if (!res) {
|
|
253
|
+
return [-1, -1];
|
|
254
|
+
}
|
|
255
|
+
return [res.x, res.y];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 所有点位移动至视口,调整位置及层级
|
|
260
|
+
* @param points
|
|
261
|
+
* @param opt
|
|
262
|
+
* @param {Array<number> = [0,0,0,0]} opt.avoid 距离边框的内边距,顺序:上、下、左、右
|
|
263
|
+
* @param {Array<number> = [0,0,0,0]} opt.minRadius flyToViewer 最小范围(米)
|
|
264
|
+
* @param {Array<number> = [0,0,0,0]} opt.maxZoom flyToViewer 最大缩放层级
|
|
265
|
+
*/
|
|
266
|
+
flyToViewer(
|
|
267
|
+
points,
|
|
268
|
+
opt = {
|
|
269
|
+
avoid: [0, 0, 0, 0],
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* flyToViewer 最小判断半径(米)
|
|
273
|
+
*/
|
|
274
|
+
minRadius: MIN_RADIUS,
|
|
275
|
+
/**
|
|
276
|
+
* flyToViewer 最大缩放层级
|
|
277
|
+
*/
|
|
278
|
+
maxZoom: MAX_ZOOM,
|
|
279
|
+
},
|
|
280
|
+
) {
|
|
281
|
+
if (points?.length === 0) {
|
|
282
|
+
return this.flyTo(points[0], opt);
|
|
283
|
+
}
|
|
284
|
+
// 创建矩形
|
|
285
|
+
const rectangle = Cesium.Rectangle.fromDegrees(
|
|
286
|
+
...this.getBounds(points, { canvas: this.viewer.scene.canvas, ...opt }),
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// 将经纬度转换为笛卡尔坐标
|
|
290
|
+
const positions = points.map((coord) => {
|
|
291
|
+
return Cesium.Cartesian3.fromDegrees(coord[0], coord[1]);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// 计算所有点位的包围球
|
|
295
|
+
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
|
|
296
|
+
|
|
297
|
+
// 计算包围球半径
|
|
298
|
+
const radius = boundingSphere.radius;
|
|
299
|
+
|
|
300
|
+
let destination = rectangle;
|
|
301
|
+
// 点位距离小于指定范围使用固定高度
|
|
302
|
+
if (radius < MIN_RADIUS || (opt?.minRadius && radius < opt.minRadius)) {
|
|
303
|
+
const center = Cesium.Rectangle.center(rectangle);
|
|
304
|
+
destination = Cesium.Cartesian3.fromRadians(
|
|
305
|
+
center.longitude,
|
|
306
|
+
center.latitude,
|
|
307
|
+
this.zoomTdistance(opt?.maxZoom ?? MAX_ZOOM),
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 设置相机视角
|
|
312
|
+
this.viewer.camera.flyTo({
|
|
313
|
+
destination,
|
|
314
|
+
...opt,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* 移动点位到中心点
|
|
320
|
+
* @param point
|
|
321
|
+
*/
|
|
322
|
+
flyTo(point, opt = {}) {
|
|
323
|
+
// 设置相机视角
|
|
324
|
+
this.viewer.camera.flyTo({
|
|
325
|
+
destination: point,
|
|
326
|
+
...opt,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function createColorCanvas(color) {
|
|
332
|
+
var width = 1,
|
|
333
|
+
height = 1;
|
|
334
|
+
var canvas = document.createElement("canvas");
|
|
335
|
+
canvas.width = width;
|
|
336
|
+
canvas.height = height;
|
|
337
|
+
var ctx = canvas.getContext("2d");
|
|
338
|
+
ctx.fillStyle = color;
|
|
339
|
+
ctx.fillRect(0, 0, width, height);
|
|
340
|
+
return canvas.toDataURL();
|
|
341
|
+
}
|