terriajs
Version:
Geospatial data visualization platform.
236 lines • 9.37 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { action, autorun, computed, makeObservable, observable } from "mobx";
import ClockRange from "terriajs-cesium/Source/Core/ClockRange";
import JulianDate from "terriajs-cesium/Source/Core/JulianDate";
import filterOutUndefined from "../Core/filterOutUndefined";
import ReferenceMixin from "../ModelMixins/ReferenceMixin";
import { DATE_SECONDS_PRECISION } from "../ModelMixins/TimeVarying";
import DefaultTimelineModel from "./DefaultTimelineModel";
import CommonStrata from "./Definition/CommonStrata";
const DEFAULT_TIMELINE_MODEL_ID = "defaultTimeline";
/**
* Manages a stack of all the time-varying datasets currently attached to the timeline. Provides
* access to the current top dataset so that it can be displayed to the user.
*
* @constructor
*/
export default class TimelineStack {
terria;
clock;
/**
* The stratum of each layer in the stack in which to store the current time as the clock ticks.
*/
tickStratumId = CommonStrata.user;
items = [];
defaultTimeVarying;
_disposeClockAutorun;
_disposeTickSubscription;
constructor(terria, clock) {
this.terria = terria;
this.clock = clock;
makeObservable(this);
}
activate() {
// Keep the Cesium clock in sync with the top layer's clock.
this._disposeClockAutorun = autorun(() => {
const topLayer = this.top;
if (!topLayer || !topLayer.currentTimeAsJulianDate) {
this.clock.shouldAnimate = false;
return;
}
this.clock.currentTime = JulianDate.clone(topLayer.currentTimeAsJulianDate, this.clock.currentTime);
this.clock.startTime = offsetIfUndefined(-43200.0, topLayer.currentTimeAsJulianDate, topLayer.startTimeAsJulianDate, this.clock.startTime);
this.clock.stopTime = offsetIfUndefined(43200.0, topLayer.currentTimeAsJulianDate, topLayer.stopTimeAsJulianDate, this.clock.stopTime);
if (topLayer.multiplier !== undefined) {
this.clock.multiplier = topLayer.multiplier;
}
else {
this.clock.multiplier = 60.0;
}
this.clock.shouldAnimate = !topLayer.isPaused;
this.clock.clockRange = ClockRange.LOOP_STOP;
if (this._disposeTickSubscription === undefined) {
// We should start synchronizing only after first run of this autorun so that
// the clock parameters are set correctly.
this._disposeTickSubscription = this.clock.onTick.addEventListener(() => {
this.syncToClock(this.tickStratumId);
});
}
});
}
deactivate() {
if (this._disposeClockAutorun) {
this._disposeClockAutorun();
}
if (this._disposeTickSubscription) {
this._disposeTickSubscription();
this._disposeTickSubscription = undefined;
}
}
/**
* The topmost time-series layer, or undefined if there is no such layer in the stack.
*/
get top() {
// Find the first item with a current, start, and stop time.
// Use the default if there isn't one.
return (this.items.find((item) => {
const dereferenced = ReferenceMixin.isMixedInto(item) && item.target
? item.target
: item;
return (dereferenced.currentTimeAsJulianDate !== undefined &&
dereferenced.startTimeAsJulianDate !== undefined &&
dereferenced.stopTimeAsJulianDate !== undefined);
}) || this.defaultTimeVarying);
}
get itemIds() {
return filterOutUndefined(this.items.map((item) => item.uniqueId));
}
/**
* Determines if the stack contains a given item.
* @param item The item to check.
* @returns True if the stack contains the item; otherwise, false.
*/
contains(item) {
return this.items.indexOf(item) >= 0;
}
/**
* Adds the supplied {@link TimeVarying} to the top of the stack. If the item is already in the stack, it will be moved
* rather than added twice.
*
* @param item
*/
addToTop(item) {
const currentIndex = this.items.indexOf(item);
this.items.unshift(item);
if (currentIndex > -1) {
this.items.splice(currentIndex, 1);
}
}
/**
* Removes a layer from the stack, no matter what its location. If the layer is currently at the top, the value of
* {@link TimelineStack#topLayer} will change.
*
* @param item;
*/
remove(item) {
const index = this.items.indexOf(item);
this.items.splice(index, 1);
}
/**
* Removes all layers.
*/
removeAll() {
this.items = [];
}
/**
* Promotes the supplied {@link CatalogItem} to the top of the stack if it is already in the stack. If the item is not
* already in the stack it won't be added.
*
* @param item
*/
promoteToTop(item) {
const currentIndex = this.items.indexOf(item);
if (currentIndex > -1) {
this.addToTop(item);
}
}
/**
* Synchronizes all layers in the stack to the current time and the paused state of the provided clock.
* Synchronizes the {@link TimelineStack#top} to the clock's `startTime`, `endTime`, and `multiplier`.
* @param stratumId The stratum in which to modify properties.
* @param clock The clock to sync to.
*/
syncToClock(stratumId) {
const clock = this.clock;
const currentTime = JulianDate.toIso8601(clock.currentTime, DATE_SECONDS_PRECISION);
const isPaused = !clock.shouldAnimate;
if (this.top) {
this.top.setTrait(stratumId, "startTime", JulianDate.toIso8601(clock.startTime, DATE_SECONDS_PRECISION));
this.top.setTrait(stratumId, "stopTime", JulianDate.toIso8601(clock.stopTime, DATE_SECONDS_PRECISION));
this.top.setTrait(stratumId, "multiplier", clock.multiplier);
}
for (let i = 0; i < this.items.length; ++i) {
const layer = this.items[i];
layer.setTrait(stratumId, "currentTime", currentTime);
layer.setTrait(stratumId, "isPaused", isPaused);
}
if (this.defaultTimeVarying) {
this.defaultTimeVarying.setTrait(stratumId, "currentTime", currentTime);
this.defaultTimeVarying.setTrait(stratumId, "isPaused", isPaused);
}
}
setAlwaysShowTimeline(show = true) {
if (show) {
this.defaultTimeVarying = this.getOrCreateDefaultTimelineModel();
}
else {
if (this.defaultTimeVarying) {
// Unregister the model so that it doesn't appear in share links
this.terria.removeModelReferences(this.defaultTimeVarying);
}
this.defaultTimeVarying = undefined;
}
this.terria.currentViewer.notifyRepaintRequired();
}
get alwaysShowingTimeline() {
return (this.defaultTimeVarying !== undefined &&
this.defaultTimeVarying.startTimeAsJulianDate !== undefined &&
this.defaultTimeVarying.stopTimeAsJulianDate !== undefined &&
this.defaultTimeVarying.currentTimeAsJulianDate !== undefined);
}
getOrCreateDefaultTimelineModel() {
let model = this.terria.getModelById(DefaultTimelineModel, DEFAULT_TIMELINE_MODEL_ID);
if (!model) {
model = new DefaultTimelineModel(DEFAULT_TIMELINE_MODEL_ID, this.terria);
this.terria.addModel(model);
}
return model;
}
}
__decorate([
observable
], TimelineStack.prototype, "items", void 0);
__decorate([
observable
], TimelineStack.prototype, "defaultTimeVarying", void 0);
__decorate([
computed
], TimelineStack.prototype, "top", null);
__decorate([
computed
], TimelineStack.prototype, "itemIds", null);
__decorate([
action
], TimelineStack.prototype, "addToTop", null);
__decorate([
action
], TimelineStack.prototype, "remove", null);
__decorate([
action
], TimelineStack.prototype, "removeAll", null);
__decorate([
action
], TimelineStack.prototype, "promoteToTop", null);
__decorate([
action
], TimelineStack.prototype, "syncToClock", null);
__decorate([
action
], TimelineStack.prototype, "setAlwaysShowTimeline", null);
__decorate([
computed
], TimelineStack.prototype, "alwaysShowingTimeline", null);
function offsetIfUndefined(offsetSeconds, baseTime, time, result) {
if (time === undefined) {
return JulianDate.addSeconds(baseTime, offsetSeconds, result || new JulianDate());
}
else {
return JulianDate.clone(time, result);
}
}
//# sourceMappingURL=TimelineStack.js.map