From d046ad13ff6fd4e94ac7c96c13bc87381f26d67f Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 12 Dec 2024 16:06:36 +0100 Subject: [PATCH] extended events --- .../events/components/EventTimelineView.vue | 24 ++++++++++---- src/plugins/timeline/ExtendedLinesOverlay.vue | 13 ++++++-- src/plugins/timeline/TimelineViewLayout.vue | 31 ++++++++++++++++--- src/ui/components/swim-lane/SwimLane.vue | 6 ++-- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/src/plugins/events/components/EventTimelineView.vue b/src/plugins/events/components/EventTimelineView.vue index b456837d72..b4c38797ef 100644 --- a/src/plugins/events/components/EventTimelineView.vue +++ b/src/plugins/events/components/EventTimelineView.vue @@ -30,9 +30,11 @@ import { scaleLinear, scaleUtc } from 'd3-scale'; import _ from 'lodash'; import mount from 'utils/mount'; +import { inject } from 'vue'; import SwimLane from '@/ui/components/swim-lane/SwimLane.vue'; +import { useAlignment } from '../../../ui/composables/alignmentContext.js'; import eventData from '../mixins/eventData.js'; const PADDING = 1; @@ -41,10 +43,18 @@ const CONTAINER_CLASS = 'c-events-tsv-container'; const NO_ITEMS_CLASS = 'c-events-tsv__no-items'; const EVENT_WRAPPER_CLASS = 'c-events-tsv__event-wrapper'; const ID_PREFIX = 'wrapper-'; +const AXES_PADDING = 20; export default { mixins: [eventData], inject: ['openmct', 'domainObject', 'objectPath', 'extendedLinesBus'], + setup() { + const domainObject = inject('domainObject'); + const objectPath = inject('objectPath'); + const openmct = inject('openmct'); + const { alignment: alignmentData } = useAlignment(domainObject, objectPath, openmct); + return { alignmentData }; + }, data() { const timeSystem = this.openmct.time.getTimeSystem(); this.metadata = {}; @@ -64,12 +74,15 @@ export default { this.updatePlotEvents(); }, deep: true + }, + alignmentData: { + handler() { + this.updateViewBounds(); + }, + deep: true } }, mounted() { - 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); @@ -349,8 +362,7 @@ export default { } }, updateExistingEventWrapper(existingEventWrapper, event) { - // Update the x co-ordinates of the event wrapper - existingEventWrapper.style.left = `${this.xScale(event.time)}px`; + existingEventWrapper.style.left = `${this.xScale(event.time) + this.alignmentData.leftWidth + AXES_PADDING}px`; }, createPathSelection() { const selection = []; @@ -406,7 +418,7 @@ export default { eventWrapper.ariaLabel = id; eventWrapper.setAttribute('id', id); eventWrapper.classList.add(EVENT_WRAPPER_CLASS); - eventWrapper.style.left = `${this.xScale(event.time)}px`; + eventWrapper.style.left = `${this.xScale(event.time) + this.alignmentData.leftWidth + AXES_PADDING}px`; const eventTickElement = document.createElement('div'); eventTickElement.classList.add('c-events-tsv__event-handle'); diff --git a/src/plugins/timeline/ExtendedLinesOverlay.vue b/src/plugins/timeline/ExtendedLinesOverlay.vue index 288aa52fbe..e4227cdaa6 100644 --- a/src/plugins/timeline/ExtendedLinesOverlay.vue +++ b/src/plugins/timeline/ExtendedLinesOverlay.vue @@ -26,7 +26,7 @@ v-for="(line, index) in extendedLines" :key="index" class="extended-line" - :style="{ left: `${line.x}px`, height: `${height}px` }" + :style="{ left: `${line.x + leftOffset}px`, height: `${height}px` }" > @@ -37,11 +37,20 @@ export default { props: { extendedLines: { type: Array, - default: () => {} + default: () => [] }, height: { type: Number, required: true + }, + leftOffset: { + type: Number, + default: 0 + } + }, + watch: { + leftOffset(newVal) { + console.log('leftOffset received:', newVal); } } }; diff --git a/src/plugins/timeline/TimelineViewLayout.vue b/src/plugins/timeline/TimelineViewLayout.vue index 79d9c2e9db..66c9f74f92 100644 --- a/src/plugins/timeline/TimelineViewLayout.vue +++ b/src/plugins/timeline/TimelineViewLayout.vue @@ -46,7 +46,11 @@ /> - + @@ -69,6 +73,8 @@ const unknownObjectType = { } }; +const AXES_PADDING = 20; + export default { components: { TimelineObjectView, @@ -96,9 +102,15 @@ export default { height: 0, useIndependentTime: this.domainObject.configuration.useIndependentTime === true, timeOptions: this.domainObject.configuration.timeOptions, - extendedLines: [] + extendedLines: [], + additionalLeftOffset: 0 }; }, + computed: { + extendedLeftOffset() { + return this.alignmentData.leftWidth + this.additionalLeftOffset; + } + }, beforeUnmount() { this.resetAlignment(); this.composition.off('add', this.addItem); @@ -109,7 +121,7 @@ export default { this.contentResizeObserver.disconnect(); this.extendedLinesBus.off('update-extended-lines', this.updateExtendedLines); }, - mounted() { + async mounted() { this.items = []; this.setTimeContext(); @@ -125,6 +137,8 @@ export default { this.handleContentResize = _.debounce(this.handleContentResize, 500); this.contentResizeObserver = new ResizeObserver(this.handleContentResize); this.contentResizeObserver.observe(this.$refs.timelineHolder); + await this.$nextTick(); + this.calculateAdditionalLeftOffset(); }, methods: { addItem(domainObject) { @@ -235,8 +249,17 @@ export default { } }, updateExtendedLines({ keyString, lines }) { - console.debug('🗺️ Updating extended lines', lines); this.extendedLines = lines; + }, + calculateAdditionalLeftOffset() { + const firstSwimLane = this.$el.querySelector('.c-swimlane__lane-object'); + if (firstSwimLane) { + const timelineHolderRect = this.$refs.timelineHolder.getBoundingClientRect(); + const laneObjectRect = firstSwimLane.getBoundingClientRect(); + const offset = laneObjectRect.left - timelineHolderRect.left; + this.additionalLeftOffset = offset + AXES_PADDING; + } + console.debug('🤖 additionalLeftOffset:', this.additionalLeftOffset); } } }; diff --git a/src/ui/components/swim-lane/SwimLane.vue b/src/ui/components/swim-lane/SwimLane.vue index 9ad3935865..e224553ab9 100644 --- a/src/ui/components/swim-lane/SwimLane.vue +++ b/src/ui/components/swim-lane/SwimLane.vue @@ -128,19 +128,19 @@ export default { hideButton: { type: Boolean, default() { - return false; + return true; } }, buttonTitle: { type: String, default() { - return ''; + return null; } }, buttonIcon: { type: String, default() { - return ''; + return null; } }, buttonClickOn: {