import * as React from 'react'; import { Orientation } from '../../../Enums/Orientation'; 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; 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; if (SHOW_SELF_DIMENSIONS && container.properties.showSelfDimensions) { AddSelfDimension(container, currentTransform, containerTopDim, containerLeftDim, scale, dimensions); } if (SHOW_BORROWER_DIMENSIONS && container.properties.isDimensionBorrower) { AddBorrowerDimension(containerBottomDim, containerRightDim, depth, scale, container, currentTransform, dimensions); } if (SHOW_CHILDREN_DIMENSIONS && container.properties.showChildrenDimensions && container.children.length > 1) { AddChildrenDimension(container, currentTransform, dimensions, containerBottomDim, containerRightDim, scale); } } return dimensions; } function AddChildrenDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], containerBottomDim: number, containerRightDim: number, scale: number ): void { AddHorizontalChildrenDimension(container, currentTransform, dimensions, containerBottomDim, scale); AddVerticalChildrenDimension(container, currentTransform, dimensions, containerRightDim, scale); } function AddHorizontalChildrenDimension( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], containerBottomDim: number, 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( container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[], containerRightDim: number, 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 AddBorrowerDimension( bottomDim: number, rightDim: number, depth: number, scale: number, container: IContainerModel, currentTransform: [number, number], dimensions: React.ReactNode[] ): void { AddHorizontalBorrowerDimension(bottomDim, container, depth, currentTransform, dimensions, scale); AddVerticalBorrowerDimension(rightDim, container, depth, currentTransform, dimensions, scale); } function AddHorizontalBorrowerDimension( bottomDim: number, container: IContainerModel, depth: number, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const yDim = bottomDim; 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.markPositionToDimensionBorrower.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( rightDim: number, container: IContainerModel, depth: number, currentTransform: [number, number], dimensions: React.ReactNode[], scale: number ): void { const xDim = rightDim; 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.markPositionToDimensionBorrower.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 AddSelfDimension( container: IContainerModel, currentTransform: [number, number], topDim: number, leftDim: number, scale: number, dimensions: React.ReactNode[] ): void { AddHorizontalSelfDimension(container, currentTransform, topDim, dimensions, scale); AddVerticalSelfDimension(container, currentTransform, leftDim, dimensions, scale); } function AddVerticalSelfDimension(container: IContainerModel, currentTransform: [number, number], leftDim: 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 x = leftDim; const textVert = height .toFixed(0) .toString(); dimensions.push( ); } function AddHorizontalSelfDimension( container: IContainerModel, currentTransform: [number, number], topDim: 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 y = topDim; const text = width .toFixed(0) .toString(); dimensions.push( ); } /** * A layer containing all dimension * @param props * @returns */ export function DimensionLayer(props: IDimensionLayerProps): JSX.Element { return ( { Dimensions(props) } ); }