bruce-cesium 5.3.9 → 5.4.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.
@@ -1,6 +1,6 @@
1
1
  import { BruceEvent, Cartes, Entity as Entity$1, Carto, Geometry, MathUtils, LRUCache, Api, Calculator, ClientFile, EntityTag, EntityType, ObjectUtils, Style, ProjectViewTile, DelayQueue, EntityLod, Bounds, ZoomControl, EntityRelationType, ENVIRONMENT, EntityHistoricData, Tileset, EntityCoords, DataLab, EntitySource, MenuItem, EntityRelation, ProgramKey, ProjectView, ProjectViewBookmark, Camera, ProjectViewLegacyTile, EntityAttachment, EntityAttachmentType, EntityAttribute, AbstractApi, Session } from 'bruce-models';
2
2
  import * as Cesium from 'cesium';
3
- import { Cartographic, Cartesian2, Math as Math$1, Cartesian3, CallbackProperty, Color, HeightReference, Rectangle, JulianDate, Entity, DistanceDisplayCondition, ClassificationType, ArcType, CornerType, ShadowMode, ConstantProperty, ConstantPositionProperty, PolygonHierarchy, PolylineGraphics, ColorMaterialProperty, ColorBlendMode, HeadingPitchRoll, Transforms, Model, HorizontalOrigin, VerticalOrigin, SceneMode, GeoJsonDataSource, Primitive, Cesium3DTileFeature, Cesium3DTileStyle, Cesium3DTileColorBlendMode, HeadingPitchRange, Ion, KmlDataSource, SceneTransforms, OrthographicFrustum, EasingFunction, NearFarScalar, EllipsoidTerrainProvider, CesiumInspector, defined, ClockRange, EllipsoidGeodesic, sampleTerrainMostDetailed, Cesium3DTileset, PolygonPipeline, BoundingSphere, Matrix3, Matrix4, GeometryInstance, IonResource, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, ScreenSpaceEventHandler, ScreenSpaceEventType, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, Quaternion, CzmlDataSource, Intersect, Fullscreen } from 'cesium';
3
+ import { Cartographic, Cartesian2, Math as Math$1, Cartesian3, CallbackProperty, Color, HeightReference, Rectangle, JulianDate, Entity, DistanceDisplayCondition, HorizontalOrigin, VerticalOrigin, ConstantProperty, ClassificationType, ConstantPositionProperty, ArcType, CornerType, ShadowMode, PolygonHierarchy, PolylineGraphics, ColorMaterialProperty, ColorBlendMode, HeadingPitchRoll, Transforms, Model, SceneMode, Primitive, Cesium3DTileFeature, GeoJsonDataSource, Cesium3DTileStyle, Cesium3DTileColorBlendMode, HeadingPitchRange, Ion, KmlDataSource, SceneTransforms, OrthographicFrustum, EasingFunction, NearFarScalar, EllipsoidTerrainProvider, CesiumInspector, defined, ClockRange, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, EllipsoidGeodesic, sampleTerrainMostDetailed, Cesium3DTileset, Matrix4, Matrix3, IonResource, PolygonPipeline, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, BoundingSphere, GeometryInstance, Quaternion, ScreenSpaceEventHandler, ScreenSpaceEventType, CzmlDataSource, Intersect, Fullscreen } from 'cesium';
4
4
 
5
5
  const TIME_LAG = 300;
6
6
  const POSITION_CHECK_TIMER = 950;
@@ -1368,6 +1368,9 @@ var CesiumAnimatedProperty;
1368
1368
  }
1369
1369
  CesiumAnimatedProperty.AnimatePositionSeries = AnimatePositionSeries;
1370
1370
  function GetSeriesPossesForHistoricEntity(viewer, heightRef, historic) {
1371
+ if (!historic || !historic.length) {
1372
+ return [];
1373
+ }
1371
1374
  const series = [];
1372
1375
  for (let i = 0; i < historic.length; i++) {
1373
1376
  const item = historic[i];
@@ -1406,25 +1409,6 @@ var CesiumAnimatedProperty;
1406
1409
  return series;
1407
1410
  }
1408
1411
  CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity = GetSeriesPossesForHistoricEntity;
1409
- /**
1410
- * Animates a tileset position and heading from a series of positions over time.
1411
- * Unlike other animation functions that directly modify the tileset,
1412
- * this provides a callback with calculated values for the caller to apply.
1413
- *
1414
- * Example:
1415
- * ```
1416
- * const dispose = CesiumAnimatedProperty.AnimateTPositionSeries({
1417
- * viewer: viewer,
1418
- * posses: positionSeries,
1419
- * onUpdate: (position, heading) => {}
1420
- * });
1421
- *
1422
- * // To dispose:
1423
- * dispose();
1424
- * ```
1425
- * @param params Animation parameters
1426
- * @returns Function to stop the animation
1427
- */
1428
1412
  class AnimateTPositionSeries {
1429
1413
  constructor(params) {
1430
1414
  // Cache for calculated values.
@@ -1432,23 +1416,74 @@ var CesiumAnimatedProperty;
1432
1416
  this.lastCalcPos3d = null;
1433
1417
  this.lastCalcHeading = null;
1434
1418
  this.removal = null;
1419
+ // Track the timeline range for which we have data.
1420
+ this.minDate = null;
1421
+ this.maxDate = null;
1422
+ // Map of positions by timestamp for quick lookup and deduplication.
1423
+ this.positionsMap = new Map();
1435
1424
  this.viewer = params.viewer;
1436
1425
  this.onUpdate = params.onUpdate;
1437
1426
  this.onDone = params.onDone;
1438
- // No positions to animate.
1439
- if (!params.posses || params.posses.length === 0) {
1440
- return;
1427
+ this.onRangeChangeCallback = params.onRangeChange;
1428
+ // Initialize the positions map
1429
+ this.positionsMap = new Map();
1430
+ // Add initial positions
1431
+ if (params.posses && params.posses.length > 0) {
1432
+ this.addPositions(params.posses);
1441
1433
  }
1442
- // Order positions by date.
1443
- const orderedPosses = [...params.posses].sort((a, b) => {
1444
- return a.dateTime.getTime() - b.dateTime.getTime();
1445
- });
1446
- // Process headings - if all are null or 0, assume all are null.
1447
- this.positions = this.processHeadings([...orderedPosses]);
1448
1434
  // Set up the animation loop.
1449
1435
  this.removal = this.viewer.scene.postUpdate.addEventListener(() => this.update());
1450
1436
  this.update();
1451
1437
  }
1438
+ /**
1439
+ * Add new positions to the animation.
1440
+ * Will deduplicate positions with the same timestamp and sort them.
1441
+ * @param newPositions Positions to add
1442
+ */
1443
+ addPositions(newPositions) {
1444
+ if (!newPositions || newPositions.length === 0) {
1445
+ return;
1446
+ }
1447
+ // Add new positions to our map, overwriting any existing positions with the same timestamp
1448
+ for (const pos of newPositions) {
1449
+ const key = pos.dateTime.toISOString();
1450
+ this.positionsMap.set(key, pos);
1451
+ }
1452
+ // Rebuild our sorted array from the map
1453
+ this.positions = Array.from(this.positionsMap.values()).sort((a, b) => {
1454
+ return a.dateTime.getTime() - b.dateTime.getTime();
1455
+ });
1456
+ // Process headings
1457
+ this.positions = this.processHeadings([...this.positions]);
1458
+ // Update our min/max dates
1459
+ if (this.positions.length > 0) {
1460
+ const first = this.positions[0];
1461
+ const last = this.positions[this.positions.length - 1];
1462
+ if (!this.minDate || first.dateTime < this.minDate) {
1463
+ this.minDate = first.dateTime;
1464
+ }
1465
+ if (!this.maxDate || last.dateTime > this.maxDate) {
1466
+ this.maxDate = last.dateTime;
1467
+ }
1468
+ }
1469
+ }
1470
+ /**
1471
+ * Get the current date range covered by our positions.
1472
+ */
1473
+ getDateRange() {
1474
+ return {
1475
+ minDate: this.minDate,
1476
+ maxDate: this.maxDate
1477
+ };
1478
+ }
1479
+ /**
1480
+ * Trigger the onRangeChange callback to request more data.
1481
+ */
1482
+ onRangeChange() {
1483
+ if (this.onRangeChangeCallback) {
1484
+ this.onRangeChangeCallback();
1485
+ }
1486
+ }
1452
1487
  /**
1453
1488
  * Stop the animation and call the onDone callback if provided.
1454
1489
  */
@@ -1462,9 +1497,12 @@ var CesiumAnimatedProperty;
1462
1497
  }
1463
1498
  }
1464
1499
  /**
1465
- * Update function called on each frame.
1500
+ * Update function called on each render frame.
1466
1501
  */
1467
1502
  update() {
1503
+ if (!this.positions || this.positions.length === 0) {
1504
+ return;
1505
+ }
1468
1506
  let now = this.viewer.scene.lastRenderTime;
1469
1507
  if (!now) {
1470
1508
  now = this.viewer.clock.currentTime;
@@ -1506,11 +1544,19 @@ var CesiumAnimatedProperty;
1506
1544
  return posses;
1507
1545
  }
1508
1546
  /**
1509
- * Calculate the position at the given time
1547
+ * Calculate the position at the given time.
1510
1548
  */
1511
1549
  calculatePosition(currentTimeMs) {
1512
1550
  const posses = this.positions;
1513
- // See if we're before the first position
1551
+ // No positions to interpolate
1552
+ if (!posses || posses.length === 0) {
1553
+ return {
1554
+ pos3d: new Cartesian3(),
1555
+ indexLast: -1,
1556
+ indexNext: -1
1557
+ };
1558
+ }
1559
+ // See if we're before the first position.
1514
1560
  if (currentTimeMs <= posses[0].dateTime.getTime()) {
1515
1561
  return {
1516
1562
  pos3d: posses[0].pos3d,
@@ -1518,7 +1564,7 @@ var CesiumAnimatedProperty;
1518
1564
  indexNext: 0
1519
1565
  };
1520
1566
  }
1521
- // See if we're after the last position
1567
+ // See if we're after the last position.
1522
1568
  if (currentTimeMs >= posses[posses.length - 1].dateTime.getTime()) {
1523
1569
  const lastIndex = posses.length - 1;
1524
1570
  return {
@@ -1527,35 +1573,41 @@ var CesiumAnimatedProperty;
1527
1573
  indexNext: lastIndex
1528
1574
  };
1529
1575
  }
1530
- // Find the current position
1576
+ // Binary search to find the closest position.
1577
+ let start = 0;
1578
+ let end = posses.length - 1;
1531
1579
  let lastIndex = 0;
1532
- for (let i = 1; i < posses.length; i++) {
1533
- let pos = posses[i];
1534
- if (currentTimeMs >= pos.dateTime.getTime()) {
1535
- lastIndex = i;
1580
+ while (start <= end) {
1581
+ const mid = Math.floor((start + end) / 2);
1582
+ const midTime = posses[mid].dateTime.getTime();
1583
+ if (midTime <= currentTimeMs) {
1584
+ lastIndex = mid;
1585
+ start = mid + 1;
1536
1586
  }
1537
1587
  else {
1538
- break;
1588
+ end = mid - 1;
1539
1589
  }
1540
1590
  }
1541
1591
  const last = posses[lastIndex];
1542
- const next = posses[lastIndex + 1];
1543
- // If no next position, use the last one
1544
- if (!next) {
1592
+ const nextIndex = Math.min(lastIndex + 1, posses.length - 1);
1593
+ const next = posses[nextIndex];
1594
+ // If we found an exact match or there's no next position.
1595
+ if (currentTimeMs === last.dateTime.getTime() || lastIndex === nextIndex) {
1545
1596
  return {
1546
1597
  pos3d: last.pos3d,
1547
1598
  indexLast: lastIndex,
1548
1599
  indexNext: lastIndex
1549
1600
  };
1550
1601
  }
1551
- // Interpolate the position
1552
- const progress = (currentTimeMs - last.dateTime.getTime()) /
1553
- (next.dateTime.getTime() - last.dateTime.getTime());
1602
+ // Interpolate between the two closest positions.
1603
+ const lastTime = last.dateTime.getTime();
1604
+ const nextTime = next.dateTime.getTime();
1605
+ const progress = (currentTimeMs - lastTime) / (nextTime - lastTime);
1554
1606
  const interpolatedPos = Cartesian3.lerp(last.pos3d, next.pos3d, progress, new Cartesian3());
1555
1607
  return {
1556
1608
  pos3d: interpolatedPos,
1557
1609
  indexLast: lastIndex,
1558
- indexNext: lastIndex + 1
1610
+ indexNext: nextIndex
1559
1611
  };
1560
1612
  }
1561
1613
  /**
@@ -2738,13 +2790,38 @@ var EntityUtils;
2738
2790
  * Returns an array of positions from the entity's currently rendered graphics.
2739
2791
  */
2740
2792
  const evaluateRendered = async () => {
2793
+ var _a, _b;
2741
2794
  const rego = visualRegister ? visualRegister.GetRego({
2742
2795
  entityId: sample.entityId,
2743
2796
  menuItemId: sample.menuItemId
2744
2797
  }) : null;
2798
+ if (!rego) {
2799
+ return [];
2800
+ }
2801
+ // If this is a historic Entity but associated with a Tileset, we'll hack the movement in.
2802
+ // Our API doesn't account for this at the moment.
2803
+ if (rego.visual instanceof Cesium3DTileFeature && ((_a = rego.historicLayers) === null || _a === void 0 ? void 0 : _a.length)) {
2804
+ // Get the Tileset.
2805
+ const tileset = rego.visual.tileset;
2806
+ if (tileset === null || tileset === void 0 ? void 0 : tileset._bruceCoords) {
2807
+ // The render logic currently swaps out the UCS location when the assembly is moving.
2808
+ const location = (_b = tileset._bruceCoords.ucs) === null || _b === void 0 ? void 0 : _b.location;
2809
+ if (location) {
2810
+ const latitude = EnsureNumber(location.latitude);
2811
+ const longitude = EnsureNumber(location.longitude);
2812
+ // Disallowing exact 0.
2813
+ if (latitude || longitude) {
2814
+ const pos3d = Cartesian3.fromDegrees(longitude, latitude, EnsureNumber(location.altitude));
2815
+ const toAdjust = [pos3d];
2816
+ await ensureHeightRefs(toAdjust, sample);
2817
+ return toAdjust;
2818
+ }
2819
+ }
2820
+ }
2821
+ }
2745
2822
  let posses = [];
2746
2823
  const parts = GatherEntity({
2747
- entity: rego === null || rego === void 0 ? void 0 : rego.visual,
2824
+ entity: rego.visual,
2748
2825
  });
2749
2826
  for (let i = 0; i < parts.length; i++) {
2750
2827
  const part = parts[i];
@@ -5213,6 +5290,12 @@ async function getStyle(api, entity, styleId) {
5213
5290
 
5214
5291
  const CESIUM_INSPECTOR_KEY = "_nextspace_inspector";
5215
5292
  const CESIUM_TIMELINE_KEY = "_nextspace_timeline";
5293
+ const CESIUM_TIMELINE_LIVE_KEY = "_nextspace_timeline_live";
5294
+ const CESIUM_TIMELINE_LIVE_PADDING_FORWARD_KEY = "_nextspace_timeline_live_padding_forward";
5295
+ const CESIUM_TIMELINE_LIVE_PADDING_BACKWARD_KEY = "_nextspace_timeline_live_padding_backward";
5296
+ const CESIUM_TIMELINE_INTERVAL_KEY = "_nextspace_timeline_interval";
5297
+ const DEFAULT_LIVE_PADDING_FORWARD_SECONDS = 5 * 60;
5298
+ const DEFAULT_LIVE_PADDING_BACKWARD_SECONDS = 25 * 60;
5216
5299
  var ViewUtils;
5217
5300
  (function (ViewUtils) {
5218
5301
  function GatherLegacyMapTiles(params) {
@@ -5435,7 +5518,10 @@ var ViewUtils;
5435
5518
  currentTimeIso: clock.currentTime.toString(),
5436
5519
  stopTime: clock.stopTime,
5437
5520
  stopTimeIso: clock.stopTime.toString(),
5438
- areCesiumValues: clock[CESIUM_TIMELINE_KEY] != true
5521
+ areCesiumValues: clock[CESIUM_TIMELINE_KEY] != true,
5522
+ isLive: clock[CESIUM_TIMELINE_LIVE_KEY] == true,
5523
+ livePaddingForwardSeconds: clock[CESIUM_TIMELINE_LIVE_PADDING_FORWARD_KEY] || DEFAULT_LIVE_PADDING_FORWARD_SECONDS,
5524
+ livePaddingBackwardSeconds: clock[CESIUM_TIMELINE_LIVE_PADDING_BACKWARD_KEY] || DEFAULT_LIVE_PADDING_BACKWARD_SECONDS
5439
5525
  };
5440
5526
  }
5441
5527
  ViewUtils.GetTimeDetails = GetTimeDetails;
@@ -5493,8 +5579,59 @@ var ViewUtils;
5493
5579
  }
5494
5580
  viewer.scene.requestRender();
5495
5581
  clock[CESIUM_TIMELINE_KEY] = true;
5582
+ clock[CESIUM_TIMELINE_LIVE_KEY] = params.isLive == true;
5583
+ clock[CESIUM_TIMELINE_LIVE_PADDING_FORWARD_KEY] = params.livePaddingSeconds || DEFAULT_LIVE_PADDING_FORWARD_SECONDS;
5584
+ clock[CESIUM_TIMELINE_LIVE_PADDING_BACKWARD_KEY] = params.livePaddingSeconds || DEFAULT_LIVE_PADDING_BACKWARD_SECONDS;
5585
+ if (params.isLive) {
5586
+ startLive(viewer);
5587
+ }
5588
+ else {
5589
+ stopLive(viewer);
5590
+ }
5496
5591
  }
5497
5592
  ViewUtils.SetTimeDetails = SetTimeDetails;
5593
+ function startLive(viewer) {
5594
+ if (viewer[CESIUM_TIMELINE_INTERVAL_KEY]) {
5595
+ // Already live.
5596
+ return;
5597
+ }
5598
+ const doUpdate = () => {
5599
+ if (!viewer || viewer.isDestroyed() || !viewer.scene) {
5600
+ stopLive(viewer);
5601
+ return;
5602
+ }
5603
+ // Get the current settings.
5604
+ const tDetails = GetTimeDetails({ viewer });
5605
+ const clock = viewer.clock;
5606
+ if (clock) {
5607
+ clock.shouldAnimate = true;
5608
+ clock.multiplier = 1;
5609
+ clock.currentTime = JulianDate.now();
5610
+ clock.startTime = JulianDate.addSeconds(clock.currentTime, -tDetails.livePaddingBackwardSeconds, new JulianDate());
5611
+ clock.stopTime = JulianDate.addSeconds(clock.currentTime, tDetails.livePaddingForwardSeconds, new JulianDate());
5612
+ clock.clockRange = ClockRange.UNBOUNDED;
5613
+ }
5614
+ };
5615
+ // We'll start an interval that occasionally updates the Cesium clock to stay in the desired settings.
5616
+ // Since it moves live (1 second per second), we don't have to worry about the ranges being out of date quickly.
5617
+ viewer[CESIUM_TIMELINE_INTERVAL_KEY] = setInterval(() => {
5618
+ doUpdate();
5619
+ }, 800);
5620
+ viewer[CESIUM_TIMELINE_LIVE_KEY] = true;
5621
+ // Initial update.
5622
+ doUpdate();
5623
+ }
5624
+ function stopLive(viewer) {
5625
+ if (!viewer) {
5626
+ return;
5627
+ }
5628
+ let interval = viewer[CESIUM_TIMELINE_INTERVAL_KEY];
5629
+ if (interval) {
5630
+ clearInterval(interval);
5631
+ viewer[CESIUM_TIMELINE_INTERVAL_KEY] = null;
5632
+ }
5633
+ viewer[CESIUM_TIMELINE_LIVE_KEY] = false;
5634
+ }
5498
5635
  })(ViewUtils || (ViewUtils = {}));
5499
5636
 
5500
5637
  const MODEL_MIN_RADIUS = 10;
@@ -17134,7 +17271,7 @@ var TilesetCadRenderManager;
17134
17271
  this.viewerDateTimeChangeRemoval = null;
17135
17272
  // Series of points to help interpolate movement when the timeline changes.
17136
17273
  this.historicPosses = [];
17137
- this.historicPossesLoading = false;
17274
+ this.historicAnimation = null;
17138
17275
  this.historicPossesLoadingProm = null;
17139
17276
  const { viewer, register: visualsManager, getters, item } = params;
17140
17277
  this.viewer = viewer;
@@ -17591,7 +17728,7 @@ var TilesetCadRenderManager;
17591
17728
  /**
17592
17729
  * Monitors the Cesium Viewer and updates the root Entity based on the scene time changing.
17593
17730
  * If the root Entity is historic, this can allow for movement of the assembly as a whole.
17594
- * @parma tileset
17731
+ * @param tileset
17595
17732
  */
17596
17733
  viewerDateTimeSub(tileset) {
17597
17734
  var _a, _b;
@@ -17605,60 +17742,172 @@ var TilesetCadRenderManager;
17605
17742
  const api = this.getters.GetBruceApi({
17606
17743
  accountId: accountId
17607
17744
  });
17608
- // Returns a series of positions to use for position interpolation based on time.
17609
- // If the timeline range is different to the previous query, we'll re-request the data.
17610
- const getSeriesPosses = async () => {
17745
+ // 'start-stop' time string that maps to a pending request.
17746
+ // Helps us avoid repeated requests that are the same.
17747
+ const pendingRequests = new Map();
17748
+ /**
17749
+ * Returns a list of historic positions for a given time range.
17750
+ * @param startStr
17751
+ * @param stopStr
17752
+ * @returns
17753
+ */
17754
+ const getPossesForRange = async (startStr, stopStr) => {
17755
+ const requestKey = `${startStr}-${stopStr}`;
17756
+ if (pendingRequests.has(requestKey)) {
17757
+ return pendingRequests.get(requestKey);
17758
+ }
17759
+ const requestPromise = new Promise(async (res) => {
17760
+ try {
17761
+ const historicData = await EntityHistoricData.GetList({
17762
+ attrKey: null,
17763
+ dateTimeFrom: startStr,
17764
+ dateTimeTo: stopStr,
17765
+ entityIds: [this.rootId],
17766
+ api: api
17767
+ });
17768
+ const posses = CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(this.viewer, HeightReference.NONE, historicData.recordsByIds[this.rootId]);
17769
+ res(posses);
17770
+ }
17771
+ catch (e) {
17772
+ console.error(e);
17773
+ res([]);
17774
+ }
17775
+ finally {
17776
+ pendingRequests.delete(requestKey);
17777
+ }
17778
+ });
17779
+ pendingRequests.set(requestKey, requestPromise);
17780
+ return requestPromise;
17781
+ };
17782
+ /**
17783
+ * Checks if the current timeline range is not fully loaded and requests the difference.
17784
+ * This will call getPossesForRange() if it needs more data.
17785
+ * @returns
17786
+ */
17787
+ const checkTimelineRange = async () => {
17611
17788
  const minDateTime = this.viewer.clock.startTime.toString();
17612
17789
  const maxDateTime = this.viewer.clock.stopTime.toString();
17613
- if (this.historicPossesMinDateTime == minDateTime &&
17614
- this.historicPossesMaxDateTime == maxDateTime) {
17615
- if (this.historicPossesLoading) {
17616
- if (!await this.historicPossesLoadingProm) {
17617
- return false;
17618
- }
17619
- }
17620
- return this.historicPosses;
17790
+ // See if the current range is within the range we already have.
17791
+ if (this.historicPosses.length > 0 &&
17792
+ this.historicPossesMinDateTime &&
17793
+ this.historicPossesMaxDateTime &&
17794
+ minDateTime >= this.historicPossesMinDateTime &&
17795
+ maxDateTime <= this.historicPossesMaxDateTime) {
17796
+ return;
17621
17797
  }
17622
- this.historicPossesMinDateTime = minDateTime;
17623
- this.historicPossesMaxDateTime = maxDateTime;
17624
- this.historicPossesLoading = true;
17625
- this.historicPossesLoadingProm = new Promise(async (res) => {
17626
- // We'll add/remove 1 second to ensure we cover all records.
17798
+ // See if the requested range is before or after the range we have.
17799
+ const fetchBefore = !this.historicPossesMinDateTime || minDateTime < this.historicPossesMinDateTime;
17800
+ const fetchAfter = !this.historicPossesMaxDateTime || maxDateTime > this.historicPossesMaxDateTime;
17801
+ if (!fetchBefore && !fetchAfter) {
17802
+ // Already have the data we need.
17803
+ return;
17804
+ }
17805
+ // No known range so we need to fetch the whole thing.
17806
+ if (!this.historicPossesMinDateTime || !this.historicPossesMaxDateTime) {
17627
17807
  const startTmp = JulianDate.toDate(this.viewer.clock.startTime);
17628
17808
  const stopTmp = JulianDate.toDate(this.viewer.clock.stopTime);
17629
17809
  const startStr = new Date(startTmp.getTime() - 1000).toISOString();
17630
17810
  const stopStr = new Date(stopTmp.getTime() + 1000).toISOString();
17631
- const historicData = await EntityHistoricData.GetList({
17632
- attrKey: null,
17633
- dateTimeFrom: startStr,
17634
- dateTimeTo: stopStr,
17635
- entityIds: [this.rootId],
17636
- api: api
17637
- });
17638
- const posses = CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(this.viewer, HeightReference.NONE, historicData.recordsByIds[this.rootId]);
17639
- if (this.historicPossesMinDateTime == minDateTime &&
17640
- this.historicPossesMaxDateTime == maxDateTime) {
17641
- this.historicPosses = posses;
17811
+ const newPositions = await getPossesForRange(startStr, stopStr);
17812
+ if (this.disposed) {
17813
+ return;
17814
+ }
17815
+ if (this.historicAnimation && this.historicAnimation.addPositions) {
17816
+ this.historicAnimation.addPositions(newPositions);
17817
+ }
17818
+ this.historicPossesMinDateTime = minDateTime;
17819
+ this.historicPossesMaxDateTime = maxDateTime;
17820
+ }
17821
+ else {
17822
+ // The data we want is before the range we've currently loaded.
17823
+ if (fetchBefore) {
17824
+ // Calculate the missing difference and request it.
17825
+ const startTmp = JulianDate.toDate(this.viewer.clock.startTime);
17826
+ const stopTmp = new Date(this.historicPossesMinDateTime);
17827
+ const startStr = new Date(startTmp.getTime() - 1000).toISOString();
17828
+ const stopStr = stopTmp.toISOString();
17829
+ getPossesForRange(startStr, stopStr).then(newPositions => {
17830
+ if (this.disposed) {
17831
+ return;
17832
+ }
17833
+ this.historicPossesMinDateTime = minDateTime;
17834
+ if (this.historicAnimation && this.historicAnimation.addPositions) {
17835
+ this.historicAnimation.addPositions(newPositions);
17836
+ }
17837
+ });
17838
+ }
17839
+ // The data we want is after the range we've currently loaded.
17840
+ if (fetchAfter) {
17841
+ // Calculate the missing difference and request it.
17842
+ const startTmp = new Date(this.historicPossesMaxDateTime);
17843
+ const stopTmp = JulianDate.toDate(this.viewer.clock.stopTime);
17844
+ const startStr = startTmp.toISOString();
17845
+ const stopStr = new Date(stopTmp.getTime() + 1000).toISOString();
17846
+ getPossesForRange(startStr, stopStr).then(newPositions => {
17847
+ if (this.disposed) {
17848
+ return;
17849
+ }
17850
+ this.historicPossesMaxDateTime = maxDateTime;
17851
+ if (this.historicAnimation && this.historicAnimation.addPositions) {
17852
+ this.historicAnimation.addPositions(newPositions);
17853
+ }
17854
+ });
17855
+ }
17856
+ }
17857
+ };
17858
+ /**
17859
+ * Requests the initial set of historic positions for the timeline range.
17860
+ * This is called when the tileset is loaded and the timeline range is set.
17861
+ * @returns
17862
+ */
17863
+ const getInitialPosses = async () => {
17864
+ const minDateTime = this.viewer.clock.startTime.toString();
17865
+ const maxDateTime = this.viewer.clock.stopTime.toString();
17866
+ this.historicPossesLoadingProm = new Promise(async (res) => {
17867
+ try {
17868
+ if (this.disposed) {
17869
+ res(false);
17870
+ return;
17871
+ }
17872
+ const startTmp = JulianDate.toDate(this.viewer.clock.startTime);
17873
+ const stopTmp = JulianDate.toDate(this.viewer.clock.stopTime);
17874
+ const startStr = new Date(startTmp.getTime() - 1000).toISOString();
17875
+ const stopStr = new Date(stopTmp.getTime() + 1000).toISOString();
17876
+ const positions = await getPossesForRange(startStr, stopStr);
17877
+ if (this.disposed) {
17878
+ res(false);
17879
+ return;
17880
+ }
17881
+ this.historicPosses = positions;
17642
17882
  this.historicPossesMinDateTime = minDateTime;
17643
17883
  this.historicPossesMaxDateTime = maxDateTime;
17644
- this.historicPossesLoading = false;
17645
- res(posses);
17884
+ res(positions);
17885
+ }
17886
+ catch (e) {
17887
+ console.error(e);
17888
+ res(false);
17646
17889
  }
17647
- res(false);
17648
17890
  });
17649
17891
  return await this.historicPossesLoadingProm;
17650
17892
  };
17651
- getSeriesPosses().then((posses) => {
17893
+ // Last known timeline range. Helps us detect changes.
17894
+ let lastStartTime = this.viewer.clock.startTime.toString();
17895
+ let lastStopTime = this.viewer.clock.stopTime.toString();
17896
+ let clockTickRemoval;
17897
+ getInitialPosses().then((posses) => {
17652
17898
  if (this.disposed || posses === false) {
17653
17899
  return;
17654
17900
  }
17655
- let animation = new CesiumAnimatedProperty.AnimateTPositionSeries({
17901
+ // Generate animation utility for the initial set of positions.
17902
+ this.historicAnimation = new CesiumAnimatedProperty.AnimateTPositionSeries({
17656
17903
  viewer: this.viewer,
17657
17904
  posses: posses,
17658
17905
  onUpdate: (pos3d, heading) => {
17659
17906
  if (this.disposed) {
17660
17907
  return;
17661
17908
  }
17909
+ // Jank code that hacks the position to be different.
17910
+ // This can mess up our panels so we'll need to disable editing until a better system is in place.
17662
17911
  const location = Cartographic.fromCartesian(pos3d);
17663
17912
  const lat = Math$1.toDegrees(location.latitude);
17664
17913
  const lon = Math$1.toDegrees(location.longitude);
@@ -17685,12 +17934,35 @@ var TilesetCadRenderManager;
17685
17934
  }
17686
17935
  };
17687
17936
  this.applyCoords(tileset, coords);
17937
+ },
17938
+ onRangeChange: () => {
17939
+ checkTimelineRange();
17940
+ },
17941
+ onDone: () => {
17942
+ if (this.viewerDateTimeChangeRemoval) {
17943
+ this.viewerDateTimeChangeRemoval();
17944
+ this.viewerDateTimeChangeRemoval = null;
17945
+ }
17946
+ }
17947
+ });
17948
+ // When the clock changes we'll see if the range is different and queue a request for the difference.
17949
+ clockTickRemoval = this.viewer.clock.onTick.addEventListener(() => {
17950
+ const startTime = this.viewer.clock.startTime.toString();
17951
+ const stopTime = this.viewer.clock.stopTime.toString();
17952
+ if (startTime !== lastStartTime || stopTime !== lastStopTime) {
17953
+ lastStartTime = startTime;
17954
+ lastStopTime = stopTime;
17955
+ this.historicAnimation.onRangeChange();
17688
17956
  }
17689
17957
  });
17690
17958
  this.viewerDateTimeChangeRemoval = () => {
17691
- if (animation) {
17692
- animation.stop();
17693
- animation = null;
17959
+ if (this.historicAnimation) {
17960
+ this.historicAnimation.stop();
17961
+ this.historicAnimation = null;
17962
+ }
17963
+ if (clockTickRemoval) {
17964
+ clockTickRemoval();
17965
+ clockTickRemoval = null;
17694
17966
  }
17695
17967
  };
17696
17968
  });
@@ -24651,7 +24923,8 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
24651
24923
  end: null,
24652
24924
  playing: false,
24653
24925
  speed: 1,
24654
- start: null
24926
+ start: null,
24927
+ live: false
24655
24928
  };
24656
24929
  }
24657
24930
  ViewUtils.SetTimeDetails({
@@ -24660,7 +24933,8 @@ async function renderNavigator(iteration, params, bookmark, view, getters) {
24660
24933
  currentTimeIso: dateTime,
24661
24934
  startTimeIso: timeline.start,
24662
24935
  stopTimeIso: timeline.end,
24663
- isAnimating: timeline.playing
24936
+ isAnimating: timeline.playing,
24937
+ isLive: timeline.live
24664
24938
  });
24665
24939
  // Newer version that has states per Entity ID + Menu Item ID.
24666
24940
  let states = bSettings === null || bSettings === void 0 ? void 0 : bSettings.states;
@@ -30476,7 +30750,7 @@ class WidgetViewBar extends Widget.AWidget {
30476
30750
  }
30477
30751
  }
30478
30752
 
30479
- const VERSION = "5.3.9";
30753
+ const VERSION = "5.4.1";
30480
30754
 
30481
- export { VERSION, CesiumViewMonitor, ViewerUtils, ViewerEventTracker, MenuItemManager, isHistoricMetadataChanged, EntityRenderEngine, EntityRenderEnginePoint, EntityRenderEnginePolyline, EntityRenderEnginePolygon, EntityRenderEngineModel3d, MenuItemCreator, VisualsRegister, RenderManager, EntitiesIdsRenderManager, DataLabRenderManager, EntitiesLoadedRenderManager, EntitiesRenderManager, EntityRenderManager, TilesetCadRenderManager, TilesetArbRenderManager, TilesetEntitiesRenderManager, TilesetOsmRenderManager, TilesetPointcloudRenderManager, TilesetGooglePhotosRenderManager, DataSourceStaticKmlManager, GoogleSearchRenderManager, RelationsRenderManager, SharedGetters, CesiumParabola, EntityLabel, ViewRenderEngine, TileRenderEngine, TilesetRenderEngine, CESIUM_INSPECTOR_KEY, CESIUM_TIMELINE_KEY, ViewUtils, DrawingUtils, MeasureUtils, EntityUtils, CesiumEntityStyler, CesiumAnimatedProperty, CesiumAnimatedInOut, Draw3dPolygon, Draw3dPolyline, MeasureCreator, Walkthrough, Widget, VIEWER_BOOKMARKS_WIDGET_KEY, WidgetBookmarks, WidgetBranding, WidgetCursorBar, WidgetEmbeddedInfoView, WidgetInfoView, WidgetNavCompass$$1 as WidgetNavCompass, VIEWER_VIEW_BAR_WIDGET_KEY, WidgetViewBar, WidgetControlViewBar, WidgetControlViewBarSearch, VIEWER_LEFT_PANEL_WIDGET_KEY, VIEWER_LEFT_PANEL_CSS_VAR_LEFT, WidgetLeftPanel, WidgetLeftPanelTab, WidgetLeftPanelTabBookmarks };
30755
+ export { VERSION, CesiumViewMonitor, ViewerUtils, ViewerEventTracker, MenuItemManager, isHistoricMetadataChanged, EntityRenderEngine, EntityRenderEnginePoint, EntityRenderEnginePolyline, EntityRenderEnginePolygon, EntityRenderEngineModel3d, MenuItemCreator, VisualsRegister, RenderManager, EntitiesIdsRenderManager, DataLabRenderManager, EntitiesLoadedRenderManager, EntitiesRenderManager, EntityRenderManager, TilesetCadRenderManager, TilesetArbRenderManager, TilesetEntitiesRenderManager, TilesetOsmRenderManager, TilesetPointcloudRenderManager, TilesetGooglePhotosRenderManager, DataSourceStaticKmlManager, GoogleSearchRenderManager, RelationsRenderManager, SharedGetters, CesiumParabola, EntityLabel, ViewRenderEngine, TileRenderEngine, TilesetRenderEngine, CESIUM_INSPECTOR_KEY, CESIUM_TIMELINE_KEY, CESIUM_TIMELINE_LIVE_KEY, CESIUM_TIMELINE_LIVE_PADDING_FORWARD_KEY, CESIUM_TIMELINE_LIVE_PADDING_BACKWARD_KEY, CESIUM_TIMELINE_INTERVAL_KEY, ViewUtils, DrawingUtils, MeasureUtils, EntityUtils, CesiumEntityStyler, CesiumAnimatedProperty, CesiumAnimatedInOut, Draw3dPolygon, Draw3dPolyline, MeasureCreator, Walkthrough, Widget, VIEWER_BOOKMARKS_WIDGET_KEY, WidgetBookmarks, WidgetBranding, WidgetCursorBar, WidgetEmbeddedInfoView, WidgetInfoView, WidgetNavCompass$$1 as WidgetNavCompass, VIEWER_VIEW_BAR_WIDGET_KEY, WidgetViewBar, WidgetControlViewBar, WidgetControlViewBarSearch, VIEWER_LEFT_PANEL_WIDGET_KEY, VIEWER_LEFT_PANEL_CSS_VAR_LEFT, WidgetLeftPanel, WidgetLeftPanelTab, WidgetLeftPanelTabBookmarks };
30482
30756
  //# sourceMappingURL=bruce-cesium.es5.js.map