mirror of
https://github.com/nasa/openmct.git
synced 2024-12-18 20:57:53 +00:00
feat: Support thumbnails in ImageryView and ImageryTimeView (#6132)
* fix: get image thumbnail formatter * refactor: ImageryView cleanup * docs: add comment * feat: Support thumbnails in ImageryView - Prefer an image's thumbnail URL if its available * feat: Support thumbnails in ImageryTimeView * refactor: rename variable * test(WIP): add thumbnail unit test, not working yet * test: temp disable test * feat: imagery thumbnail urls for example imagery * test: add unit test for imagery thumbnails * test(e2e): check for thumbnail urls - Update imagery view tests to check for use of thumbnail urls
This commit is contained in:
parent
986c596d90
commit
5e530aa625
@ -25,13 +25,13 @@ This test suite is dedicated to tests which verify the basic operations surround
|
|||||||
but only assume that example imagery is present.
|
but only assume that example imagery is present.
|
||||||
*/
|
*/
|
||||||
/* globals process */
|
/* globals process */
|
||||||
const { v4: uuid } = require('uuid');
|
|
||||||
const { waitForAnimations } = require('../../../../baseFixtures');
|
const { waitForAnimations } = require('../../../../baseFixtures');
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
||||||
const backgroundImageSelector = '.c-imagery__main-image__background-image';
|
const backgroundImageSelector = '.c-imagery__main-image__background-image';
|
||||||
const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt'];
|
const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt'];
|
||||||
const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan';
|
const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan';
|
||||||
|
const thumbnailUrlParamsRegexp = /\?w=100&h=100/;
|
||||||
|
|
||||||
//The following block of tests verifies the basic functionality of example imagery and serves as a template for Imagery objects embedded in other objects.
|
//The following block of tests verifies the basic functionality of example imagery and serves as a template for Imagery objects embedded in other objects.
|
||||||
test.describe('Example Imagery Object', () => {
|
test.describe('Example Imagery Object', () => {
|
||||||
@ -397,13 +397,11 @@ test.describe('Example Imagery in Time Strip', () => {
|
|||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto('./', { waitUntil: 'networkidle' });
|
await page.goto('./', { waitUntil: 'networkidle' });
|
||||||
timeStripObject = await createDomainObjectWithDefaults(page, {
|
timeStripObject = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Time Strip',
|
type: 'Time Strip'
|
||||||
name: 'Time Strip'.concat(' ', uuid())
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Example Imagery',
|
type: 'Example Imagery',
|
||||||
name: 'Example Imagery'.concat(' ', uuid()),
|
|
||||||
parent: timeStripObject.uuid
|
parent: timeStripObject.uuid
|
||||||
});
|
});
|
||||||
// Navigate to timestrip
|
// Navigate to timestrip
|
||||||
@ -414,17 +412,28 @@ test.describe('Example Imagery in Time Strip', () => {
|
|||||||
type: 'issue',
|
type: 'issue',
|
||||||
description: 'https://github.com/nasa/openmct/issues/5632'
|
description: 'https://github.com/nasa/openmct/issues/5632'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Hover over the timestrip to reveal a thumbnail image
|
||||||
await page.locator('.c-imagery-tsv-container').hover();
|
await page.locator('.c-imagery-tsv-container').hover();
|
||||||
// get url of the hovered image
|
|
||||||
const hoveredImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img');
|
// Get the img src of the hovered image thumbnail
|
||||||
const hoveredImgSrc = await hoveredImg.getAttribute('src');
|
const hoveredThumbnailImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img');
|
||||||
expect(hoveredImgSrc).toBeTruthy();
|
const hoveredThumbnailImgSrc = await hoveredThumbnailImg.getAttribute('src');
|
||||||
|
|
||||||
|
// Verify that imagery timestrip view uses the thumbnailUrl as img src for thumbnails
|
||||||
|
expect(hoveredThumbnailImgSrc).toBeTruthy();
|
||||||
|
expect(hoveredThumbnailImgSrc).toMatch(thumbnailUrlParamsRegexp);
|
||||||
|
|
||||||
|
// Click on the hovered thumbnail to open "View Large" view
|
||||||
await page.locator('.c-imagery-tsv-container').click();
|
await page.locator('.c-imagery-tsv-container').click();
|
||||||
// get image of view large container
|
|
||||||
|
// Get the img src of the large view image
|
||||||
const viewLargeImg = page.locator('img.c-imagery__main-image__image');
|
const viewLargeImg = page.locator('img.c-imagery__main-image__image');
|
||||||
const viewLargeImgSrc = await viewLargeImg.getAttribute('src');
|
const viewLargeImgSrc = await viewLargeImg.getAttribute('src');
|
||||||
expect(viewLargeImgSrc).toBeTruthy();
|
expect(viewLargeImgSrc).toBeTruthy();
|
||||||
expect(viewLargeImgSrc).toEqual(hoveredImgSrc);
|
|
||||||
|
// Verify that the image in the large view is the same as the hovered thumbnail
|
||||||
|
expect(viewLargeImgSrc).toEqual(hoveredThumbnailImgSrc.split('?')[0]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -441,6 +450,12 @@ test.describe('Example Imagery in Time Strip', () => {
|
|||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
*/
|
*/
|
||||||
async function performImageryViewOperationsAndAssert(page) {
|
async function performImageryViewOperationsAndAssert(page) {
|
||||||
|
// Verify that imagery thumbnails use a thumbnail url
|
||||||
|
const thumbnailImages = page.locator('.c-thumb__image');
|
||||||
|
const mainImage = page.locator('.c-imagery__main-image__image');
|
||||||
|
await expect(thumbnailImages.first()).toHaveAttribute('src', thumbnailUrlParamsRegexp);
|
||||||
|
await expect(mainImage).not.toHaveAttribute('src', thumbnailUrlParamsRegexp);
|
||||||
|
|
||||||
// Click previous image button
|
// Click previous image button
|
||||||
const previousImageButton = page.locator('.c-nav--prev');
|
const previousImageButton = page.locator('.c-nav--prev');
|
||||||
await previousImageButton.click();
|
await previousImageButton.click();
|
||||||
|
@ -107,6 +107,15 @@ export default function () {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Image Thumbnail',
|
||||||
|
key: 'thumbnail-url',
|
||||||
|
format: 'thumbnail',
|
||||||
|
hints: {
|
||||||
|
thumbnail: 1
|
||||||
|
},
|
||||||
|
source: 'url'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Image Download Name',
|
name: 'Image Download Name',
|
||||||
key: 'imageDownloadName',
|
key: 'imageDownloadName',
|
||||||
@ -143,6 +152,16 @@ export default function () {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const formatThumbnail = {
|
||||||
|
format: function (url) {
|
||||||
|
return `${url}?w=100&h=100`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
openmct.telemetry.addFormat({
|
||||||
|
key: 'thumbnail',
|
||||||
|
...formatThumbnail
|
||||||
|
});
|
||||||
openmct.telemetry.addProvider(getRealtimeProvider());
|
openmct.telemetry.addProvider(getRealtimeProvider());
|
||||||
openmct.telemetry.addProvider(getHistoricalProvider());
|
openmct.telemetry.addProvider(getHistoricalProvider());
|
||||||
openmct.telemetry.addProvider(getLadProvider());
|
openmct.telemetry.addProvider(getLadProvider());
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<img
|
<img
|
||||||
ref="img"
|
ref="img"
|
||||||
class="c-thumb__image"
|
class="c-thumb__image"
|
||||||
:src="image.url"
|
:src="`${image.thumbnailUrl || image.url}`"
|
||||||
fetchpriority="low"
|
fetchpriority="low"
|
||||||
@load="imageLoadCompleted"
|
@load="imageLoadCompleted"
|
||||||
>
|
>
|
||||||
|
@ -186,17 +186,17 @@ export default {
|
|||||||
item.remove();
|
item.remove();
|
||||||
});
|
});
|
||||||
let imagery = this.$el.querySelectorAll(`.${IMAGE_WRAPPER_CLASS}`);
|
let imagery = this.$el.querySelectorAll(`.${IMAGE_WRAPPER_CLASS}`);
|
||||||
imagery.forEach(item => {
|
imagery.forEach(imageElm => {
|
||||||
if (clearAllImagery) {
|
if (clearAllImagery) {
|
||||||
item.remove();
|
imageElm.remove();
|
||||||
} else {
|
} else {
|
||||||
const id = item.getAttributeNS(null, 'id');
|
const id = imageElm.getAttributeNS(null, 'id');
|
||||||
if (id) {
|
if (id) {
|
||||||
const timestamp = id.replace(ID_PREFIX, '');
|
const timestamp = id.replace(ID_PREFIX, '');
|
||||||
if (!this.isImageryInBounds({
|
if (!this.isImageryInBounds({
|
||||||
time: timestamp
|
time: timestamp
|
||||||
})) {
|
})) {
|
||||||
item.remove();
|
imageElm.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,25 +343,25 @@ export default {
|
|||||||
imageElement.style.display = 'block';
|
imageElement.style.display = 'block';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateExistingImageWrapper(existingImageWrapper, item, showImagePlaceholders) {
|
updateExistingImageWrapper(existingImageWrapper, image, showImagePlaceholders) {
|
||||||
//Update the x co-ordinates of the image wrapper and the url of image
|
//Update the x co-ordinates of the image wrapper and the url of image
|
||||||
//this is to avoid tearing down all elements completely and re-drawing them
|
//this is to avoid tearing down all elements completely and re-drawing them
|
||||||
this.setNSAttributesForElement(existingImageWrapper, {
|
this.setNSAttributesForElement(existingImageWrapper, {
|
||||||
'data-show-image-placeholders': showImagePlaceholders
|
'data-show-image-placeholders': showImagePlaceholders
|
||||||
});
|
});
|
||||||
existingImageWrapper.style.left = `${this.xScale(item.time)}px`;
|
existingImageWrapper.style.left = `${this.xScale(image.time)}px`;
|
||||||
|
|
||||||
let imageElement = existingImageWrapper.querySelector('img');
|
let imageElement = existingImageWrapper.querySelector('img');
|
||||||
this.setNSAttributesForElement(imageElement, {
|
this.setNSAttributesForElement(imageElement, {
|
||||||
src: item.url
|
src: image.thumbnailUrl || image.url
|
||||||
});
|
});
|
||||||
this.setImageDisplay(imageElement, showImagePlaceholders);
|
this.setImageDisplay(imageElement, showImagePlaceholders);
|
||||||
},
|
},
|
||||||
createImageWrapper(index, item, showImagePlaceholders) {
|
createImageWrapper(index, image, showImagePlaceholders) {
|
||||||
const id = `${ID_PREFIX}${item.time}`;
|
const id = `${ID_PREFIX}${image.time}`;
|
||||||
let imageWrapper = document.createElement('div');
|
let imageWrapper = document.createElement('div');
|
||||||
imageWrapper.classList.add(IMAGE_WRAPPER_CLASS);
|
imageWrapper.classList.add(IMAGE_WRAPPER_CLASS);
|
||||||
imageWrapper.style.left = `${this.xScale(item.time)}px`;
|
imageWrapper.style.left = `${this.xScale(image.time)}px`;
|
||||||
this.setNSAttributesForElement(imageWrapper, {
|
this.setNSAttributesForElement(imageWrapper, {
|
||||||
id,
|
id,
|
||||||
'data-show-image-placeholders': showImagePlaceholders
|
'data-show-image-placeholders': showImagePlaceholders
|
||||||
@ -383,7 +383,7 @@ export default {
|
|||||||
//create image element
|
//create image element
|
||||||
let imageElement = document.createElement('img');
|
let imageElement = document.createElement('img');
|
||||||
this.setNSAttributesForElement(imageElement, {
|
this.setNSAttributesForElement(imageElement, {
|
||||||
src: item.url
|
src: image.thumbnailUrl || image.url
|
||||||
});
|
});
|
||||||
imageElement.style.width = `${IMAGE_SIZE}px`;
|
imageElement.style.width = `${IMAGE_SIZE}px`;
|
||||||
imageElement.style.height = `${IMAGE_SIZE}px`;
|
imageElement.style.height = `${IMAGE_SIZE}px`;
|
||||||
@ -392,7 +392,7 @@ export default {
|
|||||||
//handle mousedown event to show the image in a large view
|
//handle mousedown event to show the image in a large view
|
||||||
imageWrapper.addEventListener('mousedown', (e) => {
|
imageWrapper.addEventListener('mousedown', (e) => {
|
||||||
if (e.button === 0) {
|
if (e.button === 0) {
|
||||||
this.expand(item.time);
|
this.expand(image.time);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@
|
|||||||
>
|
>
|
||||||
<ImageThumbnail
|
<ImageThumbnail
|
||||||
v-for="(image, index) in imageHistory"
|
v-for="(image, index) in imageHistory"
|
||||||
:key="image.url + image.time"
|
:key="`${image.thumbnailUrl || image.url}${image.time}`"
|
||||||
:image="image"
|
:image="image"
|
||||||
:active="focusedImageIndex === index"
|
:active="focusedImageIndex === index"
|
||||||
:selected="focusedImageIndex === index && isPaused"
|
:selected="focusedImageIndex === index && isPaused"
|
||||||
@ -225,6 +225,9 @@ const SHOW_THUMBS_FULLSIZE_THRESHOLD_HEIGHT = 600;
|
|||||||
|
|
||||||
const IMAGE_CONTAINER_BORDER_WIDTH = 1;
|
const IMAGE_CONTAINER_BORDER_WIDTH = 1;
|
||||||
|
|
||||||
|
const DEFAULT_IMAGE_PAN_ALT_TEXT = "Alt drag to pan";
|
||||||
|
const LINUX_IMAGE_PAN_ALT_TEXT = `Ctrl+${DEFAULT_IMAGE_PAN_ALT_TEXT}`;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ImageryView',
|
name: 'ImageryView',
|
||||||
components: {
|
components: {
|
||||||
@ -308,8 +311,8 @@ export default {
|
|||||||
},
|
},
|
||||||
focusImageStyles() {
|
focusImageStyles() {
|
||||||
return {
|
return {
|
||||||
'filter': `brightness(${this.filters.brightness}%) contrast(${this.filters.contrast}%)`,
|
filter: `brightness(${this.filters.brightness}%) contrast(${this.filters.contrast}%)`,
|
||||||
'background-image':
|
backgroundImage:
|
||||||
`${this.imageUrl ? (
|
`${this.imageUrl ? (
|
||||||
`url(${this.imageUrl}),
|
`url(${this.imageUrl}),
|
||||||
repeating-linear-gradient(
|
repeating-linear-gradient(
|
||||||
@ -320,10 +323,10 @@ export default {
|
|||||||
rgba(125,125,125,.2) 8px
|
rgba(125,125,125,.2) 8px
|
||||||
)`
|
)`
|
||||||
) : ''}`,
|
) : ''}`,
|
||||||
'transform': `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
|
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
|
||||||
'transition': `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`,
|
transition: `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`,
|
||||||
'width': `${this.sizedImageWidth}px`,
|
width: `${this.sizedImageWidth}px`,
|
||||||
'height': `${this.sizedImageHeight}px`
|
height: `${this.sizedImageHeight}px`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
time() {
|
time() {
|
||||||
@ -334,11 +337,12 @@ export default {
|
|||||||
},
|
},
|
||||||
imageWrapperStyle() {
|
imageWrapperStyle() {
|
||||||
return {
|
return {
|
||||||
'cursor-zoom-in': this.cursorStates.showCursorZoomIn,
|
cursorZoomIn: this.cursorStates.showCursorZoomIn,
|
||||||
'cursor-zoom-out': this.cursorStates.showCursorZoomOut,
|
cursorZoomOut: this.cursorStates.showCursorZoomOut,
|
||||||
'pannable': this.cursorStates.isPannable,
|
pannable: this.cursorStates.isPannable,
|
||||||
'paused unnsynced': this.isPaused && !this.isFixed,
|
paused: this.isPaused && !this.isFixed,
|
||||||
'stale': false
|
unsynced: this.isPaused && !this.isFixed,
|
||||||
|
stale: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
isImageNew() {
|
isImageNew() {
|
||||||
@ -515,10 +519,10 @@ export default {
|
|||||||
const navigator = window.navigator.userAgent;
|
const navigator = window.navigator.userAgent;
|
||||||
|
|
||||||
if (regexLinux.test(navigator)) {
|
if (regexLinux.test(navigator)) {
|
||||||
return 'Ctrl+Alt drag to pan';
|
return LINUX_IMAGE_PAN_ALT_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Alt drag to pan';
|
return DEFAULT_IMAGE_PAN_ALT_TEXT;
|
||||||
},
|
},
|
||||||
viewableArea() {
|
viewableArea() {
|
||||||
if (this.zoomFactor === 1) {
|
if (this.zoomFactor === 1) {
|
||||||
@ -679,9 +683,9 @@ export default {
|
|||||||
},
|
},
|
||||||
getVisibleLayerStyles(layer) {
|
getVisibleLayerStyles(layer) {
|
||||||
return {
|
return {
|
||||||
'background-image': `url(${layer.source})`,
|
backgroundImage: `url(${layer.source})`,
|
||||||
'transform': `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
|
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
|
||||||
'transition': `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`
|
transition: `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
setTimeContext() {
|
setTimeContext() {
|
||||||
@ -759,26 +763,26 @@ export default {
|
|||||||
return mostRecent[valueKey];
|
return mostRecent[valueKey];
|
||||||
},
|
},
|
||||||
loadVisibleLayers() {
|
loadVisibleLayers() {
|
||||||
const metaDataValues = this.metadata.valuesForHints(['image'])[0];
|
const layersMetadata = this.imageMetadataValue.layers;
|
||||||
this.imageFormat = this.openmct.telemetry.getValueFormatter(metaDataValues);
|
if (!layersMetadata) {
|
||||||
let layersMetadata = metaDataValues.layers;
|
return;
|
||||||
if (layersMetadata) {
|
}
|
||||||
this.layers = layersMetadata;
|
|
||||||
if (this.domainObject.configuration) {
|
this.layers = layersMetadata;
|
||||||
let persistedLayers = this.domainObject.configuration.layers;
|
if (this.domainObject.configuration) {
|
||||||
layersMetadata.forEach((layer) => {
|
const persistedLayers = this.domainObject.configuration.layers;
|
||||||
const persistedLayer = persistedLayers.find(object => object.name === layer.name);
|
layersMetadata.forEach((layer) => {
|
||||||
if (persistedLayer) {
|
const persistedLayer = persistedLayers.find(object => object.name === layer.name);
|
||||||
layer.visible = persistedLayer.visible === true;
|
if (persistedLayer) {
|
||||||
}
|
layer.visible = persistedLayer.visible === true;
|
||||||
});
|
}
|
||||||
this.visibleLayers = this.layers.filter(layer => layer.visible);
|
});
|
||||||
} else {
|
this.visibleLayers = this.layers.filter(layer => layer.visible);
|
||||||
this.visibleLayers = [];
|
} else {
|
||||||
this.layers.forEach((layer) => {
|
this.visibleLayers = [];
|
||||||
layer.visible = false;
|
this.layers.forEach((layer) => {
|
||||||
});
|
layer.visible = false;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persistVisibleLayers() {
|
persistVisibleLayers() {
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
||||||
&.unnsynced{
|
&.unsynced{
|
||||||
@include sUnsynced();
|
@include sUnsynced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
const DEFAULT_DURATION_FORMATTER = 'duration';
|
const DEFAULT_DURATION_FORMATTER = 'duration';
|
||||||
|
const IMAGE_HINT_KEY = 'image';
|
||||||
|
const IMAGE_THUMBNAIL_HINT_KEY = 'thumbnail';
|
||||||
|
const IMAGE_DOWNLOAD_NAME_HINT_KEY = 'imageDownloadName';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'domainObject', 'objectPath'],
|
inject: ['openmct', 'domainObject', 'objectPath'],
|
||||||
@ -32,13 +35,20 @@ export default {
|
|||||||
this.setDataTimeContext();
|
this.setDataTimeContext();
|
||||||
this.openmct.objectViews.on('clearData', this.dataCleared);
|
this.openmct.objectViews.on('clearData', this.dataCleared);
|
||||||
|
|
||||||
// set
|
// Get metadata and formatters
|
||||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||||
this.imageHints = { ...this.metadata.valuesForHints(['image'])[0] };
|
|
||||||
|
this.imageMetadataValue = { ...this.metadata.valuesForHints([IMAGE_HINT_KEY])[0] };
|
||||||
|
this.imageFormatter = this.getFormatter(this.imageMetadataValue.key);
|
||||||
|
|
||||||
|
this.imageThumbnailMetadataValue = { ...this.metadata.valuesForHints([IMAGE_THUMBNAIL_HINT_KEY])[0] };
|
||||||
|
this.imageThumbnailFormatter = this.imageThumbnailMetadataValue.key
|
||||||
|
? this.getFormatter(this.imageThumbnailMetadataValue.key)
|
||||||
|
: null;
|
||||||
|
|
||||||
this.durationFormatter = this.getFormatter(this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
this.durationFormatter = this.getFormatter(this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||||
this.imageFormatter = this.openmct.telemetry.getValueFormatter(this.imageHints);
|
this.imageDownloadNameMetadataValue = { ...this.metadata.valuesForHints([IMAGE_DOWNLOAD_NAME_HINT_KEY])[0]};
|
||||||
this.imageDownloadNameHints = { ...this.metadata.valuesForHints(['imageDownloadName'])[0]};
|
|
||||||
|
|
||||||
// initialize
|
// initialize
|
||||||
this.timeKey = this.timeSystem.key;
|
this.timeKey = this.timeSystem.key;
|
||||||
@ -105,12 +115,19 @@ export default {
|
|||||||
|
|
||||||
return this.imageFormatter.format(datum);
|
return this.imageFormatter.format(datum);
|
||||||
},
|
},
|
||||||
|
formatImageThumbnailUrl(datum) {
|
||||||
|
if (!datum || !this.imageThumbnailFormatter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.imageThumbnailFormatter.format(datum);
|
||||||
|
},
|
||||||
formatTime(datum) {
|
formatTime(datum) {
|
||||||
if (!datum) {
|
if (!datum) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dateTimeStr = this.timeFormatter.format(datum);
|
const dateTimeStr = this.timeFormatter.format(datum);
|
||||||
|
|
||||||
// Replace ISO "T" with a space to allow wrapping
|
// Replace ISO "T" with a space to allow wrapping
|
||||||
return dateTimeStr.replace("T", " ");
|
return dateTimeStr.replace("T", " ");
|
||||||
@ -118,7 +135,7 @@ export default {
|
|||||||
getImageDownloadName(datum) {
|
getImageDownloadName(datum) {
|
||||||
let imageDownloadName = '';
|
let imageDownloadName = '';
|
||||||
if (datum) {
|
if (datum) {
|
||||||
const key = this.imageDownloadNameHints.key;
|
const key = this.imageDownloadNameMetadataValue.key;
|
||||||
imageDownloadName = datum[key];
|
imageDownloadName = datum[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +167,7 @@ export default {
|
|||||||
normalizeDatum(datum) {
|
normalizeDatum(datum) {
|
||||||
const formattedTime = this.formatTime(datum);
|
const formattedTime = this.formatTime(datum);
|
||||||
const url = this.formatImageUrl(datum);
|
const url = this.formatImageUrl(datum);
|
||||||
|
const thumbnailUrl = this.formatImageThumbnailUrl(datum);
|
||||||
const time = this.parseTime(formattedTime);
|
const time = this.parseTime(formattedTime);
|
||||||
const imageDownloadName = this.getImageDownloadName(datum);
|
const imageDownloadName = this.getImageDownloadName(datum);
|
||||||
|
|
||||||
@ -157,13 +175,14 @@ export default {
|
|||||||
...datum,
|
...datum,
|
||||||
formattedTime,
|
formattedTime,
|
||||||
url,
|
url,
|
||||||
|
thumbnailUrl,
|
||||||
time,
|
time,
|
||||||
imageDownloadName
|
imageDownloadName
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getFormatter(key) {
|
getFormatter(key) {
|
||||||
let metadataValue = this.metadata.value(key) || { format: key };
|
const metadataValue = this.metadata.value(key) || { format: key };
|
||||||
let valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
|
const valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
|
||||||
|
|
||||||
return valueFormatter;
|
return valueFormatter;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ const MAIN_IMAGE_CLASS = '.js-imageryView-image';
|
|||||||
const NEW_IMAGE_CLASS = '.c-imagery__age.c-imagery--new';
|
const NEW_IMAGE_CLASS = '.c-imagery__age.c-imagery--new';
|
||||||
const REFRESH_CSS_MS = 500;
|
const REFRESH_CSS_MS = 500;
|
||||||
|
|
||||||
|
function formatThumbnail(url) {
|
||||||
|
return url.replace('logo-openmct.svg', 'logo-nasa.svg');
|
||||||
|
}
|
||||||
|
|
||||||
function getImageInfo(doc) {
|
function getImageInfo(doc) {
|
||||||
let imageElement = doc.querySelectorAll(MAIN_IMAGE_CLASS)[0];
|
let imageElement = doc.querySelectorAll(MAIN_IMAGE_CLASS)[0];
|
||||||
let timestamp = imageElement.dataset.openmctImageTimestamp;
|
let timestamp = imageElement.dataset.openmctImageTimestamp;
|
||||||
@ -124,6 +128,16 @@ describe("The Imagery View Layouts", () => {
|
|||||||
},
|
},
|
||||||
"source": "url"
|
"source": "url"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Image Thumbnail",
|
||||||
|
"key": "thumbnail-url",
|
||||||
|
"format": "thumbnail",
|
||||||
|
"hints": {
|
||||||
|
"thumbnail": 1,
|
||||||
|
"priority": 3
|
||||||
|
},
|
||||||
|
"source": "url"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"key": "name",
|
"key": "name",
|
||||||
@ -200,6 +214,11 @@ describe("The Imagery View Layouts", () => {
|
|||||||
|
|
||||||
originalRouterPath = openmct.router.path;
|
originalRouterPath = openmct.router.path;
|
||||||
|
|
||||||
|
openmct.telemetry.addFormat({
|
||||||
|
key: 'thumbnail',
|
||||||
|
format: formatThumbnail
|
||||||
|
});
|
||||||
|
|
||||||
openmct.on('start', done);
|
openmct.on('start', done);
|
||||||
openmct.startHeadless();
|
openmct.startHeadless();
|
||||||
});
|
});
|
||||||
@ -384,15 +403,32 @@ describe("The Imagery View Layouts", () => {
|
|||||||
//Looks like we need Vue.nextTick here so that computed properties settle down
|
//Looks like we need Vue.nextTick here so that computed properties settle down
|
||||||
await Vue.nextTick();
|
await Vue.nextTick();
|
||||||
const layerEls = parent.querySelectorAll('.js-layer-image');
|
const layerEls = parent.querySelectorAll('.js-layer-image');
|
||||||
console.log(layerEls);
|
|
||||||
expect(layerEls.length).toEqual(1);
|
expect(layerEls.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should use the image thumbnailUrl for thumbnails", async () => {
|
||||||
|
await Vue.nextTick();
|
||||||
|
const fullSizeImageUrl = imageTelemetry[5].url;
|
||||||
|
const thumbnailUrl = formatThumbnail(imageTelemetry[5].url);
|
||||||
|
|
||||||
|
// Ensure thumbnails are shown w/ thumbnail Urls
|
||||||
|
const thumbnails = parent.querySelectorAll(`img[src='${thumbnailUrl}']`);
|
||||||
|
expect(thumbnails.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Click a thumbnail
|
||||||
|
parent.querySelectorAll(`img[src='${thumbnailUrl}']`)[0].click();
|
||||||
|
await Vue.nextTick();
|
||||||
|
|
||||||
|
// Ensure full size image is shown w/ full size url
|
||||||
|
const fullSizeImages = parent.querySelectorAll(`img[src='${fullSizeImageUrl}']`);
|
||||||
|
expect(fullSizeImages.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
it("should show the clicked thumbnail as the main image", async () => {
|
it("should show the clicked thumbnail as the main image", async () => {
|
||||||
//Looks like we need Vue.nextTick here so that computed properties settle down
|
//Looks like we need Vue.nextTick here so that computed properties settle down
|
||||||
await Vue.nextTick();
|
await Vue.nextTick();
|
||||||
const target = imageTelemetry[5].url;
|
const thumbnailUrl = formatThumbnail(imageTelemetry[5].url);
|
||||||
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
parent.querySelectorAll(`img[src='${thumbnailUrl}']`)[0].click();
|
||||||
await Vue.nextTick();
|
await Vue.nextTick();
|
||||||
const imageInfo = getImageInfo(parent);
|
const imageInfo = getImageInfo(parent);
|
||||||
|
|
||||||
@ -417,7 +453,7 @@ describe("The Imagery View Layouts", () => {
|
|||||||
|
|
||||||
it("should show that an image is not new", async () => {
|
it("should show that an image is not new", async () => {
|
||||||
await Vue.nextTick();
|
await Vue.nextTick();
|
||||||
const target = imageTelemetry[4].url;
|
const target = formatThumbnail(imageTelemetry[4].url);
|
||||||
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
||||||
|
|
||||||
await Vue.nextTick();
|
await Vue.nextTick();
|
||||||
|
Loading…
Reference in New Issue
Block a user