import { IContainerModel } from '../../../Interfaces/IContainerModel'; import { Simplex } from '../../../utils/simplex'; import { ApplyWidthMargin, ApplyXMargin } from '../../../utils/svg'; interface IFlexibleGroup { group: IContainerModel[] offset: number size: number } /** * Flex the container and its siblings (mutate) * @param container Container to flex * @returns Flexed container */ export function Flex(container: IContainerModel): void { if (container.parent === null || container.parent === undefined) { return; } const flexibleGroups = GetFlexibleGroups(container.parent); for (const flexibleGroup of flexibleGroups) { FlexGroup(flexibleGroup); } } function FlexGroup(flexibleGroup: IFlexibleGroup): void { const children = flexibleGroup.group; const flexibleContainers = children .filter(sibling => sibling.properties.isFlex); const minWidths = flexibleContainers .map(sibling => sibling.properties.minWidth); const fixedWidth = children .filter(sibling => !sibling.properties.isFlex) .map(sibling => sibling.properties.width) .reduce((partialSum, a) => partialSum + a, 0); const requiredMaxWidth = flexibleGroup.size - fixedWidth; const minimumPossibleWidth = minWidths.reduce((partialSum, a) => partialSum + a, 0); if (minimumPossibleWidth > requiredMaxWidth) { // Swal.fire({ // icon: 'error', // title: 'Cannot fit!', // text: 'Cannot fit at all even when squeezing all flex containers to the minimum.' // }); console.error('[FlexBehavior] Cannot fit at all even when squeezing all flex containers to the minimum.'); return; } const maxMinWidths = Math.max(...minWidths); if (maxMinWidths * minWidths.length < requiredMaxWidth) { const wantedWidth = requiredMaxWidth / minWidths.length; // it fits, flex with maxMinWidths and fixed width let right = flexibleGroup.offset; for (const sibling of children) { if (!sibling.properties.isFlex) { sibling.properties.x = right; right += sibling.properties.width; continue; } sibling.properties.x = ApplyXMargin(right, sibling.properties.margin.left); sibling.properties.width = ApplyWidthMargin(wantedWidth, sibling.properties.margin.left, sibling.properties.margin.right); right += wantedWidth; } return; } // does not fit /// SIMPLEX /// const solutions: number[] = Simplex(minWidths, requiredMaxWidth); // apply the solutions for (let i = 0; i < flexibleContainers.length; i++) { flexibleContainers[i].properties.width = ApplyWidthMargin(solutions[i], flexibleContainers[i].properties.margin.left, flexibleContainers[i].properties.margin.right); } // move the containers let right = flexibleGroup.offset; for (const sibling of children) { sibling.properties.x = ApplyXMargin(right, sibling.properties.margin.left); right += sibling.properties.width; } } export function GetFlexibleGroups(parent: IContainerModel): IFlexibleGroup[] { const flexibleGroups: IFlexibleGroup[] = []; let group: IContainerModel[] = []; let offset = 0; let size = 0; for (const child of parent.children) { if (child.properties.isAnchor) { size = child.properties.x - offset; const flexibleGroup: IFlexibleGroup = { group, offset, size }; flexibleGroups.push(flexibleGroup); offset = child.properties.x + child.properties.width; group = []; continue; } group.push(child); } size = parent.properties.width - offset; const flexibleGroup: IFlexibleGroup = { group, offset, size }; flexibleGroups.push(flexibleGroup); return flexibleGroups; }