|
|
|
|
@@ -61,11 +61,25 @@
|
|
|
|
|
<div class="c-imagery__control-bar">
|
|
|
|
|
<div class="c-imagery__time">
|
|
|
|
|
<div class="c-imagery__timestamp u-style-receiver js-style-receiver">{{ time }}</div>
|
|
|
|
|
<!-- Imagery Age Freshness -->
|
|
|
|
|
<div
|
|
|
|
|
v-if="canTrackDuration"
|
|
|
|
|
:class="{'c-imagery--new': isImageNew && !refreshCSS}"
|
|
|
|
|
class="c-imagery__age icon-timer"
|
|
|
|
|
>{{ formattedDuration }}</div>
|
|
|
|
|
<!-- Rover Position Freshness -->
|
|
|
|
|
<div>isFresh {{ roverPositionIsFresh }}</div>
|
|
|
|
|
<div
|
|
|
|
|
v-if="roverPositionIsFresh !== undefined"
|
|
|
|
|
:class="{'c-imagery--new': roverPositionIsFresh}"
|
|
|
|
|
class="c-imagery__age icon-timer"
|
|
|
|
|
>{{ roverPositionIsFresh ? 'ROVER' : '' }}</div>
|
|
|
|
|
<!-- Rover Camera Position Freshness -->
|
|
|
|
|
<div
|
|
|
|
|
v-if="cameraPositionIsFresh !== undefined"
|
|
|
|
|
:class="{'c-imagery--new': cameraPositionIsFresh && !refreshCSS}"
|
|
|
|
|
class="c-imagery__age icon-timer"
|
|
|
|
|
>{{ formattedDuration }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="h-local-controls">
|
|
|
|
|
<button
|
|
|
|
|
@@ -116,7 +130,7 @@ const ARROW_RIGHT = 39;
|
|
|
|
|
const ARROW_LEFT = 37;
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
inject: ['openmct', 'domainObject'],
|
|
|
|
|
inject: ['openmct', 'domainObject', 'configuration'],
|
|
|
|
|
data() {
|
|
|
|
|
let timeSystem = this.openmct.time.timeSystem();
|
|
|
|
|
|
|
|
|
|
@@ -137,7 +151,14 @@ export default {
|
|
|
|
|
refreshCSS: false,
|
|
|
|
|
keyString: undefined,
|
|
|
|
|
focusedImageIndex: undefined,
|
|
|
|
|
numericDuration: undefined
|
|
|
|
|
numericDuration: undefined,
|
|
|
|
|
metadataEndpoints: {},
|
|
|
|
|
roverPositionIsFresh: undefined,
|
|
|
|
|
cameraPositionIsFresh: undefined,
|
|
|
|
|
roverPositionState: {},
|
|
|
|
|
cameraPositionState: {},
|
|
|
|
|
canTrackRoverPositionFreshness: undefined,
|
|
|
|
|
canTrackCameraPositionFreshness: undefined
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
@@ -201,9 +222,11 @@ export default {
|
|
|
|
|
focusedImageIndex() {
|
|
|
|
|
this.trackDuration();
|
|
|
|
|
this.resetAgeCSS();
|
|
|
|
|
this.determineRoverFreshness();
|
|
|
|
|
this.determineCameraPositionFreshness();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
mounted() {
|
|
|
|
|
async mounted() {
|
|
|
|
|
// listen
|
|
|
|
|
this.openmct.time.on('bounds', this.boundsChange);
|
|
|
|
|
this.openmct.time.on('timeSystem', this.timeSystemChange);
|
|
|
|
|
@@ -212,16 +235,34 @@ export default {
|
|
|
|
|
// set
|
|
|
|
|
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
|
|
|
|
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
|
|
|
|
this.imageHints = this.metadata.valuesForHints(['image'])[0];
|
|
|
|
|
this.durationFormatter = this.getFormatter(this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
|
|
|
|
this.imageFormatter = this.openmct.telemetry.getValueFormatter(this.metadata.valuesForHints(['image'])[0]);
|
|
|
|
|
this.imageFormatter = this.openmct.telemetry.getValueFormatter(this.imageHints);
|
|
|
|
|
|
|
|
|
|
// DELETE WHEN DONE
|
|
|
|
|
this.temporaryForImageEnhancements();
|
|
|
|
|
|
|
|
|
|
// initialize
|
|
|
|
|
this.timeKey = this.timeSystem.key;
|
|
|
|
|
this.timeFormatter = this.getFormatter(this.timeKey);
|
|
|
|
|
this.roverPositionKeys = ['Rover Heading', 'Rover Roll', 'Rover Pitch', 'Rover Yaw'];
|
|
|
|
|
this.cameraPositionKeys = ['Camera Tilt', 'Camera Pan'];
|
|
|
|
|
|
|
|
|
|
// kickoff
|
|
|
|
|
this.subscribe();
|
|
|
|
|
this.requestHistory();
|
|
|
|
|
await this.initializeRelatedTelemetry();
|
|
|
|
|
|
|
|
|
|
// DELETE
|
|
|
|
|
// examples for requesting historical data for a relatedTelemetry key
|
|
|
|
|
// and for subscribing to a relatedTelemetry key
|
|
|
|
|
// example for 'Rover Heading'
|
|
|
|
|
// ***********************************************************************
|
|
|
|
|
// let results = await this.relatedTelemetry['Rover Heading'].request();
|
|
|
|
|
// this.relatedTelemetry['Rover Heading'].subscribe((data) => {
|
|
|
|
|
// console.log('subscribe test', data);
|
|
|
|
|
// });
|
|
|
|
|
// ***********************************************************************
|
|
|
|
|
},
|
|
|
|
|
updated() {
|
|
|
|
|
this.scrollToRight();
|
|
|
|
|
@@ -236,8 +277,148 @@ export default {
|
|
|
|
|
this.openmct.time.off('bounds', this.boundsChange);
|
|
|
|
|
this.openmct.time.off('timeSystem', this.timeSystemChange);
|
|
|
|
|
this.openmct.time.off('clock', this.clockChange);
|
|
|
|
|
|
|
|
|
|
// unsubscribe from related telemetry
|
|
|
|
|
if (this.hasRelatedTelemetry) {
|
|
|
|
|
for (let key of this.relatedTelemetry.keys) {
|
|
|
|
|
if (this.relatedTelemetry[key].unsubscribe) {
|
|
|
|
|
this.relatedTelemetry[key].unsubscribe();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// for local dev, to be DELETED
|
|
|
|
|
temporaryForImageEnhancements() {
|
|
|
|
|
let roverKeys = ['Rover Heading', 'Rover Roll', 'Rover Yaw', 'Rover Pitch'];
|
|
|
|
|
let cameraKeys = ['Camera Pan', 'Camera Tilt'];
|
|
|
|
|
|
|
|
|
|
this.searchService = this.openmct.$injector.get('searchService');
|
|
|
|
|
this.temporaryDev = true;
|
|
|
|
|
|
|
|
|
|
// mock related telemetry metadata
|
|
|
|
|
this.imageHints.relatedTelemetry = {};
|
|
|
|
|
|
|
|
|
|
// populate temp keys in imageHints for local testing
|
|
|
|
|
[...roverKeys, ...cameraKeys].forEach(key => {
|
|
|
|
|
|
|
|
|
|
this.imageHints.relatedTelemetry[key] = {
|
|
|
|
|
dev: true,
|
|
|
|
|
realtime: key,
|
|
|
|
|
historical: key,
|
|
|
|
|
devInit: async () => {
|
|
|
|
|
const searchResults = await this.searchService.query(key);
|
|
|
|
|
const endpoint = searchResults.hits[0].id;
|
|
|
|
|
const domainObject = await this.openmct.objects.get(endpoint);
|
|
|
|
|
|
|
|
|
|
return domainObject;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
async initializeRelatedTelemetry() {
|
|
|
|
|
if (this.imageHints.relatedTelemetry === undefined) {
|
|
|
|
|
this.hasRelatedTelemetry = false;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DELETE
|
|
|
|
|
if (this.temporaryDev) {
|
|
|
|
|
let searchIndexBuildDelay = new Promise((resolve, reject) => {
|
|
|
|
|
setTimeout(resolve, 3000);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await searchIndexBuildDelay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let keys = Object.keys(this.imageHints.relatedTelemetry);
|
|
|
|
|
|
|
|
|
|
this.hasRelatedTelemetry = true;
|
|
|
|
|
this.relatedTelemetry = {
|
|
|
|
|
keys,
|
|
|
|
|
...this.imageHints.relatedTelemetry
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// grab historical and subscribe to realtime
|
|
|
|
|
for (let key of keys) {
|
|
|
|
|
let historicalId = this.relatedTelemetry[key].historical;
|
|
|
|
|
let realtimeId = this.relatedTelemetry[key].realtime;
|
|
|
|
|
let sameId = false;
|
|
|
|
|
|
|
|
|
|
if (historicalId && realtimeId && historicalId === realtimeId) {
|
|
|
|
|
|
|
|
|
|
// DELETE temp
|
|
|
|
|
if (this.relatedTelemetry[key].dev) {
|
|
|
|
|
this.relatedTelemetry[key].historicalDomainObject = await this.relatedTelemetry[key].devInit();
|
|
|
|
|
delete this.relatedTelemetry[key].dev;
|
|
|
|
|
delete this.relatedTelemetry[key].devInit;
|
|
|
|
|
} else {
|
|
|
|
|
this.relatedTelemetry[key].historicalDomainObject = await this.openmct.objects.get(historicalId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.relatedTelemetry[key].realtimeDomainObject = this.relatedTelemetry[key].historicalDomainObject;
|
|
|
|
|
sameId = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (historicalId) {
|
|
|
|
|
// check for on-telemetry data
|
|
|
|
|
if (historicalId[0] === '.') {
|
|
|
|
|
this.relatedTelemetry[key].valueOnTelemetry = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sameId) {
|
|
|
|
|
this.relatedTelemetry[key].historicalDomainObject = await this.openmct.objects.get(historicalId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.relatedTelemetry[key].request = async (options) => {
|
|
|
|
|
let results = await this.openmct.telemetry
|
|
|
|
|
.request(this.relatedTelemetry[key].historicalDomainObject, options);
|
|
|
|
|
|
|
|
|
|
return results;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (realtimeId) {
|
|
|
|
|
|
|
|
|
|
// set up listeners
|
|
|
|
|
this.relatedTelemetry[key].listeners = [];
|
|
|
|
|
this.relatedTelemetry[key].subscribe = (callback) => {
|
|
|
|
|
if (!this.relatedTelemetry[key].listeners.includes(callback)) {
|
|
|
|
|
this.relatedTelemetry[key].listeners.push(callback);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
this.relatedTelemetry[key].listeners.remove(callback);
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
return () => {};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!sameId) {
|
|
|
|
|
this.relatedTelemetry[key].realtimeDomainObject = await this.openmct.objects.get(realtimeId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.relatedTelemetry[key].unsubscribe = this.openmct.telemetry.subscribe(
|
|
|
|
|
this.relatedTelemetry[key].realtimeDomainObject,
|
|
|
|
|
datum => {
|
|
|
|
|
this.relatedTelemetry[key].latest = datum;
|
|
|
|
|
this.relatedTelemetry[key].listeners.forEach(callback => {
|
|
|
|
|
callback(datum);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
async requestRelatedTelemetry(key) {
|
|
|
|
|
if (this.relatedTelemetry[key] && this.relatedTelemetry[key].historicalDomainObject) {
|
|
|
|
|
let data = await this.openmct.telemetry.request(this.relatedTelemetry[key].historicalDomainObject);
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
focusElement() {
|
|
|
|
|
this.$el.focus();
|
|
|
|
|
},
|
|
|
|
|
@@ -405,6 +586,83 @@ export default {
|
|
|
|
|
|
|
|
|
|
return valueFormatter;
|
|
|
|
|
},
|
|
|
|
|
roverPositionTrackingApplicable() {
|
|
|
|
|
let canTrack = false; // possibly false first, depending on if we need all or one
|
|
|
|
|
|
|
|
|
|
for (const key of this.roverPositionKeys) {
|
|
|
|
|
// do we need ALL to be available or will one work?
|
|
|
|
|
if (this.metadata.value(key)) {
|
|
|
|
|
canTrack = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Force true, will remove
|
|
|
|
|
if (this.temporaryDev) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return canTrack;
|
|
|
|
|
},
|
|
|
|
|
async determineRoverFreshness() {
|
|
|
|
|
if (this.canTrackRoverPositionFreshness === false) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let noChanges = true;
|
|
|
|
|
|
|
|
|
|
// set up state tracking
|
|
|
|
|
for (const key of this.roverPositionKeys) {
|
|
|
|
|
try {
|
|
|
|
|
let currentState = await this.getImageMetadataValue(key, this.focusedImage[this.timeKey]);
|
|
|
|
|
currentState = currentState.toFixed(1);
|
|
|
|
|
|
|
|
|
|
if (currentState !== this.roverPositionState[key]) {
|
|
|
|
|
this.roverPositionState[key] = currentState;
|
|
|
|
|
this.roverPositionIsFresh = false;
|
|
|
|
|
noChanges = false;
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
this.roverPositionIsFresh = undefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (noChanges) {
|
|
|
|
|
this.roverPositionIsFresh = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('roverPosition is fresh', this.roverPositionIsFresh);
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
trackRoverPosition() {
|
|
|
|
|
this.cancelRoverTrackingInterval = window.setInterval(this.determineRoverFreshness, this.roverTrackingInterval);
|
|
|
|
|
},
|
|
|
|
|
cameraPositionTrackingApplicable() {
|
|
|
|
|
let canTrack = false; // possibly false first, depending on if we need all or one
|
|
|
|
|
|
|
|
|
|
for (const key of this.cameraPositionKeys) {
|
|
|
|
|
// do we need ALL to be available or will one work?
|
|
|
|
|
if (this.metadata.value(key)) {
|
|
|
|
|
canTrack = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// will remove
|
|
|
|
|
if (this.temporaryDev) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return canTrack;
|
|
|
|
|
},
|
|
|
|
|
determineCameraPositionFreshness() {
|
|
|
|
|
if (this.canTrackCameraPositionFreshness === false) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.cameraPositionIsFresh = undefined;
|
|
|
|
|
},
|
|
|
|
|
trackCameraPosition() {
|
|
|
|
|
this.cancelCameraTrackingInterval = window.setInterval(this.determineCameraFreshness, this.cameraTrackingInterval);
|
|
|
|
|
},
|
|
|
|
|
trackDuration() {
|
|
|
|
|
if (this.canTrackDuration) {
|
|
|
|
|
this.stopDurationTracking();
|
|
|
|
|
|