mirror of
https://github.com/nasa/openmct.git
synced 2025-05-09 20:12:50 +00:00
WIP: allow fixed pixel heights
This commit is contained in:
parent
54a131eaaf
commit
c5ee817c81
@ -45,6 +45,7 @@
|
|||||||
:object-path="[elementObject, domainObject]"
|
:object-path="[elementObject, domainObject]"
|
||||||
@context-click-active="setContextClickState"
|
@context-click-active="setContextClickState"
|
||||||
/>
|
/>
|
||||||
|
<slot name="content"></slot>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -42,7 +42,11 @@
|
|||||||
:allow-drop="allowDrop"
|
:allow-drop="allowDrop"
|
||||||
@dragstart-custom="moveFrom(index)"
|
@dragstart-custom="moveFrom(index)"
|
||||||
@drop-custom="moveTo(index)"
|
@drop-custom="moveTo(index)"
|
||||||
/>
|
>
|
||||||
|
<template #content="slotProps">
|
||||||
|
<slot name="content" :index="index" :object="element" v-bind="slotProps"></slot>
|
||||||
|
</template>
|
||||||
|
</ElementItem>
|
||||||
<li class="js-last-place" @drop="moveToIndex(elements.length)"></li>
|
<li class="js-last-place" @drop="moveToIndex(elements.length)"></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div v-if="elements.length === 0">No contained elements</div>
|
<div v-if="elements.length === 0">No contained elements</div>
|
||||||
|
@ -29,6 +29,7 @@ export default function ElementsViewProvider(openmct) {
|
|||||||
key: 'elementsView',
|
key: 'elementsView',
|
||||||
name: 'Elements',
|
name: 'Elements',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
|
// TODO - only use this view provider if another custom provider has not been applied
|
||||||
const hasValidSelection = selection?.length;
|
const hasValidSelection = selection?.length;
|
||||||
const isOverlayPlot = selection?.[0]?.[0]?.context?.item?.type === 'telemetry.plot.overlay';
|
const isOverlayPlot = selection?.[0]?.[0]?.context?.item?.type === 'telemetry.plot.overlay';
|
||||||
|
|
||||||
|
82
src/plugins/timeline/TimelineElementsContent.vue
Normal file
82
src/plugins/timeline/TimelineElementsContent.vue
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<template v-if="fixed">
|
||||||
|
<input
|
||||||
|
:value="size"
|
||||||
|
aria-labelledby="pixelSize"
|
||||||
|
class="field control"
|
||||||
|
:pattern="/\d+/"
|
||||||
|
type="number"
|
||||||
|
name="value"
|
||||||
|
min="0"
|
||||||
|
@change="changeSize"
|
||||||
|
/>
|
||||||
|
<span>px</span>
|
||||||
|
</template>
|
||||||
|
<select v-model="isFixed" aria-label="fixedOrFlex">
|
||||||
|
<option :selected="!isFixed" :value="false">flex</option>
|
||||||
|
<option :selected="isFixed" :value="true">fixed</option>
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { computed, inject, ref, toRaw } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
object: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const openmct = inject('openmct');
|
||||||
|
const domainObject = inject('domainObject');
|
||||||
|
|
||||||
|
openmct.objects.observe(domainObject, 'configuration.containers', updateContainer);
|
||||||
|
|
||||||
|
const container = ref(null);
|
||||||
|
const fixed = computed(() => {
|
||||||
|
return container.value?.fixed;
|
||||||
|
});
|
||||||
|
const isFixed = computed({ get: () => fixed, set: (_isFixed) => toggleFixed(_isFixed) });
|
||||||
|
const size = computed(() => container.value?.size);
|
||||||
|
|
||||||
|
function toggleFixed(_fixed) {
|
||||||
|
openmct.objectViews.emit(
|
||||||
|
`contextAction:${openmct.objects.makeKeyString(domainObject.identifier)}`,
|
||||||
|
'toggleFixedContextAction',
|
||||||
|
props.index,
|
||||||
|
_fixed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeSize(event) {
|
||||||
|
const _size = Number(event.target.value);
|
||||||
|
openmct.objectViews.emit(
|
||||||
|
`contextAction:${openmct.objects.makeKeyString(domainObject.identifier)}`,
|
||||||
|
'changeSizeContextAction',
|
||||||
|
props.index,
|
||||||
|
_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateContainer(containers) {
|
||||||
|
container.value = containers[props.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
openmct,
|
||||||
|
domainObject,
|
||||||
|
container,
|
||||||
|
fixed,
|
||||||
|
isFixed,
|
||||||
|
size,
|
||||||
|
updateContainer,
|
||||||
|
changeSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
21
src/plugins/timeline/TimelineElementsPool.vue
Normal file
21
src/plugins/timeline/TimelineElementsPool.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<ElementsPool>
|
||||||
|
<template #content="{ index, object }">
|
||||||
|
<TimelineElementsContent :index="index" :object="object" />
|
||||||
|
</template>
|
||||||
|
</ElementsPool>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import ElementsPool from '@/plugins/inspectorViews/elements/ElementsPool.vue';
|
||||||
|
|
||||||
|
import TimelineElementsContent from './TimelineElementsContent.vue';
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ElementsPool,
|
||||||
|
TimelineElementsContent
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
76
src/plugins/timeline/TimelineElementsViewProvider.js
Normal file
76
src/plugins/timeline/TimelineElementsViewProvider.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 mount from 'utils/mount';
|
||||||
|
|
||||||
|
import TimelineElementsPool from './TimelineElementsPool.vue';
|
||||||
|
|
||||||
|
export default function TimelineElementsViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'timelineElementsView',
|
||||||
|
name: 'Elements',
|
||||||
|
canView: function (selection) {
|
||||||
|
return selection?.[0]?.[0]?.context?.item?.type === 'time-strip';
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let _destroy = null;
|
||||||
|
|
||||||
|
const domainObject = selection?.[0]?.[0]?.context?.item;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (element) {
|
||||||
|
const { destroy } = mount(
|
||||||
|
{
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
TimelineElementsPool
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject
|
||||||
|
},
|
||||||
|
template: `<TimelineElementsPool />`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
app: openmct.app,
|
||||||
|
element
|
||||||
|
}
|
||||||
|
);
|
||||||
|
_destroy = destroy;
|
||||||
|
},
|
||||||
|
showTab: function (isEditing) {
|
||||||
|
const hasComposition = Boolean(domainObject && openmct.composition.get(domainObject));
|
||||||
|
|
||||||
|
return hasComposition && isEditing;
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return openmct.priority.HIGH - 1;
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
if (_destroy) {
|
||||||
|
_destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -32,7 +32,8 @@
|
|||||||
:hide-button="!item.isEventTelemetry"
|
:hide-button="!item.isEventTelemetry"
|
||||||
:button-click-on="enableExtendEventLines"
|
:button-click-on="enableExtendEventLines"
|
||||||
:button-click-off="disableExtendEventLines"
|
:button-click-off="disableExtendEventLines"
|
||||||
:style="[{ 'flex-basis': sizeString }]"
|
:class="sizeClass"
|
||||||
|
:style="sizeStyle"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
{{ item.domainObject.name }}
|
{{ item.domainObject.name }}
|
||||||
@ -64,12 +65,12 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
extendedLinesBus: {
|
container: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
size: {
|
extendedLinesBus: {
|
||||||
type: Number,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -81,8 +82,17 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
sizeString() {
|
size() {
|
||||||
return `${this.size}%`;
|
return this.container.size;
|
||||||
|
},
|
||||||
|
fixed() {
|
||||||
|
return this.container.fixed;
|
||||||
|
},
|
||||||
|
sizeClass() {
|
||||||
|
return `--${this.fixed ? 'fixed' : 'scales'}`;
|
||||||
|
},
|
||||||
|
sizeStyle() {
|
||||||
|
return `flex-basis: ${this.size}${this.fixed ? 'px' : '%'}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
<TimelineObjectView
|
<TimelineObjectView
|
||||||
class="c-timeline__content js-timeline__content"
|
class="c-timeline__content js-timeline__content"
|
||||||
:item="item"
|
:item="item"
|
||||||
:size="getContainerSize(item)"
|
:container="containers[index]"
|
||||||
:extended-lines-bus
|
:extended-lines-bus
|
||||||
/>
|
/>
|
||||||
<ResizeHandle
|
<ResizeHandle
|
||||||
@ -156,7 +156,9 @@ export default {
|
|||||||
containers,
|
containers,
|
||||||
startContainerResizing,
|
startContainerResizing,
|
||||||
containerResizing,
|
containerResizing,
|
||||||
endContainerResizing
|
endContainerResizing,
|
||||||
|
toggleFixed,
|
||||||
|
sizeFixedContainer
|
||||||
} = useFlexContainers(timelineHolder, {
|
} = useFlexContainers(timelineHolder, {
|
||||||
containers: domainObject.configuration.containers,
|
containers: domainObject.configuration.containers,
|
||||||
rowsLayout: true,
|
rowsLayout: true,
|
||||||
@ -167,13 +169,22 @@ export default {
|
|||||||
composition.value = loadedComposition;
|
composition.value = loadedComposition;
|
||||||
isCompositionLoaded = true;
|
isCompositionLoaded = true;
|
||||||
|
|
||||||
|
// check if containers configuration matches composition
|
||||||
|
// in case composition has been modified outside of view
|
||||||
|
// if so, rebuild containers to match composition
|
||||||
// sync containers to composition,
|
// sync containers to composition,
|
||||||
// in case composition modified outside of view
|
// in case composition modified outside of view
|
||||||
// but do not mutate until user makes a change
|
// but do not mutate until user makes a change
|
||||||
composition.value.forEach((object) => {
|
let isConfigurationChanged = false;
|
||||||
|
composition.value.forEach((object, index) => {
|
||||||
const containerIndex = domainObject.configuration.containers.findIndex((container) =>
|
const containerIndex = domainObject.configuration.containers.findIndex((container) =>
|
||||||
openmct.objects.areIdsEqual(container.domainObjectIdentifier, object.identifier)
|
openmct.objects.areIdsEqual(container.domainObjectIdentifier, object.identifier)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (containerIndex !== index) {
|
||||||
|
isConfigurationChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (containerIndex > -1) {
|
if (containerIndex > -1) {
|
||||||
existingContainers.push(domainObject.configuration.containers[containerIndex]);
|
existingContainers.push(domainObject.configuration.containers[containerIndex]);
|
||||||
} else {
|
} else {
|
||||||
@ -182,7 +193,13 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// add check for total size not equal to 100? if comp and containers same, probably safe
|
||||||
|
|
||||||
|
if (isConfigurationChanged) {
|
||||||
|
console.log('yo');
|
||||||
setContainers(existingContainers);
|
setContainers(existingContainers);
|
||||||
|
mutateContainers();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function addItem(_domainObject) {
|
function addItem(_domainObject) {
|
||||||
@ -267,6 +284,16 @@ export default {
|
|||||||
openmct.objects.mutate(domainObject, 'configuration.containers', containers.value);
|
openmct.objects.mutate(domainObject, 'configuration.containers', containers.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// context action called from outside component
|
||||||
|
function toggleFixedContextAction(index, fixed) {
|
||||||
|
toggleFixed(index, fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// context action called from outside component
|
||||||
|
function changeSizeContextAction(index, size) {
|
||||||
|
sizeFixedContainer(index, size);
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
compositionCollection.off('add', addItem);
|
compositionCollection.off('add', addItem);
|
||||||
compositionCollection.off('remove', removeItem);
|
compositionCollection.off('remove', removeItem);
|
||||||
@ -292,7 +319,9 @@ export default {
|
|||||||
startContainerResizing,
|
startContainerResizing,
|
||||||
containerResizing,
|
containerResizing,
|
||||||
endContainerResizing,
|
endContainerResizing,
|
||||||
mutateContainers
|
mutateContainers,
|
||||||
|
toggleFixedContextAction,
|
||||||
|
changeSizeContextAction
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -61,7 +61,8 @@ export default function TimelineViewProvider(openmct, extendedLinesBus) {
|
|||||||
isEditing
|
isEditing
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
template: '<timeline-view-layout :is-editing="isEditing"></timeline-view-layout>'
|
template:
|
||||||
|
'<timeline-view-layout ref="timeline" :is-editing="isEditing"></timeline-view-layout>'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
app: openmct.app,
|
app: openmct.app,
|
||||||
@ -71,6 +72,11 @@ export default function TimelineViewProvider(openmct, extendedLinesBus) {
|
|||||||
component = vNode.componentInstance;
|
component = vNode.componentInstance;
|
||||||
_destroy = destroy;
|
_destroy = destroy;
|
||||||
},
|
},
|
||||||
|
contextAction(action, ...args) {
|
||||||
|
if (component?.$refs?.timeline?.[action]) {
|
||||||
|
component.$refs.timeline[action](...args);
|
||||||
|
}
|
||||||
|
},
|
||||||
onEditModeChange(isEditing) {
|
onEditModeChange(isEditing) {
|
||||||
component.isEditing = isEditing;
|
component.isEditing = isEditing;
|
||||||
},
|
},
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
import { configuration } from './configuration.js';
|
import { configuration } from './configuration.js';
|
||||||
import ExtendedLinesBus from './ExtendedLinesBus.js';
|
import ExtendedLinesBus from './ExtendedLinesBus.js';
|
||||||
import TimelineCompositionPolicy from './TimelineCompositionPolicy.js';
|
import TimelineCompositionPolicy from './TimelineCompositionPolicy.js';
|
||||||
|
import TimelineElementsViewProvider from './TimelineElementsViewProvider.js';
|
||||||
import timelineInterceptor from './timelineInterceptor.js';
|
import timelineInterceptor from './timelineInterceptor.js';
|
||||||
import TimelineViewProvider from './TimelineViewProvider.js';
|
import TimelineViewProvider from './TimelineViewProvider.js';
|
||||||
|
|
||||||
const extendedLinesBus = new ExtendedLinesBus();
|
const extendedLinesBus = new ExtendedLinesBus();
|
||||||
|
|
||||||
export { extendedLinesBus };
|
export { extendedLinesBus };
|
||||||
@ -48,6 +48,7 @@ export default function () {
|
|||||||
openmct.composition.addPolicy(new TimelineCompositionPolicy(openmct).allow);
|
openmct.composition.addPolicy(new TimelineCompositionPolicy(openmct).allow);
|
||||||
|
|
||||||
openmct.objectViews.addProvider(new TimelineViewProvider(openmct, extendedLinesBus));
|
openmct.objectViews.addProvider(new TimelineViewProvider(openmct, extendedLinesBus));
|
||||||
|
openmct.inspectorViews.addProvider(new TimelineElementsViewProvider(openmct));
|
||||||
}
|
}
|
||||||
|
|
||||||
install.extendedLinesBus = extendedLinesBus;
|
install.extendedLinesBus = extendedLinesBus;
|
||||||
|
@ -45,6 +45,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
&.--scales {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--fixed {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__overlay-lines {
|
&__overlay-lines {
|
||||||
@include abs();
|
@include abs();
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
@ -89,8 +89,10 @@ export function useFlexContainers(
|
|||||||
const beforeContainer = getBeforeContainer(index);
|
const beforeContainer = getBeforeContainer(index);
|
||||||
const afterContainer = getAfterContainer(index);
|
const afterContainer = getAfterContainer(index);
|
||||||
|
|
||||||
|
if (beforeContainer && afterContainer && !beforeContainer.fixed && !afterContainer.fixed) {
|
||||||
maxMoveSize.value = beforeContainer.size + afterContainer.size;
|
maxMoveSize.value = beforeContainer.size + afterContainer.size;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getBeforeContainer(index) {
|
function getBeforeContainer(index) {
|
||||||
return containers.value
|
return containers.value
|
||||||
@ -108,24 +110,14 @@ export function useFlexContainers(
|
|||||||
const afterContainer = getAfterContainer(index);
|
const afterContainer = getAfterContainer(index);
|
||||||
const percentageMoved = Math.round((delta / getElSize()) * 100);
|
const percentageMoved = Math.round((delta / getElSize()) * 100);
|
||||||
|
|
||||||
if (beforeContainer === undefined || afterContainer === undefined) {
|
if (beforeContainer && afterContainer && !beforeContainer.fixed && !afterContainer.fixed) {
|
||||||
console.warn(
|
|
||||||
'Cannot drag to resize a single flex sized containers. Use Elements Tab in Inspector to resize fixed containers.'
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beforeContainer.fixed === true && afterContainer.fixed === true) {
|
|
||||||
console.warn(
|
|
||||||
'Cannot drag to resize two fixed sized containers. Use Elements Tab in Inspector to resize.'
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeContainer.size = getContainerSize(beforeContainer.size + percentageMoved);
|
beforeContainer.size = getContainerSize(beforeContainer.size + percentageMoved);
|
||||||
afterContainer.size = getContainerSize(afterContainer.size - percentageMoved);
|
afterContainer.size = getContainerSize(afterContainer.size - percentageMoved);
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
'Drag requires two flexible containers. Use Elements Tab in Inspector to resize.'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function endContainerResizing() {
|
function endContainerResizing() {
|
||||||
@ -163,45 +155,92 @@ export function useFlexContainers(
|
|||||||
* due to composition edits outside of view
|
* due to composition edits outside of view
|
||||||
*
|
*
|
||||||
* @param {*} items
|
* @param {*} items
|
||||||
|
* @param {Number} (optional) index of the item to apply excess to in the event of rounding errors
|
||||||
*/
|
*/
|
||||||
function sizeItems(items) {
|
function sizeItems(items, index) {
|
||||||
let totalSize;
|
let totalSize;
|
||||||
const itemsWithSize = items.filter((item) => item.size);
|
const flexItems = items.filter((item) => !item.fixed);
|
||||||
const itemsWithoutSize = items.filter((item) => !item.size);
|
const flexItemsWithSize = flexItems.filter((item) => item.size);
|
||||||
// total number of items, adjusted by each item scale
|
const flexItemsWithoutSize = flexItems.filter((item) => !item.size);
|
||||||
const totalScale = items.reduce((total, item) => {
|
// total number of flexible items, adjusted by each item scale
|
||||||
|
const totalScale = flexItems.reduce((total, item) => {
|
||||||
const scale = item.scale ?? 1;
|
const scale = item.scale ?? 1;
|
||||||
return total + scale;
|
return total + scale;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
itemsWithoutSize.forEach((item) => {
|
flexItemsWithoutSize.forEach((item) => {
|
||||||
const scale = item.scale ?? 1;
|
const scale = item.scale ?? 1;
|
||||||
item.size = Math.round((100 * scale) / totalScale);
|
item.size = Math.round((100 * scale) / totalScale);
|
||||||
});
|
});
|
||||||
|
|
||||||
totalSize = items.reduce((total, item) => total + item.size, 0);
|
totalSize = flexItems.reduce((total, item) => total + item.size, 0);
|
||||||
|
|
||||||
if (totalSize > 100) {
|
if (totalSize > 100) {
|
||||||
const addedSize = itemsWithoutSize.reduce((total, item) => total + item.size, 0);
|
const addedSize = flexItemsWithoutSize.reduce((total, item) => total + item.size, 0);
|
||||||
const remainingSize = 100 - addedSize;
|
const remainingSize = 100 - addedSize;
|
||||||
|
|
||||||
itemsWithSize.forEach((item) => {
|
flexItemsWithSize.forEach((item) => {
|
||||||
const scale = item.scale ?? 1;
|
const scale = item.scale ?? 1;
|
||||||
item.size = Math.round((item.size * scale * remainingSize) / 100);
|
item.size = Math.round((item.size * scale * remainingSize) / 100);
|
||||||
});
|
});
|
||||||
} else if (totalSize < 100) {
|
} else if (totalSize < 100) {
|
||||||
const sizeToFill = 100 - totalSize;
|
const sizeToFill = 100 - totalSize;
|
||||||
|
|
||||||
items.forEach((item) => {
|
flexItems.forEach((item) => {
|
||||||
const scale = item.scale ?? 1;
|
const scale = item.scale ?? 1;
|
||||||
item.size = Math.round((item.size * scale * 100) / sizeToFill);
|
item.size = Math.round((item.size * scale * 100) / sizeToFill);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure items add up to 100 in case of rounding error.
|
// Ensure items add up to 100 in case of rounding error.
|
||||||
totalSize = items.reduce((total, item) => total + item.size, 0);
|
totalSize = flexItems.reduce((total, item) => total + item.size, 0);
|
||||||
const excess = Math.round(100 - totalSize);
|
const excess = Math.round(100 - totalSize);
|
||||||
items[items.length - 1].size += excess;
|
|
||||||
|
if (excess) {
|
||||||
|
const _index = index !== undefined && !items[index].fixed ? index : items.length - 1;
|
||||||
|
items[_index].size += excess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFixed(index, fixed) {
|
||||||
|
let addExcessToContainer;
|
||||||
|
const remainingItems = containers.value.slice();
|
||||||
|
const container = remainingItems.splice(index, 1)[0];
|
||||||
|
|
||||||
|
if (container.fixed !== fixed) {
|
||||||
|
if (fixed) {
|
||||||
|
const sizeToFill = 100 - container.size;
|
||||||
|
container.size = Math.round((container.size / 100) * getElSize());
|
||||||
|
remainingItems.forEach((item) => {
|
||||||
|
const scale = item.scale ?? 1;
|
||||||
|
item.size = Math.round((item.size * scale * 100) / sizeToFill);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
container.size = Math.round((container.size * 100) / (getElSize() + container.size));
|
||||||
|
addExcessToContainer = index;
|
||||||
|
const remainingSize = 100 - container.size;
|
||||||
|
remainingItems.forEach((item) => {
|
||||||
|
const scale = item.scale ?? 1;
|
||||||
|
item.size = Math.round((item.size * scale * remainingSize) / 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
container.fixed = fixed;
|
||||||
|
sizeItems(containers.value, addExcessToContainer);
|
||||||
|
callback?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeFixedContainer(index, size) {
|
||||||
|
const container = containers.value[index];
|
||||||
|
|
||||||
|
if (container.fixed) {
|
||||||
|
container.size = size;
|
||||||
|
|
||||||
|
callback?.();
|
||||||
|
} else {
|
||||||
|
console.warn('Use view drag resizing to resize flexible containers.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -212,6 +251,8 @@ export function useFlexContainers(
|
|||||||
containers,
|
containers,
|
||||||
startContainerResizing,
|
startContainerResizing,
|
||||||
containerResizing,
|
containerResizing,
|
||||||
endContainerResizing
|
endContainerResizing,
|
||||||
|
toggleFixed,
|
||||||
|
sizeFixedContainer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user