import * as React from 'react'; import { Orientation } from '../../../Enums/Orientation'; import { Position } from '../../../Enums/Position'; import { ContainerModel, IContainerModel } from '../../../Interfaces/IContainerModel'; import { DIMENSION_MARGIN, SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS } from '../../../utils/default'; import { MakeRecursionDFSIterator, Pairwise } from '../../../utils/itertools'; import { TransformX, TransformY } from '../../../utils/svg'; import { Dimension } from './Dimension'; interface IDimensionLayerProps { root: ContainerModel scale: number } const MODULE_STROKE_WIDTH = 1; /** * Fonction that call another function given the positions * @param dimMapped Position mapped depending on the Position enum in order: * [0:left, 1:bottom, 2:up, 3:right] * @param positions List of positions * @param horizontalAction Action called when a left or right position is present * @param verticalAction Action called when a down or up position is present * @param params Params for the actions * (the two actions must have the same number of params, and in the same order) */ function ActionByPosition( dimMapped: number[], positions: Position[], horizontalAction: (dim: number, ...params: any[]) => void, verticalAction: (dim: number, ...params: any[]) => void, params: any[] ): void { positions.forEach((position: Position) => { const dim = dimMapped[position]; switch (position) { case Position.Left: case Position.Right: verticalAction(dim, ...params); break; case Position.Down: case Position.Up: horizontalAction(dim, ...params); break; } }); } /** * Returns a list of dimensions of all containers in root * @param param0 Object with the root container and the scale of the svg * @returns A list of dimensions */ function Dimensions({ root, scale }: IDimensionLayerProps): React.ReactNode[] { const it = MakeRecursionDFSIterator(root, 0, [0, 0]); const dimensions: React.ReactNode[] = []; const topDim = root.properties.y; const leftDim = root.properties.x; const rightDim = root.properties.x + root.properties.width; const bottomDim = root.properties.y + root.properties.height; if (!SHOW_SELF_DIMENSIONS) { return []; } for (const { container, depth, currentTransform } of it) { const containerLeftDim = leftDim - (DIMENSION_MARGIN * (depth + 1)) / scale; const containerTopDim = topDim - (DIMENSION_MARGIN * (depth + 1)) / scale; const containerBottomDim = bottomDim + (DIMENSION_MARGIN * (depth + 1)) / scale; const containerRightDim = rightDim + (DIMENSION_MARGIN * (depth + 1)) / scale; const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; if (SHOW_SELF_DIMENSIONS && container.properties.showSelfDimensions.length > 0) { ActionByPosition( dimMapped, container.properties.showSelfDimensions, AddHorizontalSelfDimension, AddVerticalSelfDimension, [container, currentTransform, dimensions, scale] ); } if (SHOW_BORROWER_DIMENSIONS && container.properties.showDimensionWithMarks.length > 0) { ActionByPosition( dimMapped, container.properties.showDimensionWithMarks, AddHorizontalBorrowerDimension, AddVerticalBorrowerDimension, [container, depth, currentTransform, dimensions, scale] ); } if (SHOW_CHILDREN_DIMENSIONS && container.properties.showChildrenDimensions.length > 0 && container.children.length > 1) { ActionByPosition( dimMapped, container.properties.showChildrenDimensions, AddHorizontalChildrenDimension, AddVerticalChildrenDimension, [container, currentTransform, dimensions, scale] ); } } return dimensions; } /** * A layer containing all dimension * @param props * @returns */ export function DimensionLayer(props: IDimensionLayerProps): JSX.Element { return ( { Dimensions(props) } ); } /// Dimensions Actions /// function AddHorizontalChildrenDimension( yDim: number, container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const childrenId = `dim-children-${container.properties.id}`; const lastChild = container.children[container.children.length - 1]; let xChildrenStart = TransformX(lastChild.properties.x, lastChild.properties.width, lastChild.properties.positionReference); let xChildrenEnd = TransformX(lastChild.properties.x, lastChild.properties.width, lastChild.properties.positionReference); // Find the min and max for (let i = container.children.length - 2; i >= 0; i--) { const child = container.children[i]; const left = TransformX(child.properties.x, child.properties.width, child.properties.positionReference); if (left < xChildrenStart) { xChildrenStart = left; } const right = TransformX(child.properties.x, child.properties.width, child.properties.positionReference); if (right > xChildrenEnd) { xChildrenEnd = right; } } const textChildren = (xChildrenEnd - xChildrenStart) .toFixed(2) .toString(); const offset = currentTransform[0] + container.properties.x; dimensions.push(); } function AddVerticalChildrenDimension( xDim: number, container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const childrenId = `dim-v-children-${container.properties.id}`; const lastChild = container.children[container.children.length - 1]; let yChildrenStart = TransformY(lastChild.properties.y, lastChild.properties.height, lastChild.properties.positionReference); let yChildrenEnd = TransformY(lastChild.properties.y, lastChild.properties.height, lastChild.properties.positionReference); // Find the min and max for (let i = container.children.length - 2; i >= 0; i--) { const child = container.children[i]; const top = TransformY(child.properties.y, child.properties.height, child.properties.positionReference); if (top < yChildrenStart) { yChildrenStart = top; } const bottom = TransformY(child.properties.y, child.properties.height, child.properties.positionReference); if (bottom > yChildrenEnd) { yChildrenEnd = bottom; } } const textChildren = (yChildrenEnd - yChildrenStart) .toFixed(2) .toString(); const offset = currentTransform[0] + container.properties.x; dimensions.push(); } function AddHorizontalBorrowerDimension( yDim: number, container: IContainerModel, depth: number, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const it = MakeRecursionDFSIterator(container, depth, currentTransform); const marks = []; // list of vertical lines for the dimension for (const { container: childContainer, currentTransform: childCurrentTransform } of it) { const isHidden = !childContainer.properties.markPosition.includes(Orientation.Horizontal); if (isHidden) { continue; } const x = TransformX( childContainer.properties.x, childContainer.properties.width, childContainer.properties.positionReference ); const restoredX = x + childCurrentTransform[0]; marks.push( restoredX ); } const restoredX = container.properties.x + currentTransform[0]; marks.push(restoredX); marks.push(restoredX + container.properties.width); marks.sort((a, b) => a - b); let count = 0; for (const { cur, next } of Pairwise(marks)) { const id = `dim-borrow-${container.properties.id}-{${count}}`; dimensions.push(); count++; } } function AddVerticalBorrowerDimension( xDim: number, container: IContainerModel, depth: number, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const it = MakeRecursionDFSIterator(container, depth, currentTransform); const marks = []; // list of vertical lines for the dimension for (const { container: childContainer, currentTransform: childCurrentTransform } of it) { const isHidden = !childContainer.properties.markPosition.includes(Orientation.Vertical); if (isHidden) { continue; } const y = TransformY( childContainer.properties.y, childContainer.properties.height, childContainer.properties.positionReference ); const restoredy = y + childCurrentTransform[1]; marks.push( restoredy ); } const restoredY = container.properties.y + currentTransform[1]; marks.push(restoredY); marks.push(restoredY + container.properties.height); marks.sort((a, b) => a - b); let count = 0; for (const { cur, next } of Pairwise(marks)) { const id = `dim-v-borrow-${container.properties.id}-{${count}}`; dimensions.push(); count++; } } function AddVerticalSelfDimension( xDim: number, container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const height = container.properties.height; const idVert = `dim-v-${container.properties.id}`; const yStart = container.properties.y + currentTransform[1]; const yEnd = yStart + height; const textVert = height .toFixed(0) .toString(); dimensions.push( ); } function AddHorizontalSelfDimension( yDim: number, container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const width = container.properties.width; const id = `dim-${container.properties.id}`; const xStart = container.properties.x + currentTransform[0]; const xEnd = xStart + width; const text = width .toFixed(0) .toString(); dimensions.push( ); }