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(
);
}