more scaffolding

This commit is contained in:
Scott Bell 2024-12-09 16:46:56 +01:00
parent 3159de08b1
commit 680b0953b2
5 changed files with 393 additions and 424 deletions

View File

@ -21,10 +21,10 @@
*****************************************************************************/
import mount from 'utils/mount';
import EventTimeView from './components/EventTimeView.vue';
import EventTimelineView from './components/EventTimelineView.vue';
export default function EventTimestripViewProvider(openmct) {
const type = 'event.time-strip.view';
const type = 'event.time-line.view';
function hasEventTelemetry(domainObject) {
const metadata = openmct.telemetry.getMetadata(domainObject);
@ -39,7 +39,7 @@ export default function EventTimestripViewProvider(openmct) {
return {
key: type,
name: 'Event Timestrip View',
name: 'Event Timeline View',
cssClass: 'icon-event',
canView: function (domainObject, objectPath) {
let isChildOfTimeStrip = objectPath.find((object) => object.type === 'time-strip');
@ -60,14 +60,14 @@ export default function EventTimestripViewProvider(openmct) {
{
el: element,
components: {
EventTimeView
EventTimelineView
},
provide: {
openmct: openmct,
domainObject: domainObject,
objectPath: objectPath
},
template: '<event-time-view ref="root"></event-time-view>'
template: '<event-timeline-view ref="root"></event-timeline-view>'
},
{
app: openmct.app,

View File

@ -1,413 +0,0 @@
<!--
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.
-->
<template>
<div ref="events" class="c-event-tsv c-timeline-holder">
<div ref="imageryHolder" class="c-imagery-tsv__contents u-contents"></div>
</div>
</template>
<script>
import { scaleLinear, scaleUtc } from 'd3-scale';
import _ from 'lodash';
import mount from 'utils/mount';
import SwimLane from '@/ui/components/swim-lane/SwimLane.vue';
import { PREVIEW_ACTION_KEY } from '@/ui/preview/PreviewAction.js';
const PADDING = 1;
const ROW_HEIGHT = 100;
const IMAGE_SIZE = 85;
const IMAGE_WIDTH_THRESHOLD = 25;
const CONTAINER_CLASS = 'c-imagery-tsv-container';
const NO_ITEMS_CLASS = 'c-imagery-tsv__no-items';
const IMAGE_WRAPPER_CLASS = 'c-imagery-tsv__image-wrapper';
const ID_PREFIX = 'wrapper-';
export default {
inject: ['openmct', 'domainObject', 'objectPath'],
data() {
let timeSystem = this.openmct.time.getTimeSystem();
this.metadata = {};
this.requestCount = 0;
return {
viewBounds: undefined,
height: 0,
durationFormatter: undefined,
imageHistory: [],
timeSystem: timeSystem,
keyString: undefined
};
},
watch: {
imageHistory: {
handler(newHistory, oldHistory) {
this.updatePlotImagery();
},
deep: true
}
},
mounted() {
this.previewAction = this.openmct.actions.getAction(PREVIEW_ACTION_KEY);
this.canvas = this.$refs.imagery.appendChild(document.createElement('canvas'));
this.canvas.height = 0;
this.canvasContext = this.canvas.getContext('2d');
this.setDimensions();
this.setScaleAndPlotImagery = this.setScaleAndPlotImagery.bind(this);
this.updateViewBounds = this.updateViewBounds.bind(this);
this.setTimeContext = this.setTimeContext.bind(this);
this.setTimeContext();
this.updateViewBounds();
this.resize = _.debounce(this.resize, 400);
this.imageryStripResizeObserver = new ResizeObserver(this.resize);
this.imageryStripResizeObserver.observe(this.$refs.imagery);
this.unlisten = this.openmct.objects.observe(this.domainObject, '*', this.observeForChanges);
},
beforeUnmount() {
if (this.imageryStripResizeObserver) {
this.imageryStripResizeObserver.disconnect();
}
this.stopFollowingTimeContext();
if (this.unlisten) {
this.unlisten();
}
if (this.destroyImageryContainer) {
this.destroyImageryContainer();
}
},
methods: {
setTimeContext() {
this.stopFollowingTimeContext();
this.timeContext = this.openmct.time.getContextForView(this.objectPath);
this.timeContext.on('timeSystem', this.setScaleAndPlotImagery);
this.timeContext.on('boundsChanged', this.updateViewBounds);
},
stopFollowingTimeContext() {
if (this.timeContext) {
this.timeContext.off('timeSystem', this.setScaleAndPlotImagery);
this.timeContext.off('boundsChanged', this.updateViewBounds);
}
},
expand(imageTimestamp) {
const path = this.objectPath[0];
this.previewAction.invoke([path], {
timestamp: imageTimestamp,
objectPath: this.objectPath
});
},
observeForChanges(mutatedObject) {
this.updateViewBounds();
},
resize() {
let clientWidth = this.getClientWidth();
if (clientWidth !== this.width) {
this.setDimensions();
this.updateViewBounds();
}
},
getClientWidth() {
let clientWidth = this.$refs.imagery.clientWidth;
if (!clientWidth) {
//this is a hack - need a better way to find the parent of this component
let parent = this.openmct.layout.$refs.browseObject.$el;
if (parent) {
clientWidth = parent.getBoundingClientRect().width;
}
}
return clientWidth;
},
updateViewBounds(bounds, isTick) {
this.viewBounds = this.timeContext.getBounds();
if (this.timeSystem === undefined) {
this.timeSystem = this.timeContext.getTimeSystem();
}
this.setScaleAndPlotImagery(this.timeSystem, !isTick);
},
setScaleAndPlotImagery(timeSystem, clearAllImagery) {
if (timeSystem !== undefined) {
this.timeSystem = timeSystem;
this.timeFormatter = this.getFormatter(this.timeSystem.key);
}
this.setScale(this.timeSystem);
this.updatePlotImagery(clearAllImagery);
},
getFormatter(key) {
const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
let metadataValue = metadata.value(key) || { format: key };
let valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
return valueFormatter;
},
updatePlotImagery(clearAllImagery) {
this.clearPreviousImagery(clearAllImagery);
if (this.xScale) {
this.drawImagery();
}
},
clearPreviousImagery(clearAllImagery) {
//TODO: Only clear items that are out of bounds
let noItemsEl = this.$el.querySelectorAll(`.${NO_ITEMS_CLASS}`);
noItemsEl.forEach((item) => {
item.remove();
});
let imagery = this.$el.querySelectorAll(`.${IMAGE_WRAPPER_CLASS}`);
imagery.forEach((imageElm) => {
if (clearAllImagery) {
imageElm.remove();
} else {
const id = imageElm.getAttributeNS(null, 'id');
if (id) {
const timestamp = id.replace(ID_PREFIX, '');
if (
!this.isImageryInBounds({
time: timestamp
})
) {
imageElm.remove();
}
}
}
});
},
setDimensions() {
const imageryHolder = this.$refs.imagery;
this.width = this.getClientWidth();
this.height = Math.round(imageryHolder.getBoundingClientRect().height);
},
setScale(timeSystem) {
if (!this.width) {
return;
}
if (timeSystem === undefined) {
timeSystem = this.timeContext.getTimeSystem();
}
if (timeSystem.isUTCBased) {
this.xScale = scaleUtc();
this.xScale.domain([new Date(this.viewBounds.start), new Date(this.viewBounds.end)]);
} else {
this.xScale = scaleLinear();
this.xScale.domain([this.viewBounds.start, this.viewBounds.end]);
}
this.xScale.range([PADDING, this.width - PADDING * 2]);
},
isImageryInBounds(imageObj) {
return imageObj.time <= this.viewBounds.end && imageObj.time >= this.viewBounds.start;
},
getImageryContainer() {
let containerHeight = 100;
let containerWidth = this.imageHistory.length ? this.width : 200;
let imageryContainer;
let existingContainer = this.$el.querySelector(`.${CONTAINER_CLASS}`);
if (existingContainer) {
imageryContainer = existingContainer;
imageryContainer.style.maxWidth = `${containerWidth}px`;
} else {
if (this.destroyImageryContainer) {
this.destroyImageryContainer();
}
const { vNode, destroy } = mount(
{
components: {
SwimLane
},
provide: {
openmct: this.openmct
},
data() {
return {
isNested: true
};
},
template: `<swim-lane :is-nested="isNested" :hide-label="true"><template v-slot:object><div class="c-imagery-tsv-container"></div></template></swim-lane>`
},
{
app: this.openmct.app
}
);
this.destroyImageryContainer = destroy;
const component = vNode.componentInstance;
this.$refs.imageryHolder.appendChild(component.$el);
imageryContainer = component.$el.querySelector(`.${CONTAINER_CLASS}`);
imageryContainer.style.maxWidth = `${containerWidth}px`;
imageryContainer.style.height = `${containerHeight}px`;
}
return imageryContainer;
},
isImageryWidthAcceptable() {
// We're calculating if there is enough space between images to show the thumbnails.
// This algorithm could probably be enhanced to check the x co-ordinate distance between 2 consecutive images, but
// we will go with this for now assuming imagery is not sorted by asc time so it's difficult to calculate.
// TODO: Use telemetry.requestCollection to get sorted telemetry
const currentStart = this.viewBounds.start;
const currentEnd = this.viewBounds.end;
const rectX = this.xScale(currentStart);
const rectY = this.xScale(currentEnd);
const imageContainerWidth = this.imageHistory.length
? (rectY - rectX) / this.imageHistory.length
: 0;
return imageContainerWidth < IMAGE_WIDTH_THRESHOLD;
},
drawImagery() {
let imageryContainer = this.getImageryContainer();
const showImagePlaceholders = this.isImageryWidthAcceptable();
let index = 0;
if (this.imageHistory.length) {
this.imageHistory.forEach((currentImageObject) => {
if (this.isImageryInBounds(currentImageObject)) {
this.plotImagery(currentImageObject, showImagePlaceholders, imageryContainer, index);
index = index + 1;
}
});
} else {
this.plotNoItems(imageryContainer);
}
},
plotNoItems(containerElement) {
let textElement = document.createElement('text');
textElement.classList.add(NO_ITEMS_CLASS);
textElement.innerHTML = 'No images within timeframe';
containerElement.appendChild(textElement);
},
setNSAttributesForElement(element, attributes) {
if (!element) {
return;
}
Object.keys(attributes).forEach((key) => {
element.setAttributeNS(null, key, attributes[key]);
});
},
setStyles(element, styles) {
if (!element) {
return;
}
Object.keys(styles).forEach((key) => {
element.style[key] = styles[key];
});
},
getImageWrapper(item) {
const id = `${ID_PREFIX}${item.time}`;
return this.$el.querySelector(`.c-imagery-tsv__contents div[id=${id}]`);
},
plotImagery(item, showImagePlaceholders, containerElement, index) {
let existingImageWrapper = this.getImageWrapper(item);
//imageWrapper wraps the vertical tick and the image
if (existingImageWrapper) {
this.updateExistingImageWrapper(existingImageWrapper, item, showImagePlaceholders);
} else {
let imageWrapper = this.createImageWrapper(index, item, showImagePlaceholders);
containerElement.appendChild(imageWrapper);
}
},
setImageDisplay(imageElement, showImagePlaceholders) {
if (showImagePlaceholders) {
imageElement.style.display = 'none';
} else {
imageElement.style.display = 'block';
}
},
updateExistingImageWrapper(existingImageWrapper, image, showImagePlaceholders) {
//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.setNSAttributesForElement(existingImageWrapper, {
'data-show-image-placeholders': showImagePlaceholders
});
existingImageWrapper.style.left = `${this.xScale(image.time)}px`;
let imageElement = existingImageWrapper.querySelector('img');
this.setNSAttributesForElement(imageElement, {
src: image.thumbnailUrl || image.url
});
this.setImageDisplay(imageElement, showImagePlaceholders);
},
createImageWrapper(index, image, showImagePlaceholders) {
const id = `${ID_PREFIX}${image.time}`;
let imageWrapper = document.createElement('div');
imageWrapper.ariaLabel = id;
imageWrapper.classList.add(IMAGE_WRAPPER_CLASS);
imageWrapper.style.left = `${this.xScale(image.time)}px`;
this.setNSAttributesForElement(imageWrapper, {
id,
'data-show-image-placeholders': showImagePlaceholders
});
//create image vertical tick indicator
let imageTickElement = document.createElement('div');
imageTickElement.classList.add('c-imagery-tsv__image-handle');
imageTickElement.style.width = '2px';
imageTickElement.style.height = `${String(ROW_HEIGHT - 10)}px`;
imageWrapper.appendChild(imageTickElement);
//create placeholder - this will also hold the actual image
let imagePlaceholder = document.createElement('div');
imagePlaceholder.classList.add('c-imagery-tsv__image-placeholder');
imagePlaceholder.style.width = `${IMAGE_SIZE}px`;
imagePlaceholder.style.height = `${IMAGE_SIZE}px`;
imageWrapper.appendChild(imagePlaceholder);
//create image element
let imageElement = document.createElement('img');
this.setNSAttributesForElement(imageElement, {
src: image.thumbnailUrl || image.url
});
imageElement.style.width = `${IMAGE_SIZE}px`;
imageElement.style.height = `${IMAGE_SIZE}px`;
this.setImageDisplay(imageElement, showImagePlaceholders);
//handle mousedown event to show the image in a large view
imageWrapper.addEventListener('mousedown', (e) => {
if (e.button === 0) {
this.expand(image.time);
}
});
imagePlaceholder.appendChild(imageElement);
return imageWrapper;
}
}
};
</script>

View File

@ -0,0 +1,385 @@
<!--
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.
-->
<template>
<div ref="events" class="c-event-tsv c-timeline-holder">
<div ref="eventsHolder" class="c-event-tsv__contents u-contents"></div>
</div>
</template>
<script>
import { scaleLinear, scaleUtc } from 'd3-scale';
import _ from 'lodash';
import mount from 'utils/mount';
import SwimLane from '@/ui/components/swim-lane/SwimLane.vue';
import { PREVIEW_ACTION_KEY } from '@/ui/preview/PreviewAction.js';
const PADDING = 1;
const ROW_HEIGHT = 100;
const EVENT_DETAIL_SIZE = 85;
const CONTAINER_CLASS = 'c-event-tsv-container';
const NO_ITEMS_CLASS = 'c-event-tsv__no-items';
const EVENT_WRAPPER_CLASS = 'c-event-tsv__event-wrapper';
const ID_PREFIX = 'wrapper-';
export default {
inject: ['openmct', 'domainObject', 'objectPath'],
data() {
let timeSystem = this.openmct.time.getTimeSystem();
this.metadata = {};
this.requestCount = 0;
return {
viewBounds: undefined,
height: 0,
durationFormatter: undefined,
eventHistory: [],
timeSystem: timeSystem,
keyString: undefined
};
},
watch: {
eventHistory: {
handler(newHistory, oldHistory) {
this.updatePlotEvents();
},
deep: true
}
},
mounted() {
this.previewAction = this.openmct.actions.getAction(PREVIEW_ACTION_KEY);
this.canvas = this.$refs.events.appendChild(document.createElement('canvas'));
this.canvas.height = 0;
this.canvasContext = this.canvas.getContext('2d');
this.setDimensions();
this.setScaleAndPlotEvents = this.setScaleAndPlotEvents.bind(this);
this.updateViewBounds = this.updateViewBounds.bind(this);
this.setTimeContext = this.setTimeContext.bind(this);
this.setTimeContext();
this.updateViewBounds();
this.resize = _.debounce(this.resize, 400);
this.eventStripResizeObserver = new ResizeObserver(this.resize);
this.eventStripResizeObserver.observe(this.$refs.events);
this.unlisten = this.openmct.objects.observe(this.domainObject, '*', this.observeForChanges);
},
beforeUnmount() {
if (this.eventStripResizeObserver) {
this.eventStripResizeObserver.disconnect();
}
this.stopFollowingTimeContext();
if (this.unlisten) {
this.unlisten();
}
if (this.destroyEventContainer) {
this.destroyEventContainer();
}
},
methods: {
setTimeContext() {
this.stopFollowingTimeContext();
this.timeContext = this.openmct.time.getContextForView(this.objectPath);
this.timeContext.on('timeSystem', this.setScaleAndPlotEvents);
this.timeContext.on('boundsChanged', this.updateViewBounds);
},
stopFollowingTimeContext() {
if (this.timeContext) {
this.timeContext.off('timeSystem', this.setScaleAndPlotEvents);
this.timeContext.off('boundsChanged', this.updateViewBounds);
}
},
expand(eventTimestamp) {
const path = this.objectPath[0];
this.previewAction.invoke([path], {
timestamp: eventTimestamp,
objectPath: this.objectPath
});
},
observeForChanges(mutatedObject) {
this.updateViewBounds();
},
resize() {
let clientWidth = this.getClientWidth();
if (clientWidth !== this.width) {
this.setDimensions();
this.updateViewBounds();
}
},
getClientWidth() {
let clientWidth = this.$refs.events.clientWidth;
if (!clientWidth) {
//this is a hack - need a better way to find the parent of this component
let parent = this.openmct.layout.$refs.browseObject.$el;
if (parent) {
clientWidth = parent.getBoundingClientRect().width;
}
}
return clientWidth;
},
updateViewBounds(bounds, isTick) {
this.viewBounds = this.timeContext.getBounds();
if (this.timeSystem === undefined) {
this.timeSystem = this.timeContext.getTimeSystem();
}
this.setScaleAndPlotEvents(this.timeSystem, !isTick);
},
setScaleAndPlotEvents(timeSystem, clearAllEvents) {
if (timeSystem !== undefined) {
this.timeSystem = timeSystem;
this.timeFormatter = this.getFormatter(this.timeSystem.key);
}
this.setScale(this.timeSystem);
this.updatePlotEvents(clearAllEvents);
},
getFormatter(key) {
const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
let metadataValue = metadata.value(key) || { format: key };
let valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
return valueFormatter;
},
updatePlotEvents(clearAllEvents) {
this.clearPreviousEvents(clearAllEvents);
if (this.xScale) {
this.drawEvents();
}
},
clearPreviousEvents(clearAllEvents) {
//TODO: Only clear items that are out of bounds
let noItemsEl = this.$el.querySelectorAll(`.${NO_ITEMS_CLASS}`);
noItemsEl.forEach((item) => {
item.remove();
});
let events = this.$el.querySelectorAll(`.${EVENT_WRAPPER_CLASS}`);
events.forEach((eventElm) => {
if (clearAllEvents) {
eventElm.remove();
} else {
const id = eventElm.getAttributeNS(null, 'id');
if (id) {
const timestamp = id.replace(ID_PREFIX, '');
if (
!this.isEventInBounds({
time: timestamp
})
) {
eventElm.remove();
}
}
}
});
},
setDimensions() {
const eventsHolder = this.$refs.events;
this.width = this.getClientWidth();
this.height = Math.round(eventsHolder.getBoundingClientRect().height);
},
setScale(timeSystem) {
if (!this.width) {
return;
}
if (timeSystem === undefined) {
timeSystem = this.timeContext.getTimeSystem();
}
if (timeSystem.isUTCBased) {
this.xScale = scaleUtc();
this.xScale.domain([new Date(this.viewBounds.start), new Date(this.viewBounds.end)]);
} else {
this.xScale = scaleLinear();
this.xScale.domain([this.viewBounds.start, this.viewBounds.end]);
}
this.xScale.range([PADDING, this.width - PADDING * 2]);
},
isEventInBounds(evenObj) {
return evenObj.time <= this.viewBounds.end && evenObj.time >= this.viewBounds.start;
},
getEventsContainer() {
let containerHeight = 100;
let containerWidth = this.eventHistory.length ? this.width : 200;
let eventContainer;
let existingContainer = this.$el.querySelector(`.${CONTAINER_CLASS}`);
if (existingContainer) {
eventContainer = existingContainer;
eventContainer.style.maxWidth = `${containerWidth}px`;
} else {
if (this.destroyEventsContainer) {
this.destroyEventsContainer();
}
const { vNode, destroy } = mount(
{
components: {
SwimLane
},
provide: {
openmct: this.openmct
},
data() {
return {
isNested: true
};
},
template: `<swim-lane :is-nested="isNested" :hide-label="true"><template v-slot:object><div class="c-event-tsv-container"></div></template></swim-lane>`
},
{
app: this.openmct.app
}
);
this.destroyEventsContainer = destroy;
const component = vNode.componentInstance;
this.$refs.eventsHolder.appendChild(component.$el);
eventContainer = component.$el.querySelector(`.${CONTAINER_CLASS}`);
eventContainer.style.maxWidth = `${containerWidth}px`;
eventContainer.style.height = `${containerHeight}px`;
}
return eventContainer;
},
drawEvents() {
let eventContainer = this.getEventsContainer();
let index = 0;
if (this.eventHistory.length) {
this.eventHistory.forEach((currentEventObject) => {
if (this.isEventsInBounds(currentEventObject)) {
this.plotEvents(currentEventObject, eventContainer, index);
index = index + 1;
}
});
} else {
this.plotNoItems(eventContainer);
}
},
plotNoItems(containerElement) {
let textElement = document.createElement('text');
textElement.classList.add(NO_ITEMS_CLASS);
textElement.innerHTML = 'No events within timeframe';
containerElement.appendChild(textElement);
},
setNSAttributesForElement(element, attributes) {
if (!element) {
return;
}
Object.keys(attributes).forEach((key) => {
element.setAttributeNS(null, key, attributes[key]);
});
},
setStyles(element, styles) {
if (!element) {
return;
}
Object.keys(styles).forEach((key) => {
element.style[key] = styles[key];
});
},
getEventWrapper(item) {
const id = `${ID_PREFIX}${item.time}`;
return this.$el.querySelector(`.c-events-tsv__contents div[id=${id}]`);
},
plotEvents(item, containerElement, index) {
let existingEventWrapper = this.getEventWrapper(item);
//eventWrapper wraps the vertical tick and the EVENT
if (existingEventWrapper) {
this.updateExistingEventWrapper(existingEventWrapper, item);
} else {
let eventWrapper = this.createEventWrapper(index, item);
containerElement.appendChild(eventWrapper);
}
},
setEventDisplay(eventElement) {
eventElement.style.display = 'block';
},
updateExistingEventWrapper(existingEventWrapper, event) {
//Update the x co-ordinates of the event wrapper and the url of event
//this is to avoid tearing down all elements completely and re-drawing them
existingEventWrapper.style.left = `${this.xScale(event.time)}px`;
let eventElement = existingEventWrapper.querySelector('img');
this.setNSAttributesForElement(eventElement, {
src: event.thumbnailUrl || event.url
});
this.setEventDisplay(eventElement);
},
createEventWrapper(index, event) {
const id = `${ID_PREFIX}${event.time}`;
let eventWrapper = document.createElement('div');
eventWrapper.ariaLabel = id;
eventWrapper.classList.add(EVENT_WRAPPER_CLASS);
eventWrapper.style.left = `${this.xScale(event.time)}px`;
//create event vertical tick indicator
let eventTickElement = document.createElement('div');
eventTickElement.classList.add('c-events-tsv__event-handle');
eventTickElement.style.width = '2px';
eventTickElement.style.height = `${String(ROW_HEIGHT - 10)}px`;
eventWrapper.appendChild(eventTickElement);
//create placeholder - this will also hold the actual event
let eventPlaceholder = document.createElement('div');
eventPlaceholder.classList.add('c-events-tsv__event-placeholder');
eventPlaceholder.style.width = `${EVENT_DETAIL_SIZE}px`;
eventPlaceholder.style.height = `${EVENT_DETAIL_SIZE}px`;
eventWrapper.appendChild(eventPlaceholder);
//create event element
let eventElement = document.createElement('img');
this.setNSAttributesForElement(eventElement, {
src: event.thumbnailUrl || event.url
});
eventElement.style.width = `${EVENT_DETAIL_SIZE}px`;
eventElement.style.height = `${EVENT_DETAIL_SIZE}px`;
this.setEventDisplay(eventElement);
//handle mousedown event to show the event in a large view
eventWrapper.addEventListener('mousedown', (e) => {
if (e.button === 0) {
this.expand(event.time);
}
});
eventPlaceholder.appendChild(eventElement);
return eventWrapper;
}
}
};
</script>

View File

@ -20,10 +20,10 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventTimestripViewProvider from './EventTimestripViewProvider.js';
import EventTimelineViewProvider from './EventTimelineViewProvider.js';
export default function (options) {
return function install(openmct) {
openmct.objectViews.addProvider(new EventTimestripViewProvider(openmct));
openmct.objectViews.addProvider(new EventTimelineViewProvider(openmct));
};
}

View File

@ -33,10 +33,7 @@ export default function TimelineCompositionPolicy(openmct) {
}
function hasDomainAndRange(metadata) {
return (
metadata.valuesForHints(['range']).length > 0 &&
metadata.valuesForHints(['domain']).length > 0
);
return metadata.valuesForHints(['domain']).length > 0;
}
function hasImageTelemetry(domainObject, metadata) {