Add more Position for the dimensions Rename isDimensionBorrower and MarkPosition... Refactor components in ContainerForm with Checkboxes and Selector Add more docs
376 lines
11 KiB
TypeScript
376 lines
11 KiB
TypeScript
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 (
|
|
<g>
|
|
{ Dimensions(props) }
|
|
</g>
|
|
);
|
|
}
|
|
|
|
/// 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(<Dimension
|
|
key={childrenId}
|
|
id={childrenId}
|
|
xStart={xChildrenStart + offset}
|
|
xEnd={xChildrenEnd + offset}
|
|
yStart={yDim}
|
|
yEnd={yDim}
|
|
strokeWidth={MODULE_STROKE_WIDTH}
|
|
text={textChildren}
|
|
scale={scale} />);
|
|
}
|
|
|
|
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(<Dimension
|
|
key={childrenId}
|
|
id={childrenId}
|
|
xStart={xDim}
|
|
yStart={yChildrenStart + offset}
|
|
xEnd={xDim}
|
|
yEnd={yChildrenEnd + offset}
|
|
strokeWidth={MODULE_STROKE_WIDTH}
|
|
text={textChildren}
|
|
scale={scale}
|
|
/>);
|
|
}
|
|
|
|
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(<Dimension
|
|
key={id}
|
|
id={id}
|
|
xStart={cur}
|
|
xEnd={next}
|
|
yStart={yDim}
|
|
yEnd={yDim}
|
|
strokeWidth={MODULE_STROKE_WIDTH}
|
|
text={(next - cur).toFixed(0).toString()}
|
|
scale={scale} />);
|
|
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(<Dimension
|
|
key={id}
|
|
id={id}
|
|
xStart={xDim}
|
|
xEnd={xDim}
|
|
yStart={cur}
|
|
yEnd={next}
|
|
strokeWidth={MODULE_STROKE_WIDTH}
|
|
text={(next - cur).toFixed(0).toString()}
|
|
scale={scale} />);
|
|
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(
|
|
<Dimension
|
|
key={idVert}
|
|
id={idVert}
|
|
xStart={xDim}
|
|
yStart={yStart}
|
|
xEnd={xDim}
|
|
yEnd={yEnd}
|
|
strokeWidth={MODULE_STROKE_WIDTH}
|
|
text={textVert}
|
|
scale={scale} />
|
|
);
|
|
}
|
|
|
|
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(
|
|
<Dimension
|
|
key={id}
|
|
id={id}
|
|
xStart={xStart}
|
|
yStart={yDim}
|
|
xEnd={xEnd}
|
|
yEnd={yDim}
|
|
strokeWidth={MODULE_STROKE_WIDTH}
|
|
text={text}
|
|
scale={scale} />
|
|
);
|
|
}
|