@hzab/map-combine 0.4.2-alpha.4 → 0.4.2-alpha.6

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 CHANGED
@@ -6,6 +6,7 @@ break: PointAggregation datas 改为数组对象
6
6
  fix: cesium flyTo height 计算
7
7
  feat: map.bussinesses onFrame 事件回调
8
8
  fix: AmapPoint drawPoint 逻辑修复
9
+ feat: Cesium 线 首次加载优化
9
10
 
10
11
  # @hzab/map-combine@0.4.1
11
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/map-combine",
3
- "version": "0.4.2-alpha.4",
3
+ "version": "0.4.2-alpha.6",
4
4
  "description": "地图组件",
5
5
  "main": "src",
6
6
  "scripts": {
@@ -1,358 +1,328 @@
1
- import { AMapImageryProvider } from "./cesium-tile-covert";
2
-
3
- import { MapCombine } from "../basic/MapCombine";
4
- import { PointOption, Point } from "../basic/Point";
5
- import { PointAggregationOption, PointAggregation } from "../basic/PointAggregation";
6
- import { PolygonOption, Polygon } from "../basic/Polygon";
7
- import { PolylineOption, Polyline } from "../basic/Polyline";
8
- import { Tile3DOption, Tile3D } from "../basic/Tile3D";
9
- import { type BasicModelOption, type BasicModel } from "../basic/BasicModel";
10
-
11
- import { bindEvent } from "./CesiumEvent";
12
- import { drawPoint } from "./CesiumPoint";
13
- import { drawPolygon } from "./CesiumPolygon";
14
- import { drawPolyline } from "./CesiumPolyline";
15
- import { drawTile3D } from "./CesiumTile3D";
16
- import { CesiumModel } from "./CesiumModel";
17
-
18
- const $m = 20037508.34278924;
19
- /**
20
- * flyToViewer 最小判断半径(米)
21
- */
22
- const MIN_RADIUS = 500;
23
- /**
24
- * flyToViewer 最大缩放层级
25
- */
26
- const MAX_ZOOM = 18;
27
-
28
- export class CesiumMap extends MapCombine {
29
- viewer: any;
30
- markers: any;
31
- option;
32
-
33
- container: HTMLDivElement;
34
-
35
- get cursor(): string {
36
- return this.container.style.cursor;
37
- }
38
- set cursor(val: string) {
39
- this.container.style.cursor = val;
40
- }
41
-
42
- get moveable(): boolean {
43
- return this.viewer.scene.screenSpaceCameraController.enableRotate;
44
- }
45
- set moveable(val: boolean) {
46
- this.viewer.scene.screenSpaceCameraController.enableRotate = val;
47
- }
48
- get center(): number[] {
49
- const { viewer, container } = this;
50
- const width = container.offsetWidth;
51
- const height = container.offsetHeight;
52
- const position = viewer.scene.camera.pickEllipsoid(
53
- new Cesium.Cartesian2(width / 2, height / 2),
54
- viewer.scene.globe.ellipsoid,
55
- );
56
- const cartographic = Cesium.Cartographic.fromCartesian(position);
57
- return [Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)];
58
- }
59
- set center(val: number[]) {
60
- const { viewer, container } = this;
61
- const width = container.offsetWidth;
62
- const height = container.offsetHeight;
63
- const position = viewer.scene.camera.pickEllipsoid(
64
- new Cesium.Cartesian2(width / 2, height / 2),
65
- viewer.scene.globe.ellipsoid,
66
- );
67
- const target = Cesium.Cartesian3.fromDegrees(...val);
68
- Cesium.Cartesian3.subtract(target, position, target);
69
- Cesium.Cartesian3.add(this.viewer.camera.position, target, this.viewer.camera.position);
70
- }
71
-
72
- get zoom(): number {
73
- const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
74
- return this.distanceTzoom(cartographic.height);
75
- }
76
- set zoom(val: number) {
77
- const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
78
- cartographic.height = this.zoomTdistance(val);
79
- this.viewer.camera.position = Cesium.Cartesian3.fromRadians(
80
- cartographic.longitude,
81
- cartographic.latitude,
82
- cartographic.height,
83
- );
84
- }
85
-
86
- fov = 0.9695385667699215;
87
- distanceTzoom(distance: number) {
88
- const height = this.container.offsetHeight;
89
- return Math.log2(($m * height) / (256 * Math.tan(this.fov / 2) * distance));
90
- }
91
- zoomTdistance(zoom: number): number {
92
- const height = this.container.offsetHeight;
93
- return ($m * height) / (256 * Math.tan(this.fov / 2) * Math.pow(2, zoom));
94
- }
95
-
96
- constructor(viewer?: any) {
97
- super();
98
- this._initParamsEvent(viewer);
99
- }
100
-
101
- init(opt) {
102
- this.option = opt;
103
- const { container, center = [120.2288892, 30.2349677, 0], zoom = 13, url } = opt || {};
104
- const viewer = new Cesium.Viewer(container, {
105
- vrButton: false,
106
- // 检索
107
- geocoder: false,
108
- // home
109
- homeButton: false,
110
- // 切换3d地图
111
- sceneModePicker: false,
112
- // 底图切换按钮
113
- baseLayerPicker: false,
114
- // 问号
115
- navigationHelpButton: false,
116
- // 动画控制
117
- animation: false,
118
- // 版权信息
119
- creditContainer: document.createElement("div"),
120
- // 时间轴
121
- timeline: false,
122
- // 全屏按钮
123
- fullscreenButton: false,
124
- selectionIndicator: false,
125
- // 打开动画
126
- shouldAnimate: false,
127
- infoBox: false,
128
- // 只进行3d渲染,没有2d,2.5d,提高性能
129
- scene3DOnly: true,
130
- // 初始设置一个纯色瓦片,避免报错影响后续瓦片加载
131
- imageryProvider: new Cesium.SingleTileImageryProvider({
132
- url: createColorCanvas("#333"),
133
- rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
134
- }),
135
- });
136
-
137
- // viewer.cesiumWidget.creditContainer.remove();
138
-
139
- // viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
140
-
141
- this._initParamsEvent(viewer);
142
-
143
- // 处理瓦片
144
- this._createLayer();
145
-
146
- const map = this;
147
- const d = Cesium.Cartesian3.fromDegrees(...center);
148
- map.setView([d.x, d.y, d.z, 6.283185307179586, -1.5691285980481942, 0]);
149
- map.center = center;
150
- map.zoom = zoom;
151
-
152
- return map;
153
- }
154
-
155
- private _initParamsEvent(viewer) {
156
- if (!viewer) {
157
- return;
158
- }
159
- this.viewer = viewer;
160
-
161
- this.container = viewer?.container;
162
- this.container.appendChild(this.htmllayer);
163
- this.cursor = "default";
164
- this.markers = this.viewer.scene.primitives.add(new Cesium.BillboardCollection());
165
-
166
- bindEvent(this);
167
- }
168
-
169
- private _createLayer() {
170
- const { url, subdomains, proj, minZoomLevel, maxZoomLevel } = this.option;
171
- let layer: any;
172
- let options = {
173
- ...this.option,
174
- };
175
-
176
- switch (proj) {
177
- case "GCJ02->WGS84":
178
- options = {
179
- ...options,
180
- crs: "WGS84", // 使用84坐标系,默认为:GCJ02
181
- };
182
- layer = this.viewer.imageryLayers.addImageryProvider(new AMapImageryProvider(options));
183
-
184
- break;
185
- default:
186
- options = {
187
- ...options,
188
- tilingScheme: new Cesium.WebMercatorTilingScheme(),
189
- };
190
- layer = this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider(options));
191
- break;
192
- }
193
-
194
- this.viewer.imageryLayers.add(layer);
195
-
196
- return layer;
197
- }
198
-
199
- getView() {
200
- const { camera } = this.viewer;
201
- return [camera.position.x, camera.position.y, camera.position.z, camera.heading, camera.pitch, camera.roll];
202
- }
203
-
204
- setView(e: number[]) {
205
- const { camera } = this.viewer;
206
- camera.setView({
207
- destination: new Cesium.Cartesian3(e[0], e[1], e[2]),
208
- orientation: new Cesium.HeadingPitchRoll(e[3], e[4], e[5]),
209
- });
210
- }
211
-
212
- createPoint<K>(option?: Partial<PointOption<K>>): Point<K> {
213
- const e = new Point(this, option);
214
- drawPoint(this, e);
215
- return e;
216
- }
217
-
218
- createPointAggregation(option?: PointAggregationOption): PointAggregation {
219
- const e = new PointAggregation(this, option);
220
- return e;
221
- }
222
-
223
- createPolyline<K>(option?: Partial<PolylineOption<K>>): Polyline<K> {
224
- const e = new Polyline(this, option);
225
- drawPolyline(this, e);
226
- return e;
227
- }
228
-
229
- createPolygon<K>(option?: Partial<PolygonOption<K>>): Polygon<K> {
230
- const e = new Polygon(this, option);
231
- drawPolygon(this, e);
232
- return e;
233
- }
234
-
235
- createTile3D(option?: Partial<Tile3DOption>): Tile3D {
236
- const e = new Tile3D(this, option);
237
- drawTile3D(this, e);
238
- return e;
239
- }
240
-
241
- createModel(option?: Partial<BasicModelOption> | undefined): BasicModel {
242
- return new CesiumModel(this, option);
243
- }
244
-
245
- canvasTgeography(p: number[]): number[] {
246
- const { viewer } = this;
247
- const cartesian2 = new Cesium.Cartesian2(...p);
248
- const ray = viewer.camera.getPickRay(cartesian2);
249
- const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
250
-
251
- if (cartesian) {
252
- const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
253
- return [
254
- Cesium.Math.toDegrees(cartographic.longitude),
255
- Cesium.Math.toDegrees(cartographic.latitude),
256
- cartographic.height,
257
- ];
258
- } else {
259
- return [0, 0, 0];
260
- }
261
- }
262
- geographyTcanvas(p: number[]): number[] {
263
- const res = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, Cesium.Cartesian3.fromDegrees(...p));
264
- if (!res) {
265
- return [-1, -1];
266
- }
267
- return [res.x, res.y];
268
- }
269
-
270
- /**
271
- * 所有点位移动至视口,调整位置及层级
272
- * @param points
273
- * @param opt
274
- * @param {Array<number> = [0,0,0,0]} opt.avoid 距离边框的内边距,顺序:上、下、左、右
275
- * @param {Array<number> = [0,0,0,0]} opt.minRadius flyToViewer 最小范围(米)
276
- * @param {Array<number> = [0,0,0,0]} opt.maxZoom flyToViewer 最大缩放层级
277
- */
278
- flyToViewer(
279
- points,
280
- opt = {
281
- avoid: [0, 0, 0, 0],
282
-
283
- /**
284
- * flyToViewer 最小判断半径(米)
285
- */
286
- minRadius: MIN_RADIUS,
287
- /**
288
- * flyToViewer 最大缩放层级
289
- */
290
- maxZoom: MAX_ZOOM,
291
- },
292
- ) {
293
- if (points?.length === 0) {
294
- return this.flyTo(points[0], opt);
295
- }
296
- // 创建矩形
297
- const rectangle = Cesium.Rectangle.fromDegrees(
298
- ...this.getBounds(points, { canvas: this.viewer.scene.canvas, ...opt }),
299
- );
300
-
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
- // 设置相机视角
324
- this.viewer.camera.flyTo({
325
- destination,
326
- ...opt,
327
- });
328
- }
329
-
330
- /**
331
- * 移动点位到中心点
332
- * @param point
333
- */
334
- flyTo(point, opt = {}) {
335
- const height = this.zoomTdistance(this.zoom);
336
- // 取消任何正在进行的飞行,防止排队
337
- if (this.viewer.camera.cancelFlight) {
338
- this.viewer.camera.cancelFlight();
339
- }
340
- // 设置相机视角
341
- this.viewer.camera.flyTo({
342
- destination: Cesium.Cartesian3.fromDegrees(point[0], point[1], height),
343
- ...opt,
344
- });
345
- }
346
- }
347
-
348
- function createColorCanvas(color) {
349
- var width = 1,
350
- height = 1;
351
- var canvas = document.createElement("canvas");
352
- canvas.width = width;
353
- canvas.height = height;
354
- var ctx = canvas.getContext("2d");
355
- ctx.fillStyle = color;
356
- ctx.fillRect(0, 0, width, height);
357
- return canvas.toDataURL();
358
- }
1
+ import { AMapImageryProvider } from "./cesium-tile-covert";
2
+
3
+ import { MapCombine } from "../basic/MapCombine";
4
+ import { PointOption, Point } from "../basic/Point";
5
+ import { PointAggregationOption, PointAggregation } from "../basic/PointAggregation";
6
+ import { PolygonOption, Polygon } from "../basic/Polygon";
7
+ import { PolylineOption, Polyline } from "../basic/Polyline";
8
+ import { Tile3DOption, Tile3D } from "../basic/Tile3D";
9
+ import { type BasicModelOption, type BasicModel } from "../basic/BasicModel";
10
+
11
+ import { bindEvent } from "./CesiumEvent";
12
+ import { drawPoint } from "./CesiumPoint";
13
+ import { drawPolygon } from "./CesiumPolygon";
14
+ import { drawPolyline } from "./CesiumPolyline";
15
+ import { drawTile3D } from "./CesiumTile3D";
16
+ import { CesiumModel } from "./CesiumModel";
17
+
18
+ const $m = 20037508.34278924;
19
+ /**
20
+ * flyToViewer 最大缩放层级
21
+ */
22
+ const MAX_ZOOM = 18;
23
+
24
+ export class CesiumMap extends MapCombine {
25
+ viewer: any;
26
+ markers: any;
27
+ option;
28
+
29
+ container: HTMLDivElement;
30
+
31
+ get cursor(): string {
32
+ return this.container.style.cursor;
33
+ }
34
+ set cursor(val: string) {
35
+ this.container.style.cursor = val;
36
+ }
37
+
38
+ get moveable(): boolean {
39
+ return this.viewer.scene.screenSpaceCameraController.enableRotate;
40
+ }
41
+ set moveable(val: boolean) {
42
+ this.viewer.scene.screenSpaceCameraController.enableRotate = val;
43
+ }
44
+ get center(): number[] {
45
+ const { viewer, container } = this;
46
+ const width = container.offsetWidth;
47
+ const height = container.offsetHeight;
48
+ const position = viewer.scene.camera.pickEllipsoid(
49
+ new Cesium.Cartesian2(width / 2, height / 2),
50
+ viewer.scene.globe.ellipsoid,
51
+ );
52
+ const cartographic = Cesium.Cartographic.fromCartesian(position);
53
+ return [Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)];
54
+ }
55
+ set center(val: number[]) {
56
+ const { viewer, container } = this;
57
+ const width = container.offsetWidth;
58
+ const height = container.offsetHeight;
59
+ const position = viewer.scene.camera.pickEllipsoid(
60
+ new Cesium.Cartesian2(width / 2, height / 2),
61
+ viewer.scene.globe.ellipsoid,
62
+ );
63
+ const target = Cesium.Cartesian3.fromDegrees(...val);
64
+ Cesium.Cartesian3.subtract(target, position, target);
65
+ Cesium.Cartesian3.add(this.viewer.camera.position, target, this.viewer.camera.position);
66
+ }
67
+
68
+ get zoom(): number {
69
+ const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
70
+ return this.distanceTzoom(cartographic.height);
71
+ }
72
+ set zoom(val: number) {
73
+ const cartographic = Cesium.Cartographic.fromCartesian(this.viewer.camera.position);
74
+ cartographic.height = this.zoomTdistance(val);
75
+ this.viewer.camera.position = Cesium.Cartesian3.fromRadians(
76
+ cartographic.longitude,
77
+ cartographic.latitude,
78
+ cartographic.height,
79
+ );
80
+ }
81
+
82
+ fov = 0.9695385667699215;
83
+ distanceTzoom(distance: number) {
84
+ const height = this.container.offsetHeight;
85
+ return Math.log2(($m * height) / (256 * Math.tan(this.fov / 2) * distance));
86
+ }
87
+ zoomTdistance(zoom: number): number {
88
+ const height = this.container.offsetHeight;
89
+ return ($m * height) / (256 * Math.tan(this.fov / 2) * Math.pow(2, zoom));
90
+ }
91
+
92
+ constructor(viewer?: any) {
93
+ super();
94
+ this._initParamsEvent(viewer);
95
+ }
96
+
97
+ init(opt) {
98
+ this.option = opt;
99
+ const { container, center = [120.2288892, 30.2349677, 0], zoom = 13, url } = opt || {};
100
+ const viewer = new Cesium.Viewer(container, {
101
+ vrButton: false,
102
+ // 检索
103
+ geocoder: false,
104
+ // home
105
+ homeButton: false,
106
+ // 切换3d地图
107
+ sceneModePicker: false,
108
+ // 底图切换按钮
109
+ baseLayerPicker: false,
110
+ // 问号
111
+ navigationHelpButton: false,
112
+ // 动画控制
113
+ animation: false,
114
+ // 版权信息
115
+ creditContainer: document.createElement("div"),
116
+ // 时间轴
117
+ timeline: false,
118
+ // 全屏按钮
119
+ fullscreenButton: false,
120
+ selectionIndicator: false,
121
+ // 打开动画
122
+ shouldAnimate: false,
123
+ infoBox: false,
124
+ // 只进行3d渲染,没有2d,2.5d,提高性能
125
+ scene3DOnly: true,
126
+ // 初始设置一个纯色瓦片,避免报错影响后续瓦片加载
127
+ imageryProvider: new Cesium.SingleTileImageryProvider({
128
+ url: createColorCanvas("#333"),
129
+ rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
130
+ }),
131
+ });
132
+
133
+ // viewer.cesiumWidget.creditContainer.remove();
134
+
135
+ // viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
136
+
137
+ this._initParamsEvent(viewer);
138
+
139
+ // 处理瓦片
140
+ this._createLayer();
141
+
142
+ const map = this;
143
+ const d = Cesium.Cartesian3.fromDegrees(...center);
144
+ map.setView([d.x, d.y, d.z, 6.283185307179586, -1.5691285980481942, 0]);
145
+ map.center = center;
146
+ map.zoom = zoom;
147
+
148
+ return map;
149
+ }
150
+
151
+ private _initParamsEvent(viewer) {
152
+ if (!viewer) {
153
+ return;
154
+ }
155
+ this.viewer = viewer;
156
+
157
+ this.container = viewer?.container;
158
+ this.container.appendChild(this.htmllayer);
159
+ this.cursor = "default";
160
+ this.markers = this.viewer.scene.primitives.add(new Cesium.BillboardCollection());
161
+
162
+ bindEvent(this);
163
+ }
164
+
165
+ private _createLayer() {
166
+ const { url, subdomains, proj, minZoomLevel, maxZoomLevel } = this.option;
167
+ let layer: any;
168
+ let options = {
169
+ ...this.option,
170
+ };
171
+
172
+ switch (proj) {
173
+ case "GCJ02->WGS84":
174
+ options = {
175
+ ...options,
176
+ crs: "WGS84", // 使用84坐标系,默认为:GCJ02
177
+ };
178
+ layer = this.viewer.imageryLayers.addImageryProvider(new AMapImageryProvider(options));
179
+
180
+ break;
181
+ default:
182
+ options = {
183
+ ...options,
184
+ tilingScheme: new Cesium.WebMercatorTilingScheme(),
185
+ };
186
+ layer = this.viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider(options));
187
+ break;
188
+ }
189
+
190
+ this.viewer.imageryLayers.add(layer);
191
+
192
+ return layer;
193
+ }
194
+
195
+ getView() {
196
+ const { camera } = this.viewer;
197
+ return [camera.position.x, camera.position.y, camera.position.z, camera.heading, camera.pitch, camera.roll];
198
+ }
199
+
200
+ setView(e: number[]) {
201
+ const { camera } = this.viewer;
202
+ camera.setView({
203
+ destination: new Cesium.Cartesian3(e[0], e[1], e[2]),
204
+ orientation: new Cesium.HeadingPitchRoll(e[3], e[4], e[5]),
205
+ });
206
+ }
207
+
208
+ createPoint<K>(option?: Partial<PointOption<K>>): Point<K> {
209
+ const e = new Point(this, option);
210
+ drawPoint(this, e);
211
+ return e;
212
+ }
213
+
214
+ createPointAggregation(option?: PointAggregationOption): PointAggregation {
215
+ const e = new PointAggregation(this, option);
216
+ return e;
217
+ }
218
+
219
+ createPolyline<K>(option?: Partial<PolylineOption<K>>): Polyline<K> {
220
+ const e = new Polyline(this, option);
221
+ drawPolyline(this, e);
222
+ return e;
223
+ }
224
+
225
+ createPolygon<K>(option?: Partial<PolygonOption<K>>): Polygon<K> {
226
+ const e = new Polygon(this, option);
227
+ drawPolygon(this, e);
228
+ return e;
229
+ }
230
+
231
+ createTile3D(option?: Partial<Tile3DOption>): Tile3D {
232
+ const e = new Tile3D(this, option);
233
+ drawTile3D(this, e);
234
+ return e;
235
+ }
236
+
237
+ createModel(option?: Partial<BasicModelOption> | undefined): BasicModel {
238
+ return new CesiumModel(this, option);
239
+ }
240
+
241
+ canvasTgeography(p: number[]): number[] {
242
+ const { viewer } = this;
243
+ const cartesian2 = new Cesium.Cartesian2(...p);
244
+ const ray = viewer.camera.getPickRay(cartesian2);
245
+ const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
246
+
247
+ if (cartesian) {
248
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
249
+ return [
250
+ Cesium.Math.toDegrees(cartographic.longitude),
251
+ Cesium.Math.toDegrees(cartographic.latitude),
252
+ cartographic.height,
253
+ ];
254
+ } else {
255
+ return [0, 0, 0];
256
+ }
257
+ }
258
+ geographyTcanvas(p: number[]): number[] {
259
+ const res = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, Cesium.Cartesian3.fromDegrees(...p));
260
+ if (!res) {
261
+ return [-1, -1];
262
+ }
263
+ return [res.x, res.y];
264
+ }
265
+
266
+ /**
267
+ * 所有点位移动至视口,调整位置及层级
268
+ * @param points
269
+ * @param opt
270
+ * @param {Array<number> = [0,0,0,0]} opt.avoid 距离边框的内边距,顺序:上、下、左、右
271
+ * @param {Array<number> = [0,0,0,0]} opt.minRadius flyToViewer 最小范围(米)
272
+ * @param {Array<number> = [0,0,0,0]} opt.maxZoom flyToViewer 最大缩放层级
273
+ */
274
+ flyToViewer(
275
+ points,
276
+ opt = {
277
+ avoid: [0, 0, 0, 0],
278
+
279
+ /**
280
+ * flyToViewer 最大缩放层级
281
+ */
282
+ maxZoom: MAX_ZOOM,
283
+ },
284
+ ) {
285
+ if (points?.length === 0) {
286
+ return this.flyTo(points[0], opt);
287
+ }
288
+ // 创建矩形
289
+ const destination = Cesium.Rectangle.fromDegrees(
290
+ ...this.getBounds(points, { canvas: this.viewer.scene.canvas, maxZoom: MAX_ZOOM, ...opt }),
291
+ );
292
+
293
+ // 设置相机视角
294
+ this.viewer.camera.flyTo({
295
+ destination,
296
+ ...opt,
297
+ });
298
+ }
299
+
300
+ /**
301
+ * 移动点位到中心点
302
+ * @param point
303
+ */
304
+ flyTo(point, opt = {}) {
305
+ const height = this.zoomTdistance(this.zoom);
306
+ // 取消任何正在进行的飞行,防止排队
307
+ if (this.viewer.camera.cancelFlight) {
308
+ this.viewer.camera.cancelFlight();
309
+ }
310
+ // 设置相机视角
311
+ this.viewer.camera.flyTo({
312
+ destination: Cesium.Cartesian3.fromDegrees(point[0], point[1], height),
313
+ ...opt,
314
+ });
315
+ }
316
+ }
317
+
318
+ function createColorCanvas(color) {
319
+ var width = 1,
320
+ height = 1;
321
+ var canvas = document.createElement("canvas");
322
+ canvas.width = width;
323
+ canvas.height = height;
324
+ var ctx = canvas.getContext("2d");
325
+ ctx.fillStyle = color;
326
+ ctx.fillRect(0, 0, width, height);
327
+ return canvas.toDataURL();
328
+ }
@@ -14,6 +14,7 @@ czm_material czm_getMaterial(czm_materialInput materialInput){
14
14
  material.alpha = colorImage.a * color.a;
15
15
  return material;
16
16
  }`;
17
+
17
18
  function createLineMaterial(e: Polyline<unknown>) {
18
19
  if (e.icon || e.flow) {
19
20
  const material = new Cesium.Material({
@@ -99,25 +100,180 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
99
100
  },
100
101
  };
101
102
 
102
- let primitive: any;
103
103
  let cache: any[];
104
104
  let activeNode: ChainNode<any, any>;
105
- if (polyline.coordinates) {
106
- status = 2;
107
- cache = polyline.coordinates.map(geographyTcartesian3);
108
- primitive = new Cesium.Primitive({
109
- show: polyline.show,
110
- geometryInstances: new Cesium.GeometryInstance({
111
- geometry: new Cesium.PolylineGeometry({
112
- positions: cache,
105
+
106
+ let geometryInstance = null;
107
+ let primitive = null;
108
+ let currentPositions = [];
109
+ let isFirstRender = true;
110
+
111
+ /**
112
+ * 更新或创建线条几何体
113
+ * @param newPositions - 新的顶点数组
114
+ * @param forceRebuild 强制重建
115
+ */
116
+ function updatePrimitiveGeometry(newPositions, forceRebuild: boolean = false) {
117
+ // 验证数据有效性
118
+ if (!newPositions || newPositions.length < 2) {
119
+ if (primitive) {
120
+ viewer.scene.primitives.remove(primitive);
121
+ primitive = null;
122
+ geometryInstance = null;
123
+ }
124
+ currentPositions = [];
125
+ return;
126
+ }
127
+
128
+ // 强制重建,跳过检查
129
+ if (!forceRebuild && !isFirstRender) {
130
+ if (currentPositions.length === newPositions.length) {
131
+ let same = true;
132
+ for (let i = 0; i < newPositions.length; i++) {
133
+ const p1 = currentPositions[i];
134
+ const p2 = newPositions[i];
135
+ if (
136
+ !p1 ||
137
+ !p2 ||
138
+ Math.abs(p1.x - p2.x) > 1e-10 ||
139
+ Math.abs(p1.y - p2.y) > 1e-10 ||
140
+ Math.abs(p1.z - p2.z) > 1e-10
141
+ ) {
142
+ same = false;
143
+ break;
144
+ }
145
+ }
146
+ if (same) return;
147
+ }
148
+ }
149
+
150
+ // 创建新的几何体数据
151
+ let newGeometry: any = null;
152
+ try {
153
+ newGeometry = Cesium.PolylineGeometry.createGeometry(
154
+ new Cesium.PolylineGeometry({
155
+ positions: newPositions,
113
156
  width: polyline.lineWidth,
114
157
  vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT,
115
158
  }),
159
+ );
160
+ } catch (error) {
161
+ console.error("创建几何体失败:", error);
162
+ return;
163
+ }
164
+
165
+ if (!newGeometry) return;
166
+
167
+ // 复用或创建 Primitive
168
+ if (geometryInstance && primitive && !forceRebuild) {
169
+ // 复用几何体实例
170
+ try {
171
+ geometryInstance.geometry = newGeometry;
172
+ if (primitive._state !== undefined) {
173
+ primitive._state = Cesium.PrimitiveState.NEEDS_REBUILD;
174
+ }
175
+ if (primitive._boundingVolume) {
176
+ primitive._boundingVolume = undefined;
177
+ }
178
+ if (primitive._dirty !== undefined) {
179
+ primitive._dirty = true;
180
+ }
181
+ } catch (error) {
182
+ console.warn("复用 Primitive 失败,降级到重建:", error);
183
+ // 降级:重新创建
184
+ if (primitive) {
185
+ viewer.scene.primitives.remove(primitive);
186
+ primitive = null;
187
+ }
188
+ geometryInstance = new Cesium.GeometryInstance({
189
+ geometry: newGeometry,
190
+ id: _event,
191
+ });
192
+ primitive = new Cesium.Primitive({
193
+ show: polyline.show !== false,
194
+ asynchronous: false,
195
+ geometryInstances: geometryInstance,
196
+ appearance: appearance,
197
+ compressVertices: true,
198
+ releaseGeometryInstances: false,
199
+ });
200
+ viewer.scene.primitives.add(primitive);
201
+ }
202
+ // 复用 Primitive,只更新几何体数据(性能最优)
203
+ try {
204
+ // 直接替换几何体数据
205
+ geometryInstance.geometry = newGeometry;
206
+
207
+ // 关键:标记 Primitive 需要重建
208
+ // 在 Cesium 1.90.1 中,这些内部状态需要手动触发
209
+ if (primitive._state !== undefined) {
210
+ primitive._state = Cesium.PrimitiveState.NEEDS_REBUILD;
211
+ }
212
+
213
+ // 清除缓存的包围盒,强制重新计算
214
+ if (primitive._boundingVolume) {
215
+ primitive._boundingVolume = undefined;
216
+ }
217
+
218
+ // 标记为脏,触发重绘
219
+ if (primitive._dirty !== undefined) {
220
+ primitive._dirty = true;
221
+ }
222
+
223
+ // 对于某些版本,可能需要重新设置 geometryInstances
224
+ // primitive.geometryInstances = geometryInstance;
225
+ } catch (error) {
226
+ // 如果复用失败,降级到重建方案
227
+ console.warn("复用 Primitive 失败,降级到重建:", error);
228
+ forceRebuild = true;
229
+ }
230
+ }
231
+
232
+ // 强制重建或者首次创建,重新创建 Primitive
233
+ if (forceRebuild || !primitive || !geometryInstance) {
234
+ if (primitive) {
235
+ viewer.scene.primitives.remove(primitive);
236
+ primitive = null;
237
+ }
238
+
239
+ geometryInstance = new Cesium.GeometryInstance({
240
+ geometry: newGeometry,
116
241
  id: _event,
117
- }),
118
- appearance,
119
- });
120
- viewer.scene.primitives.add(primitive);
242
+ });
243
+
244
+ primitive = new Cesium.Primitive({
245
+ show: polyline.show !== false,
246
+ asynchronous: false,
247
+ geometryInstances: geometryInstance,
248
+ appearance: appearance,
249
+ compressVertices: true,
250
+ releaseGeometryInstances: false,
251
+ });
252
+
253
+ viewer.scene.primitives.add(primitive);
254
+ isFirstRender = false;
255
+ }
256
+
257
+ currentPositions = newPositions.slice();
258
+ }
259
+
260
+ function cleanupPrimitive() {
261
+ if (primitive) {
262
+ viewer.scene.primitives.remove(primitive);
263
+ primitive = null;
264
+ }
265
+ if (geometryInstance) {
266
+ geometryInstance = null;
267
+ }
268
+ currentPositions = [];
269
+ isFirstRender = true;
270
+ }
271
+
272
+ // 初始加载
273
+ if (polyline.coordinates) {
274
+ status = 2;
275
+ cache = polyline.coordinates.map(geographyTcartesian3);
276
+ updatePrimitiveGeometry(cache, true); // 强制重建
121
277
  }
122
278
 
123
279
  const editor = new PolylineEditor<any, any>();
@@ -180,8 +336,10 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
180
336
  markers.remove(n.shape);
181
337
  });
182
338
  editor.on("empty", () => {
183
- // markers.removeAll()
184
- viewer.scene.primitives.remove(primitive);
339
+ if (primitive) {
340
+ viewer.scene.primitives.remove(primitive);
341
+ primitive = null;
342
+ }
185
343
  status = 0;
186
344
  });
187
345
 
@@ -218,7 +376,6 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
218
376
  break;
219
377
  case "dash":
220
378
  keys.add("Material");
221
-
222
379
  break;
223
380
  default:
224
381
  throw new Error(`${key} 还不支持修改`);
@@ -229,14 +386,13 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
229
386
  case "Primitive":
230
387
  if (polyline.coordinates) {
231
388
  cache = polyline.coordinates.map((e) => geographyTcartesian3(e));
389
+ updatePrimitiveGeometry(cache, true); // 强制重建
232
390
  } else {
233
391
  cache = [];
234
392
  markers.removeAll();
235
393
  status = 0;
236
394
  }
237
-
238
395
  initPrimitive();
239
-
240
396
  break;
241
397
  case "Material":
242
398
  material = createLineMaterial(polyline);
@@ -254,6 +410,7 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
254
410
  break;
255
411
  }
256
412
  };
413
+
257
414
  let temp: any;
258
415
  const onMouseMove = () => {
259
416
  const e = event.geography;
@@ -262,13 +419,13 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
262
419
  case 1:
263
420
  cache.pop();
264
421
  cache.push(geographyTcartesian3(e));
265
- initPrimitive();
422
+ updatePrimitiveGeometry(cache); // 普通更新
266
423
  break;
267
424
  case 4:
268
425
  temp = geographyTcartesian3(e);
269
426
  activeNode.update([temp.x, temp.y, temp.z]);
270
427
  cache = editor.getCoordinates().map((e) => new Cesium.Cartesian3(...e));
271
- initPrimitive();
428
+ updatePrimitiveGeometry(cache, true); // 强制重建
272
429
  break;
273
430
  }
274
431
  };
@@ -284,38 +441,16 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
284
441
  break;
285
442
  case 1:
286
443
  cache.push(cache[cache.length - 1]);
287
- // geometry.setCoordinates(cache)
288
444
  initPrimitive();
289
445
  break;
290
446
  }
291
447
  };
292
448
 
293
449
  const initPrimitive = () => {
294
- primitive && viewer.scene.primitives.remove(primitive);
295
450
  if (cache.length > 1) {
296
- const geometry = Cesium.PolylineGeometry.createGeometry(
297
- new Cesium.PolylineGeometry({
298
- positions: cache,
299
- width: polyline.lineWidth,
300
- vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT,
301
- }),
302
- );
303
- if (geometry) {
304
- primitive = new Cesium.Primitive({
305
- show: polyline.show,
306
- asynchronous: false,
307
- geometryInstances: new Cesium.GeometryInstance({
308
- geometry,
309
- id: _event,
310
- }),
311
- appearance,
312
- });
313
- viewer.scene.primitives.add(primitive);
314
- } else {
315
- primitive = undefined;
316
- }
451
+ updatePrimitiveGeometry(cache, true); // 强制重建
317
452
  } else {
318
- primitive = undefined;
453
+ cleanupPrimitive();
319
454
  }
320
455
  };
321
456
 
@@ -326,7 +461,6 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
326
461
  skip++;
327
462
  cache.pop();
328
463
  cache.pop();
329
- // geometry.setCoordinates(cache)
330
464
  polyline.coordinates = cache.map((e) => cartesian3Tgeography(e));
331
465
  polyline.event.trigger("data-loaded");
332
466
  polyline.event.trigger("pointer-in");
@@ -348,8 +482,10 @@ export function drawPolyline(map: CesiumMap, polyline: Polyline<unknown>) {
348
482
  };
349
483
 
350
484
  const onDestroy = () => {
351
- primitive && viewer.scene.primitives.remove(primitive);
352
- viewer.scene.primitives.remove(markers);
485
+ cleanupPrimitive();
486
+ if (markers) {
487
+ viewer.scene.primitives.remove(markers);
488
+ }
353
489
  event.off("pointer-move", onMouseMove);
354
490
  event.off("left-click", onClick);
355
491
  event.off("double-click", onDbClick);
@@ -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
- return [minLon, minLat, maxLon, maxLat];
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
+ }