bruce-cesium 5.4.0 → 5.4.2
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/bruce-cesium.es5.js +585 -449
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +587 -447
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/cesium-animated-property.js +97 -45
- package/dist/lib/rendering/cesium-animated-property.js.map +1 -1
- package/dist/lib/rendering/getters/batched-data-getter.js +7 -1
- package/dist/lib/rendering/getters/batched-data-getter.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js +237 -357
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js +172 -37
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js.map +1 -1
- package/dist/lib/rendering/view-render-engine.js +4 -2
- package/dist/lib/rendering/view-render-engine.js.map +1 -1
- package/dist/lib/utils/view-utils.js +62 -2
- package/dist/lib/utils/view-utils.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/cesium-animated-property.d.ts +24 -21
- package/dist/types/rendering/getters/batched-data-getter.d.ts +3 -1
- package/dist/types/rendering/render-managers/entities/entities-ids-render-manager.d.ts +22 -7
- package/dist/types/rendering/render-managers/tilesets/tileset-cad-render-manager.d.ts +2 -2
- package/dist/types/utils/view-utils.d.ts +9 -0
- package/package.json +2 -2
|
@@ -7,21 +7,7 @@ const entity_render_engine_1 = require("../../entity-render-engine");
|
|
|
7
7
|
const visuals_register_1 = require("../../visuals-register");
|
|
8
8
|
const point_clustering_1 = require("../common/point-clustering");
|
|
9
9
|
const batched_data_getter_1 = require("../../getters/batched-data-getter");
|
|
10
|
-
const js_utils_1 = require("../../../internal/js-utils");
|
|
11
10
|
const BATCH_SIZE = 500;
|
|
12
|
-
function getValue(viewer, obj) {
|
|
13
|
-
if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
|
|
14
|
-
let date = viewer.scene.lastRenderTime;
|
|
15
|
-
if (!date) {
|
|
16
|
-
date = viewer.clock.currentTime;
|
|
17
|
-
}
|
|
18
|
-
return obj.getValue(date);
|
|
19
|
-
}
|
|
20
|
-
return obj;
|
|
21
|
-
}
|
|
22
|
-
function colorToCColor(color) {
|
|
23
|
-
return new Cesium.Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
|
|
24
|
-
}
|
|
25
11
|
/**
|
|
26
12
|
* Render manager for rendering an array of entity ids.
|
|
27
13
|
* This will render them in batches to avoid overloading the viewer.
|
|
@@ -38,23 +24,27 @@ var EntitiesIdsRenderManager;
|
|
|
38
24
|
this.getterSub = null;
|
|
39
25
|
this.disposed = false;
|
|
40
26
|
this.renderedEntities = {};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
|
|
27
|
+
// Callback to dispose the monitoring of the viewer's timeline for historic data.
|
|
28
|
+
this.viewerDateTimeChangeRemoval = null;
|
|
29
|
+
// Entity ID -> historic information on the Entity.
|
|
30
|
+
// This helps us manage what needs changing whenever we receive the same Entity update, or when the timeline range changes.
|
|
31
|
+
this.entitiesHistoric = {};
|
|
32
|
+
// Queue for renderAsIndividuals to avoid concurrent calls.
|
|
33
|
+
this.renderQueueActive = false;
|
|
34
|
+
this.renderQueue = [];
|
|
35
|
+
this.renderQueueForceFlags = [];
|
|
45
36
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
46
37
|
this.viewer = viewer;
|
|
47
38
|
this.apiGetter = apiGetter;
|
|
48
39
|
this.monitor = monitor;
|
|
49
40
|
this.item = item;
|
|
50
41
|
this.visualsManager = visualsManager;
|
|
51
|
-
this.useGeojson = item.renderAsGeojson == true;
|
|
52
42
|
if (this.item.enableClustering) {
|
|
53
43
|
this.clustering = new point_clustering_1.PointClustering(visualsManager, this.item.id, (_a = this.item) === null || _a === void 0 ? void 0 : _a.clustering);
|
|
54
44
|
}
|
|
55
45
|
}
|
|
56
46
|
Init() {
|
|
57
|
-
var _a;
|
|
47
|
+
var _a, _b, _c;
|
|
58
48
|
if (this.disposed) {
|
|
59
49
|
throw (new Error("This item is disposed."));
|
|
60
50
|
}
|
|
@@ -74,15 +64,19 @@ var EntitiesIdsRenderManager;
|
|
|
74
64
|
if (this.renderPriority == null) {
|
|
75
65
|
this.renderPriority = 2;
|
|
76
66
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
this.getter = new batched_data_getter_1.BatchedDataGetter.Getter(this.item.BruceEntity.EntityIds, this.monitor, BATCH_SIZE);
|
|
67
|
+
this.getter = new batched_data_getter_1.BatchedDataGetter.Getter(this.item.BruceEntity.EntityIds, this.monitor, BATCH_SIZE,
|
|
68
|
+
// Don't emit the same Entity multiple times.
|
|
69
|
+
true);
|
|
82
70
|
this.getterSub = this.getter.OnUpdate.Subscribe((ids) => {
|
|
83
71
|
this.onGetterUpdate(ids);
|
|
84
72
|
});
|
|
85
73
|
this.getter.Start();
|
|
74
|
+
if (((_b = this.item.BruceEntity) === null || _b === void 0 ? void 0 : _b.historic) || ((_c = this.item.BruceEntity) === null || _c === void 0 ? void 0 : _c.historicAttrKey)) {
|
|
75
|
+
this.viewerDateTimeSub();
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.viewerDateTimeDispose();
|
|
79
|
+
}
|
|
86
80
|
}
|
|
87
81
|
Dispose() {
|
|
88
82
|
if (this.disposed) {
|
|
@@ -100,11 +94,11 @@ var EntitiesIdsRenderManager;
|
|
|
100
94
|
});
|
|
101
95
|
(_b = this.clustering) === null || _b === void 0 ? void 0 : _b.Dispose();
|
|
102
96
|
this.clustering = null;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
97
|
+
this.viewerDateTimeDispose();
|
|
98
|
+
// Clear render queue when disposed
|
|
99
|
+
this.renderQueue = [];
|
|
100
|
+
this.renderQueueForceFlags = [];
|
|
101
|
+
this.renderQueueActive = false;
|
|
108
102
|
}
|
|
109
103
|
async ReRender(params) {
|
|
110
104
|
let { entityIds, force, entities } = params;
|
|
@@ -139,10 +133,6 @@ var EntitiesIdsRenderManager;
|
|
|
139
133
|
}
|
|
140
134
|
if (CameraZoomSettings === null || CameraZoomSettings === void 0 ? void 0 : CameraZoomSettings.length) {
|
|
141
135
|
this.item.CameraZoomSettings = CameraZoomSettings;
|
|
142
|
-
if (this.renderAsGeojson && this.item.CameraZoomSettings.length > 1) {
|
|
143
|
-
console.warn("Geojson rendering does not support multiple zoom controls. Only the first one will be used.");
|
|
144
|
-
this.item.CameraZoomSettings = [this.item.CameraZoomSettings[0]];
|
|
145
|
-
}
|
|
146
136
|
}
|
|
147
137
|
if (queueRerender != false) {
|
|
148
138
|
const entityIds = Object.keys(this.renderedEntities);
|
|
@@ -154,15 +144,25 @@ var EntitiesIdsRenderManager;
|
|
|
154
144
|
}
|
|
155
145
|
}
|
|
156
146
|
async onGetterUpdate(entityIds, force = false) {
|
|
157
|
-
if (this.disposed || this.viewer.isDestroyed()) {
|
|
147
|
+
if (this.disposed || this.viewer.isDestroyed() || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
|
|
158
148
|
return;
|
|
159
149
|
}
|
|
160
150
|
try {
|
|
161
151
|
const api = this.apiGetter.getApi();
|
|
152
|
+
let newDateTime = null;
|
|
153
|
+
if (this.item.BruceEntity.historic || this.item.BruceEntity.historicAttrKey) {
|
|
154
|
+
newDateTime = Cesium.JulianDate.toDate(this.viewer.clock.currentTime).toISOString();
|
|
155
|
+
}
|
|
162
156
|
const { entities } = await bruce_models_1.Entity.GetListByIds({
|
|
163
157
|
api,
|
|
164
158
|
entityIds,
|
|
165
|
-
|
|
159
|
+
historicPoint: newDateTime,
|
|
160
|
+
historicKey: this.item.BruceEntity.historicAttrKey,
|
|
161
|
+
migrated: true,
|
|
162
|
+
// If we're taking 5+ minutes to make a query, it's a dud.
|
|
163
|
+
// This is a timeout imposed on our DB and not external sources.
|
|
164
|
+
// Honestly could lower down to 30 seconds, but we'll keep it high for now.
|
|
165
|
+
maxSearchTimeSec: 60 * 5,
|
|
166
166
|
});
|
|
167
167
|
await this.renderEntities(entities, force);
|
|
168
168
|
}
|
|
@@ -171,347 +171,82 @@ var EntitiesIdsRenderManager;
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
async renderEntities(entities, force = false) {
|
|
174
|
-
if (this.disposed || this.viewer.isDestroyed()) {
|
|
174
|
+
if (this.disposed || this.viewer.isDestroyed() || !(entities === null || entities === void 0 ? void 0 : entities.length)) {
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
177
|
try {
|
|
178
|
-
|
|
179
|
-
const zoomItem = this.item.CameraZoomSettings[0];
|
|
180
|
-
if (zoomItem.DisplayType == bruce_models_1.ZoomControl.EDisplayType.Point) {
|
|
181
|
-
// We'll just render these as individuals since we don't support point geojson.
|
|
182
|
-
await this.renderAsIndividuals(entities, force);
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
await this.renderAsGeojson(entities, force);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
await this.renderAsIndividuals(entities, force);
|
|
190
|
-
}
|
|
178
|
+
await this.queueRenderAsIndividuals(entities, force);
|
|
191
179
|
}
|
|
192
180
|
catch (e) {
|
|
193
181
|
console.error(e);
|
|
194
182
|
}
|
|
195
183
|
}
|
|
196
184
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* @param entities
|
|
200
|
-
* @param force TODO: This should re-render entities that are already rendered.
|
|
185
|
+
* Queues a render operation to be processed in sequence.
|
|
186
|
+
* If an operation is already in progress, this will be added to the queue.
|
|
201
187
|
*/
|
|
202
|
-
async
|
|
203
|
-
|
|
204
|
-
entities = entities.filter((entity) => {
|
|
205
|
-
var _a;
|
|
206
|
-
return !this.renderedEntities[(_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID];
|
|
207
|
-
});
|
|
208
|
-
// Mark these as rendered.
|
|
209
|
-
entities.forEach((entity) => {
|
|
210
|
-
var _a;
|
|
211
|
-
this.renderedEntities[(_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID] = true;
|
|
212
|
-
});
|
|
213
|
-
// This process only supports a single zoom control item.
|
|
214
|
-
const zoomItem = this.item.CameraZoomSettings[0];
|
|
215
|
-
// If we're after 3d models then we'll check if there are LODs and render those as individuals.
|
|
216
|
-
if (zoomItem.DisplayType == bruce_models_1.ZoomControl.EDisplayType.Model3D && entities.length) {
|
|
217
|
-
const { lods } = await bruce_models_1.EntityLod.GetLods({
|
|
218
|
-
api: this.apiGetter.getApi(),
|
|
219
|
-
filter: {
|
|
220
|
-
externalSources: false,
|
|
221
|
-
Items: entities.map(x => {
|
|
222
|
-
var _a, _b;
|
|
223
|
-
return {
|
|
224
|
-
entityId: (_a = x.Bruce) === null || _a === void 0 ? void 0 : _a.ID,
|
|
225
|
-
categoryId: (_b = zoomItem.LODCategoryID) !== null && _b !== void 0 ? _b : "GLB",
|
|
226
|
-
group: "DEFAULT",
|
|
227
|
-
level: Number(zoomItem.LODLevel)
|
|
228
|
-
};
|
|
229
|
-
}),
|
|
230
|
-
strict: false
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
if (this.disposed) {
|
|
234
|
-
this.doDispose();
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
const withLods = lods.filter(x => x.entityId && !!x.clientFileId).map(x => x.entityId);
|
|
238
|
-
const individuals = entities.filter((entity) => {
|
|
239
|
-
var _a;
|
|
240
|
-
return withLods.includes((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID);
|
|
241
|
-
});
|
|
242
|
-
if (individuals.length) {
|
|
243
|
-
this.renderAsIndividuals(individuals, force);
|
|
244
|
-
}
|
|
245
|
-
// Now we proceed with what is left.
|
|
246
|
-
entities = entities.filter((entity) => {
|
|
247
|
-
var _a;
|
|
248
|
-
return !withLods.includes((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID);
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
if (!entities.length) {
|
|
188
|
+
async queueRenderAsIndividuals(entities, force = false) {
|
|
189
|
+
if (this.disposed) {
|
|
252
190
|
return;
|
|
253
191
|
}
|
|
254
|
-
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
api: this.apiGetter.getApi(),
|
|
259
|
-
styleId: zoomItem === null || zoomItem === void 0 ? void 0 : zoomItem.StyleID
|
|
260
|
-
})).style) === null || _a === void 0 ? void 0 : _a.Settings;
|
|
261
|
-
}
|
|
262
|
-
// Probably deleted.
|
|
263
|
-
catch (e) {
|
|
264
|
-
console.error(e);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
let entityTypeId = (_b = this.item.BruceEntity) === null || _b === void 0 ? void 0 : _b["EntityType.ID"];
|
|
268
|
-
if (!entityTypeId) {
|
|
269
|
-
entityTypeId = (_d = (_c = entities.find(x => { var _a; return !!((_a = x.Bruce) === null || _a === void 0 ? void 0 : _a["EntityType.ID"]); })) === null || _c === void 0 ? void 0 : _c.Bruce) === null || _d === void 0 ? void 0 : _d["EntityType.ID"];
|
|
270
|
-
}
|
|
271
|
-
// Getting type regardless cause it's needed for name calculations.
|
|
272
|
-
let entityType;
|
|
273
|
-
if (entityTypeId) {
|
|
274
|
-
// Try using the Entity Type default if one is specified in the menu item.
|
|
275
|
-
try {
|
|
276
|
-
entityType = (_e = (await bruce_models_1.EntityType.Get({
|
|
277
|
-
entityTypeId: entityTypeId,
|
|
278
|
-
api: this.apiGetter.getApi()
|
|
279
|
-
}))) === null || _e === void 0 ? void 0 : _e.entityType;
|
|
280
|
-
if (!style && entityType) {
|
|
281
|
-
if (entityType["DisplaySetting.ID"] && entityType["DisplaySetting.ID"] > 0) {
|
|
282
|
-
style = (_f = (await bruce_models_1.Style.Get({
|
|
283
|
-
api: this.apiGetter.getApi(),
|
|
284
|
-
styleId: entityType["DisplaySetting.ID"]
|
|
285
|
-
})).style) === null || _f === void 0 ? void 0 : _f.Settings;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
catch (e) {
|
|
290
|
-
console.error(e);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
const pStyle = (_g = style === null || style === void 0 ? void 0 : style.polygonStyle) !== null && _g !== void 0 ? _g : {};
|
|
294
|
-
const lStyle = (_h = style === null || style === void 0 ? void 0 : style.polylineStyle) !== null && _h !== void 0 ? _h : {};
|
|
295
|
-
const polygonsClamped = ((_j = pStyle === null || pStyle === void 0 ? void 0 : pStyle.altitudeOption) === null || _j === void 0 ? void 0 : _j.id) == null ? true : ((_k = pStyle === null || pStyle === void 0 ? void 0 : pStyle.altitudeOption) === null || _k === void 0 ? void 0 : _k.id) == 0;
|
|
296
|
-
const bFillColor = bruce_models_1.Calculator.GetColor(pStyle.fillColor, {}, []);
|
|
297
|
-
const cFillColor = bFillColor ? colorToCColor(bFillColor) : Cesium.Color.fromCssColorString("rgba(139, 195, 74, 0.8)");
|
|
298
|
-
const bLineColor = bruce_models_1.Calculator.GetColor(pStyle.lineColor, {}, []);
|
|
299
|
-
const cLineColor = bLineColor ? colorToCColor(bLineColor) : Cesium.Color.fromCssColorString("rgba(80, 80, 80, 0.8)");
|
|
300
|
-
let lineWidthPx = pStyle.lineWidth ? bruce_models_1.Calculator.GetNumber(pStyle.lineWidth, {}, []) : null;
|
|
301
|
-
if (lineWidthPx == null) {
|
|
302
|
-
lineWidthPx = 1;
|
|
303
|
-
}
|
|
304
|
-
lineWidthPx = (0, js_utils_1.EnsureNumber)(lineWidthPx);
|
|
305
|
-
if (lineWidthPx < 0.01) {
|
|
306
|
-
lineWidthPx = 0;
|
|
307
|
-
}
|
|
308
|
-
lineWidthPx = Math.round(lineWidthPx);
|
|
309
|
-
const collection = {
|
|
310
|
-
features: [],
|
|
311
|
-
type: "FeatureCollection"
|
|
312
|
-
};
|
|
313
|
-
for (let i = 0; i < entities.length; i++) {
|
|
314
|
-
const entity = entities[i];
|
|
315
|
-
const feature = bruce_models_1.Geometry.ToGeoJsonFeature({
|
|
316
|
-
geometry: entity.Bruce.VectorGeometry,
|
|
317
|
-
noAltitude: polygonsClamped && lineWidthPx <= 0,
|
|
318
|
-
altitude: lineWidthPx > 0 && polygonsClamped ? 1 : null,
|
|
319
|
-
properties: {
|
|
320
|
-
...entity,
|
|
321
|
-
Bruce: {
|
|
322
|
-
...entity.Bruce,
|
|
323
|
-
// Exclude as we just converted it to geojson.
|
|
324
|
-
VectorGeometry: null
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
if (feature) {
|
|
329
|
-
collection.features.push(feature);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Anything that failed to turn into geojson or points we'll render as individuals.
|
|
333
|
-
const individuals = entities.filter((entity) => {
|
|
334
|
-
const feature = collection.features.find(x => { var _a, _b; return ((_b = (_a = x.properties) === null || _a === void 0 ? void 0 : _a.Bruce) === null || _b === void 0 ? void 0 : _b.ID) == entity.Bruce.ID; });
|
|
335
|
-
if (!feature) {
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
if (feature.geometry.type == "Point") {
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
return false;
|
|
342
|
-
});
|
|
343
|
-
if (individuals.length) {
|
|
344
|
-
this.renderAsIndividuals(individuals, force);
|
|
345
|
-
}
|
|
346
|
-
// Filter out points (the ones we just rendered as individuals).
|
|
347
|
-
collection.features = collection.features.filter(x => x.geometry.type != "Point");
|
|
348
|
-
// If there is nothing to render now, return.
|
|
349
|
-
if (!collection.features.length) {
|
|
192
|
+
// If no active render is happening, start processing immediately.
|
|
193
|
+
if (!this.renderQueueActive) {
|
|
194
|
+
this.renderQueueActive = true;
|
|
195
|
+
await this.processRenderQueue(entities, force);
|
|
350
196
|
return;
|
|
351
197
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
198
|
+
// Otherwise, add to the queue.
|
|
199
|
+
this.renderQueue.push(entities);
|
|
200
|
+
this.renderQueueForceFlags.push(force);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Processes the render queue, handling one rendering operation at a time.
|
|
204
|
+
*/
|
|
205
|
+
async processRenderQueue(initialEntities, initialForce = false) {
|
|
360
206
|
if (this.disposed) {
|
|
361
|
-
this.
|
|
207
|
+
this.renderQueueActive = false;
|
|
362
208
|
return;
|
|
363
209
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
* @param thing
|
|
369
|
-
* @param entityId
|
|
370
|
-
* @param data
|
|
371
|
-
* @returns
|
|
372
|
-
*/
|
|
373
|
-
const applyStyle = (thing, entityId, data) => {
|
|
374
|
-
if (thing.polygon) {
|
|
375
|
-
const bFillColor = bruce_models_1.Calculator.GetColor(pStyle.fillColor, data, []);
|
|
376
|
-
const cFillColor = bFillColor ? colorToCColor(bFillColor) : Cesium.Color.fromCssColorString("rgba(139, 195, 74, 0.8)");
|
|
377
|
-
const bLineColor = bruce_models_1.Calculator.GetColor(pStyle.lineColor, data, []);
|
|
378
|
-
const cLineColor = bLineColor ? colorToCColor(bLineColor) : Cesium.Color.fromCssColorString("rgba(80, 80, 80, 0.8)");
|
|
379
|
-
let width = pStyle.lineWidth ? bruce_models_1.Calculator.GetNumber(pStyle.lineWidth, data, []) : null;
|
|
380
|
-
if (width == null) {
|
|
381
|
-
width = 1;
|
|
382
|
-
}
|
|
383
|
-
width = (0, js_utils_1.EnsureNumber)(width);
|
|
384
|
-
if (width < 0.01) {
|
|
385
|
-
width = 0;
|
|
386
|
-
}
|
|
387
|
-
let curFillColor = getValue(this.viewer, thing.polygon.material);
|
|
388
|
-
if (curFillColor && curFillColor instanceof Cesium.ColorMaterialProperty) {
|
|
389
|
-
curFillColor = curFillColor.color;
|
|
390
|
-
}
|
|
391
|
-
let curLineColor = getValue(this.viewer, thing.polygon.outlineColor);
|
|
392
|
-
if (curLineColor && curLineColor instanceof Cesium.ColorMaterialProperty) {
|
|
393
|
-
curLineColor = curLineColor.color;
|
|
394
|
-
}
|
|
395
|
-
const curWidth = getValue(this.viewer, thing.polygon.outlineWidth);
|
|
396
|
-
if ((curFillColor instanceof Cesium.Color && curFillColor.equals(cFillColor)) &&
|
|
397
|
-
(curLineColor instanceof Cesium.Color && curLineColor.equals(cLineColor)) &&
|
|
398
|
-
curWidth == width) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
thing.polygon.material = new Cesium.ColorMaterialProperty(cFillColor);
|
|
402
|
-
thing.polygon.outlineColor = new Cesium.ConstantProperty(cLineColor);
|
|
403
|
-
thing.polygon.outlineWidth = new Cesium.ConstantProperty(width);
|
|
404
|
-
}
|
|
405
|
-
else if (thing.polyline) {
|
|
406
|
-
const bColor = lStyle.lineColor ? bruce_models_1.Calculator.GetColor(lStyle.lineColor, data, []) : null;
|
|
407
|
-
const cColor = bColor ? colorToCColor(bColor) : Cesium.Color.fromCssColorString("rgba(255, 193, 7, 0.8)");
|
|
408
|
-
let width = lStyle.lineWidth ? bruce_models_1.Calculator.GetNumber(lStyle.lineWidth, data, []) : null;
|
|
409
|
-
if (width == null) {
|
|
410
|
-
width = 2;
|
|
411
|
-
}
|
|
412
|
-
width = (0, js_utils_1.EnsureNumber)(width);
|
|
413
|
-
if (width < 0.01) {
|
|
414
|
-
width = 0;
|
|
415
|
-
}
|
|
416
|
-
let curColor = getValue(this.viewer, thing.polyline.material);
|
|
417
|
-
if (curColor && curColor instanceof Cesium.ColorMaterialProperty) {
|
|
418
|
-
curColor = curColor.color;
|
|
419
|
-
}
|
|
420
|
-
const curWidth = getValue(this.viewer, thing.polyline.width);
|
|
421
|
-
if ((curColor instanceof Cesium.Color && curColor.equals(cColor)) &&
|
|
422
|
-
curWidth == width) {
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
thing.polyline.material = new Cesium.ColorMaterialProperty(cColor);
|
|
426
|
-
thing.polyline.width = new Cesium.ConstantProperty(width);
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
let toForceUpdate = [];
|
|
430
|
-
/**
|
|
431
|
-
* Registers a given cesium entity produced from rendering geojson.
|
|
432
|
-
* Since one nextspace entity can have multiple cesium entities, there is special logic to group them together.
|
|
433
|
-
* @param thing
|
|
434
|
-
* @returns
|
|
435
|
-
*/
|
|
436
|
-
const register = (thing) => {
|
|
437
|
-
var _a, _b, _c, _d;
|
|
438
|
-
// See if the cesium entity already exists in a group.
|
|
439
|
-
let group = groups.find((x) => { var _a; return ((_a = x.visual) === null || _a === void 0 ? void 0 : _a.id) == thing.id || x.siblings.find(x => (x === null || x === void 0 ? void 0 : x.id) == thing.id); });
|
|
440
|
-
if (group) {
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
const metadata = getValue(this.viewer, thing === null || thing === void 0 ? void 0 : thing.properties);
|
|
444
|
-
const entityId = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
445
|
-
if (!entityId) {
|
|
210
|
+
try {
|
|
211
|
+
// Process the initial batch.
|
|
212
|
+
await this.renderAsIndividuals(initialEntities, initialForce);
|
|
213
|
+
if (this.disposed) {
|
|
446
214
|
return;
|
|
447
215
|
}
|
|
448
|
-
//
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
};
|
|
461
|
-
groups.push(group);
|
|
462
|
-
applyStyle(thing, entityId, group.data);
|
|
463
|
-
const rego = {
|
|
464
|
-
entityId: entityId,
|
|
465
|
-
menuItemId: this.item.id,
|
|
466
|
-
menuItemType: this.item.Type,
|
|
467
|
-
visual: thing,
|
|
468
|
-
priority: this.renderPriority,
|
|
469
|
-
entityTypeId: group.entityTypeId,
|
|
470
|
-
accountId: this.apiGetter.accountId,
|
|
471
|
-
tagIds: group.tagIds ? [].concat(group.tagIds) : [],
|
|
472
|
-
name: entityType ? (_d = bruce_models_1.Entity.CalculateName({
|
|
473
|
-
entity: group.data,
|
|
474
|
-
type: entityType,
|
|
475
|
-
defaultToId: false
|
|
476
|
-
})) !== null && _d !== void 0 ? _d : "Unnamed Entity" : "Unnamed Entity",
|
|
477
|
-
cdn: this.item.cdnEnabled,
|
|
478
|
-
collection: source.entities
|
|
479
|
-
};
|
|
480
|
-
group.rego = rego;
|
|
481
|
-
this.visualsManager.AddRego({
|
|
482
|
-
rego,
|
|
483
|
-
requestRender: false
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
// Found a group. We flag this as a sibling entity of the primary.
|
|
487
|
-
else {
|
|
488
|
-
applyStyle(thing, entityId, group.data);
|
|
489
|
-
group.siblings.push(thing);
|
|
490
|
-
group.visual._siblingGraphics = group.siblings;
|
|
491
|
-
thing._parentEntity = group.visual;
|
|
492
|
-
if (group.rego) {
|
|
493
|
-
this.visualsManager.RefreshMark({
|
|
494
|
-
rego: group.rego
|
|
495
|
-
});
|
|
496
|
-
if (!toForceUpdate.includes(entityId)) {
|
|
497
|
-
toForceUpdate.push(entityId);
|
|
216
|
+
// Process any queued items.
|
|
217
|
+
while (this.renderQueue.length > 0 && !this.disposed) {
|
|
218
|
+
// If multiple entities are waiting, combine them to reduce render operations.
|
|
219
|
+
const allEntities = [];
|
|
220
|
+
const forces = [];
|
|
221
|
+
// Collect all pending entities.
|
|
222
|
+
while (this.renderQueue.length > 0) {
|
|
223
|
+
const entities = this.renderQueue.shift();
|
|
224
|
+
const force = this.renderQueueForceFlags.shift();
|
|
225
|
+
if (entities && entities.length > 0) {
|
|
226
|
+
allEntities.push(...entities);
|
|
227
|
+
forces.push(force);
|
|
498
228
|
}
|
|
499
229
|
}
|
|
230
|
+
if (allEntities.length > 0) {
|
|
231
|
+
// If any are forced, we need to force the render.
|
|
232
|
+
const combinedForce = forces.some(f => f === true);
|
|
233
|
+
const uniqueEntities = this.deduplicateEntities(allEntities);
|
|
234
|
+
await this.renderAsIndividuals(uniqueEntities, combinedForce);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
this.renderQueueActive = false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
deduplicateEntities(entities) {
|
|
243
|
+
const entityMap = new Map();
|
|
244
|
+
for (const entity of entities) {
|
|
245
|
+
if (entity && entity.Bruce && entity.Bruce.ID) {
|
|
246
|
+
entityMap.set(entity.Bruce.ID, entity);
|
|
500
247
|
}
|
|
501
|
-
};
|
|
502
|
-
const sEntities = source.entities.values;
|
|
503
|
-
for (let i = 0; i < sEntities.length; i++) {
|
|
504
|
-
const cEntity = sEntities[i];
|
|
505
|
-
register(cEntity);
|
|
506
|
-
}
|
|
507
|
-
if (toForceUpdate.length) {
|
|
508
|
-
this.visualsManager.ForceUpdate({
|
|
509
|
-
entityIds: toForceUpdate,
|
|
510
|
-
refreshColors: true,
|
|
511
|
-
requestRender: false
|
|
512
|
-
});
|
|
513
248
|
}
|
|
514
|
-
|
|
249
|
+
return Array.from(entityMap.values());
|
|
515
250
|
}
|
|
516
251
|
/**
|
|
517
252
|
* Our default path.
|
|
@@ -522,16 +257,28 @@ var EntitiesIdsRenderManager;
|
|
|
522
257
|
*/
|
|
523
258
|
async renderAsIndividuals(entities, force = false) {
|
|
524
259
|
var _a;
|
|
260
|
+
if (this.disposed || this.viewer.isDestroyed() || !entities.length) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
let entitiesHistoric = {};
|
|
264
|
+
if ((this.item.BruceEntity.historic || this.item.BruceEntity.historicAttrKey) && entities.length) {
|
|
265
|
+
entitiesHistoric = await this.getHistoricInfo(entities);
|
|
266
|
+
}
|
|
525
267
|
const { updated, entities: cEntities } = await entity_render_engine_1.EntityRenderEngine.Render({
|
|
526
268
|
viewer: this.viewer,
|
|
527
269
|
apiGetter: this.apiGetter,
|
|
528
270
|
entities: entities,
|
|
529
271
|
menuItemId: this.item.id,
|
|
530
272
|
visualRegister: this.visualsManager,
|
|
273
|
+
entitiesHistoric: entitiesHistoric,
|
|
274
|
+
entityHistoricDrawTrack: this.item.historicDrawTrack,
|
|
531
275
|
zoomControl: this.item.CameraZoomSettings,
|
|
532
276
|
force
|
|
533
277
|
});
|
|
534
278
|
for (let i = 0; i < entities.length; i++) {
|
|
279
|
+
if (this.disposed) {
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
535
282
|
const entity = entities[i];
|
|
536
283
|
const id = entity.Bruce.ID;
|
|
537
284
|
const cEntity = cEntities.get(id);
|
|
@@ -580,10 +327,143 @@ var EntitiesIdsRenderManager;
|
|
|
580
327
|
(_a = this.clustering) === null || _a === void 0 ? void 0 : _a.RemoveEntity(id, false);
|
|
581
328
|
}
|
|
582
329
|
}
|
|
583
|
-
this.
|
|
584
|
-
|
|
585
|
-
this.clustering.
|
|
330
|
+
if (!this.disposed) {
|
|
331
|
+
this.viewer.scene.requestRender();
|
|
332
|
+
if (this.clustering && entities.length) {
|
|
333
|
+
this.clustering.Update();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Returns historic information for the given set of Entities at the current timeline range.
|
|
339
|
+
* @param entities
|
|
340
|
+
*/
|
|
341
|
+
async getHistoricInfo(entities) {
|
|
342
|
+
const startTmp = Cesium.JulianDate.toDate(this.viewer.clock.startTime);
|
|
343
|
+
const stopTmp = Cesium.JulianDate.toDate(this.viewer.clock.stopTime);
|
|
344
|
+
let rangesToRequest = [{
|
|
345
|
+
start: startTmp.toISOString(),
|
|
346
|
+
stop: stopTmp.toISOString()
|
|
347
|
+
}];
|
|
348
|
+
// If we already have cached data, determine what ranges we're missing.
|
|
349
|
+
if (this.lastHistoricMin && this.lastHistoricMax && Object.keys(this.entitiesHistoric).length >= entities.length) {
|
|
350
|
+
const cachedStart = new Date(this.lastHistoricMin).getTime();
|
|
351
|
+
const cachedStop = new Date(this.lastHistoricMax).getTime();
|
|
352
|
+
const newStart = startTmp.getTime();
|
|
353
|
+
const newStop = stopTmp.getTime();
|
|
354
|
+
// Complete overlap - we already have all the data.
|
|
355
|
+
if (newStart >= cachedStart && newStop <= cachedStop) {
|
|
356
|
+
return this.entitiesHistoric;
|
|
357
|
+
}
|
|
358
|
+
// Calculate missing ranges.
|
|
359
|
+
rangesToRequest = [];
|
|
360
|
+
// Check if we need data before our cached range.
|
|
361
|
+
if (newStart < cachedStart) {
|
|
362
|
+
rangesToRequest.push({
|
|
363
|
+
start: startTmp.toISOString(),
|
|
364
|
+
stop: new Date(cachedStart).toISOString()
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
// Check if we need data after our cached range.
|
|
368
|
+
if (newStop > cachedStop) {
|
|
369
|
+
rangesToRequest.push({
|
|
370
|
+
start: new Date(cachedStop).toISOString(),
|
|
371
|
+
stop: stopTmp.toISOString()
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const entityIds = entities.map(x => x.Bruce.ID);
|
|
376
|
+
const combined = { ...this.entitiesHistoric };
|
|
377
|
+
// Make requests for each missing range
|
|
378
|
+
for (const range of rangesToRequest) {
|
|
379
|
+
if (this.disposed) {
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
// Add padding to ensure we get all data.
|
|
383
|
+
const start = new Date(range.start);
|
|
384
|
+
const stop = new Date(range.stop);
|
|
385
|
+
start.setSeconds(start.getSeconds() - 1);
|
|
386
|
+
stop.setSeconds(stop.getSeconds() + 1);
|
|
387
|
+
const paddedStartStr = start.toISOString();
|
|
388
|
+
const paddedStopStr = stop.toISOString();
|
|
389
|
+
const historicData = await bruce_models_1.EntityHistoricData.GetList({
|
|
390
|
+
attrKey: this.item.BruceEntity.historicAttrKey,
|
|
391
|
+
dateTimeFrom: paddedStartStr,
|
|
392
|
+
dateTimeTo: paddedStopStr,
|
|
393
|
+
entityIds: entityIds,
|
|
394
|
+
api: this.apiGetter.getApi()
|
|
395
|
+
});
|
|
396
|
+
if (this.disposed) {
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
// Merge the new data with existing data
|
|
400
|
+
const records = historicData.recordsByIds;
|
|
401
|
+
const recordsIds = Object.keys(records);
|
|
402
|
+
for (let i = 0; i < recordsIds.length; i++) {
|
|
403
|
+
const entityId = recordsIds[i];
|
|
404
|
+
const latest = records[entityId] || [];
|
|
405
|
+
const current = combined[entityId] || [];
|
|
406
|
+
// Use a Map to de-duplicate by timestamp.
|
|
407
|
+
const tmp = new Map();
|
|
408
|
+
for (let j = 0; j < current.length; j++) {
|
|
409
|
+
const record = current[j];
|
|
410
|
+
const dateTime = new Date(record.dateTime).getTime();
|
|
411
|
+
tmp.set(dateTime, record);
|
|
412
|
+
}
|
|
413
|
+
for (let j = 0; j < latest.length; j++) {
|
|
414
|
+
const record = latest[j];
|
|
415
|
+
const dateTime = new Date(record.dateTime).getTime();
|
|
416
|
+
tmp.set(dateTime, record);
|
|
417
|
+
}
|
|
418
|
+
// Convert to array and sort by date.
|
|
419
|
+
const sorted = Array.from(tmp.values()).sort((a, b) => {
|
|
420
|
+
return new Date(a.dateTime).getTime() - new Date(b.dateTime).getTime();
|
|
421
|
+
});
|
|
422
|
+
combined[entityId] = sorted;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (!this.disposed) {
|
|
426
|
+
// Update our cache boundaries.
|
|
427
|
+
this.lastHistoricMin = startTmp.toISOString();
|
|
428
|
+
this.lastHistoricMax = stopTmp.toISOString();
|
|
429
|
+
this.entitiesHistoric = combined;
|
|
430
|
+
}
|
|
431
|
+
return combined;
|
|
432
|
+
}
|
|
433
|
+
viewerDateTimeSub() {
|
|
434
|
+
var _a, _b;
|
|
435
|
+
if ((!((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historic) && !((_b = this.item.BruceEntity) === null || _b === void 0 ? void 0 : _b.historicAttrKey)) || this.viewerDateTimeChangeRemoval) {
|
|
436
|
+
return;
|
|
586
437
|
}
|
|
438
|
+
const THROTTLE_INTERVAL = 2000;
|
|
439
|
+
let queue = new bruce_models_1.DelayQueue(() => {
|
|
440
|
+
this.onGetterUpdate(Object.keys(this.renderedEntities));
|
|
441
|
+
}, THROTTLE_INTERVAL, true);
|
|
442
|
+
let clockTickRemoval;
|
|
443
|
+
let prevTick = this.viewer.clock.currentTime.toString();
|
|
444
|
+
clockTickRemoval = this.viewer.clock.onTick.addEventListener(() => {
|
|
445
|
+
if (this.disposed || this.viewer.isDestroyed()) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const currentTick = this.viewer.clock.currentTime.toString();
|
|
449
|
+
if (currentTick === prevTick) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
queue.Call();
|
|
453
|
+
});
|
|
454
|
+
this.viewerDateTimeChangeRemoval = () => {
|
|
455
|
+
if (clockTickRemoval) {
|
|
456
|
+
clockTickRemoval();
|
|
457
|
+
clockTickRemoval = null;
|
|
458
|
+
}
|
|
459
|
+
queue.Dispose();
|
|
460
|
+
queue = null;
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
viewerDateTimeDispose() {
|
|
464
|
+
var _a;
|
|
465
|
+
(_a = this.viewerDateTimeChangeRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
466
|
+
this.viewerDateTimeChangeRemoval = null;
|
|
587
467
|
}
|
|
588
468
|
}
|
|
589
469
|
EntitiesIdsRenderManager.Manager = Manager;
|