mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 23:36:41 +00:00
f4cf9c756b
* feat: add function to generate a seeded random value * fix: produce the same compass orientation per timestamp - helps for consistent visual tests --------- Co-authored-by: John Hill <john.c.hill@nasa.gov>
295 lines
9.7 KiB
JavaScript
295 lines
9.7 KiB
JavaScript
/*****************************************************************************
|
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
|
* as represented by the Administrator of the National Aeronautics and Space
|
|
* Administration. All rights reserved.
|
|
*
|
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
* Open MCT includes source code licensed under additional open source
|
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
* this source code distribution or the Licensing information page available
|
|
* at runtime from the About dialog for additional information.
|
|
*****************************************************************************/
|
|
|
|
import { seededRandom } from 'utils/random.js';
|
|
|
|
const DEFAULT_IMAGE_SAMPLES = [
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18731.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18732.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18733.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18734.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18735.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18736.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18737.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18738.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18739.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18740.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18741.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18742.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18743.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18744.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18745.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18746.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18747.jpg',
|
|
'https://www.nasa.gov/wp-content/uploads/static/history/alsj/a16/AS16-117-18748.jpg'
|
|
];
|
|
const DEFAULT_IMAGE_LOAD_DELAY_IN_MILLISECONDS = 20000;
|
|
const MIN_IMAGE_LOAD_DELAY_IN_MILLISECONDS = 5000;
|
|
|
|
let openmctInstance;
|
|
|
|
export default function () {
|
|
return function install(openmct) {
|
|
openmctInstance = openmct;
|
|
openmct.types.addType('example.imagery', {
|
|
key: 'example.imagery',
|
|
name: 'Example Imagery',
|
|
cssClass: 'icon-image',
|
|
description:
|
|
'For development use. Creates example imagery data that mimics a live imagery stream.',
|
|
creatable: true,
|
|
initialize: (object) => {
|
|
object.configuration = {
|
|
imageLocation: '',
|
|
imageLoadDelayInMilliSeconds: DEFAULT_IMAGE_LOAD_DELAY_IN_MILLISECONDS,
|
|
imageSamples: [],
|
|
layers: []
|
|
};
|
|
|
|
object.telemetry = {
|
|
values: [
|
|
{
|
|
name: 'Name',
|
|
key: 'name'
|
|
},
|
|
{
|
|
name: 'Time',
|
|
key: 'utc',
|
|
format: 'utc',
|
|
hints: {
|
|
domain: 2
|
|
}
|
|
},
|
|
{
|
|
name: 'Local Time',
|
|
key: 'local',
|
|
format: 'local-format',
|
|
hints: {
|
|
domain: 1
|
|
}
|
|
},
|
|
{
|
|
name: 'Image',
|
|
key: 'url',
|
|
format: 'image',
|
|
hints: {
|
|
image: 1
|
|
},
|
|
layers: [
|
|
{
|
|
source: 'dist/imagery/example-imagery-layer-16x9.png',
|
|
name: '16:9'
|
|
},
|
|
{
|
|
source: 'dist/imagery/example-imagery-layer-safe.png',
|
|
name: 'Safe'
|
|
},
|
|
{
|
|
source: 'dist/imagery/example-imagery-layer-scale.png',
|
|
name: 'Scale'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'Image Thumbnail',
|
|
key: 'thumbnail-url',
|
|
format: 'thumbnail',
|
|
hints: {
|
|
thumbnail: 1
|
|
},
|
|
source: 'url'
|
|
},
|
|
{
|
|
name: 'Image Download Name',
|
|
key: 'imageDownloadName',
|
|
format: 'imageDownloadName',
|
|
hints: {
|
|
imageDownloadName: 1
|
|
}
|
|
}
|
|
]
|
|
};
|
|
},
|
|
form: [
|
|
{
|
|
key: 'imageLocation',
|
|
name: 'Images url list (comma separated)',
|
|
control: 'textarea',
|
|
cssClass: 'l-inline',
|
|
property: ['configuration', 'imageLocation']
|
|
},
|
|
{
|
|
key: 'imageLoadDelayInMilliSeconds',
|
|
name: 'Image load delay (milliseconds)',
|
|
control: 'numberfield',
|
|
required: true,
|
|
cssClass: 'l-inline',
|
|
property: ['configuration', 'imageLoadDelayInMilliSeconds']
|
|
}
|
|
]
|
|
});
|
|
|
|
const formatThumbnail = {
|
|
format: function (url) {
|
|
return `${url}?w=100&h=100`;
|
|
}
|
|
};
|
|
|
|
openmct.telemetry.addFormat({
|
|
key: 'thumbnail',
|
|
...formatThumbnail
|
|
});
|
|
openmct.telemetry.addProvider(getRealtimeProvider(openmct));
|
|
openmct.telemetry.addProvider(getHistoricalProvider(openmct));
|
|
openmct.telemetry.addProvider(getLadProvider(openmct));
|
|
};
|
|
}
|
|
|
|
function getCompassValues(min, max, timestamp) {
|
|
return min + seededRandom(timestamp) * (max - min);
|
|
}
|
|
|
|
function getImageSamples(configuration) {
|
|
let imageSamples = DEFAULT_IMAGE_SAMPLES;
|
|
|
|
if (configuration.imageLocation && configuration.imageLocation.length) {
|
|
imageSamples = getImageUrlListFromConfig(configuration);
|
|
}
|
|
|
|
return imageSamples;
|
|
}
|
|
|
|
function getImageUrlListFromConfig(configuration) {
|
|
return configuration.imageLocation.split(',');
|
|
}
|
|
|
|
function getImageLoadDelay(domainObject) {
|
|
const imageLoadDelay = Math.trunc(
|
|
Number(domainObject.configuration.imageLoadDelayInMilliSeconds)
|
|
);
|
|
if (!imageLoadDelay) {
|
|
openmctInstance.objects.mutate(
|
|
domainObject,
|
|
'configuration.imageLoadDelayInMilliSeconds',
|
|
DEFAULT_IMAGE_LOAD_DELAY_IN_MILLISECONDS
|
|
);
|
|
|
|
return DEFAULT_IMAGE_LOAD_DELAY_IN_MILLISECONDS;
|
|
}
|
|
|
|
if (imageLoadDelay < MIN_IMAGE_LOAD_DELAY_IN_MILLISECONDS) {
|
|
openmctInstance.objects.mutate(
|
|
domainObject,
|
|
'configuration.imageLoadDelayInMilliSeconds',
|
|
MIN_IMAGE_LOAD_DELAY_IN_MILLISECONDS
|
|
);
|
|
|
|
return MIN_IMAGE_LOAD_DELAY_IN_MILLISECONDS;
|
|
}
|
|
|
|
return imageLoadDelay;
|
|
}
|
|
|
|
function getRealtimeProvider(openmct) {
|
|
return {
|
|
supportsSubscribe: (domainObject) => domainObject.type === 'example.imagery',
|
|
subscribe: (domainObject, callback) => {
|
|
const delay = getImageLoadDelay(domainObject);
|
|
const interval = setInterval(() => {
|
|
const imageSamples = getImageSamples(domainObject.configuration);
|
|
const datum = pointForTimestamp(openmct.time.now(), domainObject.name, imageSamples, delay);
|
|
callback(datum);
|
|
}, delay);
|
|
|
|
return () => {
|
|
clearInterval(interval);
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
function getHistoricalProvider(openmct) {
|
|
return {
|
|
supportsRequest: (domainObject, options) => {
|
|
return domainObject.type === 'example.imagery' && options.strategy !== 'latest';
|
|
},
|
|
request: (domainObject, options) => {
|
|
const delay = getImageLoadDelay(domainObject);
|
|
let start = options.start;
|
|
const end = Math.min(options.end, openmct.time.now());
|
|
const data = [];
|
|
while (start <= end && data.length < delay) {
|
|
const imageSamples = getImageSamples(domainObject.configuration);
|
|
const generatedDataPoint = pointForTimestamp(start, domainObject.name, imageSamples, delay);
|
|
data.push(generatedDataPoint);
|
|
start += delay;
|
|
}
|
|
|
|
return Promise.resolve(data);
|
|
}
|
|
};
|
|
}
|
|
|
|
function getLadProvider(openmct) {
|
|
return {
|
|
supportsRequest: (domainObject, options) => {
|
|
return domainObject.type === 'example.imagery' && options.strategy === 'latest';
|
|
},
|
|
request: (domainObject, options) => {
|
|
const delay = getImageLoadDelay(domainObject);
|
|
const datum = pointForTimestamp(
|
|
openmct.time.now(),
|
|
domainObject.name,
|
|
getImageSamples(domainObject.configuration),
|
|
delay
|
|
);
|
|
|
|
return Promise.resolve([datum]);
|
|
}
|
|
};
|
|
}
|
|
|
|
function pointForTimestamp(timestamp, name, imageSamples, delay) {
|
|
const url = imageSamples[Math.floor(timestamp / delay) % imageSamples.length];
|
|
const urlItems = url.split('/');
|
|
const imageDownloadName = `example.imagery.${urlItems[urlItems.length - 1]}`;
|
|
const navCamTransformations = {
|
|
translateX: 0,
|
|
translateY: 18,
|
|
rotation: 0,
|
|
scale: 0.3,
|
|
cameraAngleOfView: 70
|
|
};
|
|
|
|
return {
|
|
name,
|
|
utc: Math.floor(timestamp / delay) * delay,
|
|
local: Math.floor(timestamp / delay) * delay,
|
|
url,
|
|
sunOrientation: getCompassValues(0, 360, timestamp),
|
|
cameraAzimuth: getCompassValues(0, 360, timestamp),
|
|
heading: getCompassValues(0, 360, timestamp),
|
|
transformations: navCamTransformations,
|
|
imageDownloadName
|
|
};
|
|
}
|