mirror of
https://github.com/nasa/openmct.git
synced 2025-03-12 23:44:08 +00:00
WIP: use flex layout container sizing for timeline
This commit is contained in:
parent
25a372e725
commit
4345722fe0
17
src/plugins/timeline/Container.js
Normal file
17
src/plugins/timeline/Container.js
Normal file
@ -0,0 +1,17 @@
|
||||
class Container {
|
||||
constructor(domainObject, size) {
|
||||
this.domainObjectIdentifier = domainObject.identifier;
|
||||
this.size = size;
|
||||
this.scale = getContainerScale(domainObject);
|
||||
}
|
||||
}
|
||||
|
||||
function getContainerScale(domainObject) {
|
||||
if (domainObject.type === 'telemetry.plot.stacked') {
|
||||
return domainObject?.composition?.length;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
export default Container;
|
@ -24,7 +24,6 @@
|
||||
<SwimLane
|
||||
:icon-class="item.type.definition.cssClass"
|
||||
:status="status"
|
||||
:min-height="item.height"
|
||||
:show-ucontents="isPlanLikeObject(item.domainObject)"
|
||||
:span-rows-count="item.rowCount"
|
||||
:domain-object="item.domainObject"
|
||||
@ -33,6 +32,7 @@
|
||||
:hide-button="!hasEventTelemetry()"
|
||||
:button-click-on="enableExtendEventLines"
|
||||
:button-click-off="disableExtendEventLines"
|
||||
:style="[{ 'flex-basis': sizeString }]"
|
||||
>
|
||||
<template #label>
|
||||
{{ item.domainObject.name }}
|
||||
@ -67,6 +67,10 @@ export default {
|
||||
extendedLinesBus: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -76,6 +80,11 @@ export default {
|
||||
status: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sizeString() {
|
||||
return `${this.size}px`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
item(newItem) {
|
||||
if (!this.context) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
<TimelineObjectView
|
||||
class="c-timeline__content js-timeline__content"
|
||||
:item="item"
|
||||
:size="getContainerSize(item)"
|
||||
:extended-lines-bus
|
||||
/>
|
||||
<ResizeHandle
|
||||
@ -71,8 +72,10 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash';
|
||||
import { identifierEquals } from 'objectUtils';
|
||||
import { useDragResizer } from 'utils/vue/useDragResizer.js';
|
||||
import { inject, provide } from 'vue';
|
||||
import { useFlexContainers } from 'utils/vue/useFlexContainers.js';
|
||||
import { inject, onMounted, provide, ref } from 'vue';
|
||||
|
||||
import SwimLane from '@/ui/components/swim-lane/SwimLane.vue';
|
||||
import ResizeHandle from '@/ui/layout/ResizeHandle/ResizeHandle.vue';
|
||||
@ -80,6 +83,7 @@ import ResizeHandle from '@/ui/layout/ResizeHandle/ResizeHandle.vue';
|
||||
import TimelineAxis from '../../ui/components/TimeSystemAxis.vue';
|
||||
import { useAlignment } from '../../ui/composables/alignmentContext.js';
|
||||
import { getValidatedData, getValidatedGroups } from '../plan/util.js';
|
||||
import Container from './Container.js';
|
||||
import ExtendedLinesOverlay from './ExtendedLinesOverlay.vue';
|
||||
import TimelineObjectView from './TimelineObjectView.vue';
|
||||
|
||||
@ -112,6 +116,8 @@ export default {
|
||||
const domainObject = inject('domainObject');
|
||||
const path = inject('path');
|
||||
const openmct = inject('openmct');
|
||||
const items = ref([]);
|
||||
|
||||
const { alignment: alignmentData, reset: resetAlignment } = useAlignment(
|
||||
domainObject,
|
||||
path,
|
||||
@ -124,11 +130,46 @@ export default {
|
||||
provide('swimLaneLabelWidth', swimLaneLabelWidth);
|
||||
provide('mousedown', mousedown);
|
||||
|
||||
return { alignmentData, resetAlignment };
|
||||
// Flex containers - Swimlane height
|
||||
const timelineHolder = ref(null);
|
||||
onMounted(() => {
|
||||
console.log(timelineHolder.value);
|
||||
});
|
||||
|
||||
const {
|
||||
addContainer,
|
||||
containers,
|
||||
startContainerResizing,
|
||||
containerResizing,
|
||||
endContainerResizing
|
||||
} = useFlexContainers(timelineHolder, {
|
||||
containerClass: Container,
|
||||
rowsLayout: true
|
||||
});
|
||||
|
||||
function getContainerSize(item) {
|
||||
const containerforItem = containers.value.find((container) =>
|
||||
identifierEquals(container.domainObjectIdentifier, item.identifier)
|
||||
);
|
||||
|
||||
return containerforItem.size;
|
||||
}
|
||||
|
||||
return {
|
||||
containers,
|
||||
getContainerSize,
|
||||
timelineHolder,
|
||||
items,
|
||||
addContainer,
|
||||
alignmentData,
|
||||
resetAlignment,
|
||||
startContainerResizing,
|
||||
containerResizing,
|
||||
endContainerResizing
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
items: [],
|
||||
timeSystems: [],
|
||||
height: 0,
|
||||
useIndependentTime: this.domainObject.configuration.useIndependentTime === true,
|
||||
@ -205,6 +246,7 @@ export default {
|
||||
};
|
||||
|
||||
this.items.push(item);
|
||||
this.addContainer(item);
|
||||
},
|
||||
removeItem(identifier) {
|
||||
let index = this.items.findIndex((item) =>
|
||||
|
@ -22,42 +22,42 @@
|
||||
|
||||
/********************************************* TIME STRIP */
|
||||
.c-timeline-holder {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
height: 100%;
|
||||
|
||||
// Plot view overrides
|
||||
.gl-plot-display-area,
|
||||
.gl-plot-axis-area.gl-plot-y {
|
||||
bottom: $interiorMargin !important;
|
||||
}
|
||||
// Plot view overrides
|
||||
.gl-plot-display-area,
|
||||
.gl-plot-axis-area.gl-plot-y {
|
||||
bottom: $interiorMargin !important;
|
||||
}
|
||||
}
|
||||
|
||||
.c-timeline {
|
||||
&__objects {
|
||||
display: contents;
|
||||
&__objects {
|
||||
display: contents;
|
||||
|
||||
.c-swimlane {
|
||||
min-height: 100px; // TEMP!! Will be replaced when heights are set by user
|
||||
}
|
||||
.c-swimlane {
|
||||
// min-height: 100px; // TEMP!! Will be replaced when heights are set by user
|
||||
}
|
||||
}
|
||||
|
||||
&__overlay-lines {
|
||||
//background: rgba(deeppink, 0.2);
|
||||
@include abs();
|
||||
top: 20px; // Offset down to line up with time axis ticks line
|
||||
pointer-events: none; // Allows clicks to pass through
|
||||
z-index: 10; // Ensure it sits atop swimlanes
|
||||
}
|
||||
&__overlay-lines {
|
||||
//background: rgba(deeppink, 0.2);
|
||||
@include abs();
|
||||
top: 20px; // Offset down to line up with time axis ticks line
|
||||
pointer-events: none; // Allows clicks to pass through
|
||||
z-index: 10; // Ensure it sits atop swimlanes
|
||||
}
|
||||
|
||||
&__no-items {
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
&__no-items {
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
97
src/utils/vue/useFlexContainers.js
Normal file
97
src/utils/vue/useFlexContainers.js
Normal file
@ -0,0 +1,97 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
export function useFlexContainers(element, { rowsLayout, minContainerSize = 5, callback }) {
|
||||
const containers = ref([]);
|
||||
const maxMoveSize = ref(null);
|
||||
let sizingContainers = 0;
|
||||
|
||||
function addContainer(container) {
|
||||
containers.value.push(container);
|
||||
|
||||
if (container.scale) {
|
||||
sizingContainers += container.scale;
|
||||
} else {
|
||||
sizingContainers++;
|
||||
}
|
||||
|
||||
sizeItems(containers.value, container);
|
||||
|
||||
callback?.();
|
||||
}
|
||||
|
||||
function startContainerResizing(index) {
|
||||
const beforeContainer = containers.value[index];
|
||||
const afterContainer = containers.value[index + 1];
|
||||
|
||||
maxMoveSize.value = beforeContainer.size + afterContainer.size;
|
||||
}
|
||||
|
||||
function containerResizing(index, delta, event) {
|
||||
let percentageMoved = Math.round((delta / getElSize()) * 100);
|
||||
let beforeContainer = containers.value[index];
|
||||
let afterContainer = containers.value[index + 1];
|
||||
|
||||
beforeContainer.size = getContainerSize(beforeContainer.size + percentageMoved);
|
||||
afterContainer.size = getContainerSize(afterContainer.size - percentageMoved);
|
||||
}
|
||||
|
||||
function endContainerResizing() {
|
||||
// persist the new container sizes
|
||||
callback?.(containers.value);
|
||||
}
|
||||
|
||||
function getElSize() {
|
||||
if (rowsLayout) {
|
||||
return element.value.offsetHeight;
|
||||
} else {
|
||||
return element.value.offsetWidth;
|
||||
}
|
||||
}
|
||||
|
||||
function getContainerSize(size) {
|
||||
if (size < minContainerSize) {
|
||||
return minContainerSize;
|
||||
} else if (size > maxMoveSize.value - minContainerSize) {
|
||||
return maxMoveSize.value - minContainerSize;
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
// Resize items so that newItem fits proportionally (newItem must be an element
|
||||
// of items). If newItem does not have a size or is sized at 100%, newItem will
|
||||
// have size set to 1/n * 100, where n is the total number of items.
|
||||
function sizeItems(items, newItem) {
|
||||
const newItemScale = newItem.scale || 1;
|
||||
|
||||
if (items.length === 1) {
|
||||
newItem.size = 100;
|
||||
} else {
|
||||
if (!newItem.size || newItem.size === 100) {
|
||||
newItem.size = Math.round((100 * newItemScale) / sizingContainers);
|
||||
}
|
||||
|
||||
// Resize oldItems to fit inside remaining space;
|
||||
const oldItems = items.filter((item) => item !== newItem);
|
||||
const remainingSize = 100 - newItem.size;
|
||||
|
||||
oldItems.forEach((item) => {
|
||||
const itemScale = item.scale || 1;
|
||||
item.size = Math.round((item.size * itemScale * remainingSize) / 100);
|
||||
});
|
||||
|
||||
// Ensure items add up to 100 in case of rounding error.
|
||||
let total = items.reduce((t, item) => t + item.size, 0);
|
||||
let excess = Math.round(100 - total);
|
||||
oldItems[oldItems.length - 1].size += excess;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
addContainer,
|
||||
containers,
|
||||
startContainerResizing,
|
||||
containerResizing,
|
||||
endContainerResizing
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user