Merged PR 196: Implement Vertical orientation + Upgrade Heroicons to 2.0

Implémenter l'orientation verticale

Modifier l'effet de append

Implementer RigidBody

Implementer Flex et simplex

Implémenter Push

Implémenter Swap

Implement MinMaxHeight without behaviors

Fix Margin for Height

Implement PositionReference

Fix dimension vertical position inside children

Add orientation change in form

Implement sortChildren

Implement Anchor

Fix warning message on overlapping

Fix minimap when root container is vertical

#7287
#7288
#7289
#7290
#7291
#7292
#7294
#7295
#7296
#7297
#7298
#7299
#7300
#7301
#7302
This commit is contained in:
Eric Nguyen 2022-09-28 16:07:56 +00:00
parent 459e83a0c8
commit 18cbacaca1
45 changed files with 2112 additions and 1063 deletions

View file

@ -1,15 +1,13 @@
import * as React from 'react';
import { Interweave, Node } from 'interweave';
import { IContainerModel } from '../../../Interfaces/IContainerModel';
import { DIMENSION_MARGIN, SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS, SHOW_TEXT } from '../../../utils/default';
import { CancelParentTransform, GetDepth, MakeIterator, Pairwise } from '../../../utils/itertools';
import { Dimension } from './Dimension';
import { IContainerProperties } from '../../../Interfaces/IContainerProperties';
import { TransformX } from '../../../utils/svg';
import { Camelize } from '../../../utils/stringtools';
import { SHOW_TEXT } from '../../../utils/default';
interface IContainerProps {
model: IContainerModel
depth: number
scale: number
}
@ -22,6 +20,7 @@ export function Container(props: IContainerProps): JSX.Element {
child => <Container
key={`container-${child.properties.id}`}
model={child}
depth={props.depth + 1}
scale={props.scale}
/>);
@ -57,71 +56,6 @@ export function Container(props: IContainerProps): JSX.Element {
style={style}
>
</rect>);
// Dimension props
const depth = GetDepth(props.model);
const dimensionMargin = DIMENSION_MARGIN * depth / props.scale;
const id = `dim-${props.model.properties.id}`;
const xStart: number = 0;
const xEnd = width;
const yDim = -dimensionMargin;
const strokeWidth = 1;
const text = (width.toFixed(0) ?? 0).toString();
let childrenDimensions: JSX.Element | null = null;
if (props.model.properties.showChildrenDimensions && props.model.children.length > 1 && SHOW_CHILDREN_DIMENSIONS) {
const {
childrenId, xChildrenStart, xChildrenEnd, yChildren, textChildren
} = GetChildrenDimensionProps(props, dimensionMargin);
childrenDimensions = <Dimension
id={childrenId}
xStart={xChildrenStart}
xEnd={xChildrenEnd}
yStart={yChildren}
yEnd={yChildren}
strokeWidth={strokeWidth}
text={textChildren}
scale={props.scale} />;
}
const borrowerDimensions: JSX.Element[] = [];
if (props.model.properties.isDimensionBorrower && SHOW_BORROWER_DIMENSIONS) {
const it = MakeIterator(props.model);
const marks = [];
for (const container of it) {
if (!container.properties.markPositionToDimensionBorrower) {
continue;
}
const x = TransformX(
container.properties.x,
container.properties.width,
container.properties.xPositionReference
);
const [restoredX] = CancelParentTransform(container.parent, x, 0, props.model);
marks.push(
restoredX
);
}
marks.push(0);
marks.push(props.model.properties.width);
marks.sort((a, b) => a - b);
let count = 0;
for (const { cur, next } of Pairwise(marks)) {
const id = `dim-borrow-${props.model.properties.id}-{${count}}`;
borrowerDimensions.push(<Dimension
key={id}
id={id}
xStart={cur}
xEnd={next}
yStart={props.model.properties.height + yDim * -1}
yEnd={props.model.properties.height + yDim * -1}
strokeWidth={strokeWidth}
text={(next - cur).toFixed(0).toString()}
scale={props.scale}
/>);
count++;
}
}
return (
<g
@ -129,19 +63,6 @@ export function Container(props: IContainerProps): JSX.Element {
transform={transform}
key={`container-${props.model.properties.id}`}
>
{(props.model.properties.showSelfDimensions && SHOW_SELF_DIMENSIONS)
? <Dimension
id={id}
xStart={xStart}
xEnd={xEnd}
yStart={yDim}
yEnd={yDim}
strokeWidth={strokeWidth}
text={text}
scale={props.scale} />
: null}
{childrenDimensions}
{borrowerDimensions}
{svg}
{SHOW_TEXT
? <text
@ -160,33 +81,6 @@ export function Container(props: IContainerProps): JSX.Element {
);
}
function GetChildrenDimensionProps(props: IContainerProps, dimensionMargin: number): { childrenId: string, xChildrenStart: number, xChildrenEnd: number, yChildren: number, textChildren: string } {
const childrenId = `dim-children-${props.model.properties.id}`;
const lastChild = props.model.children[props.model.children.length - 1];
let xChildrenStart = TransformX(lastChild.properties.x, lastChild.properties.width, lastChild.properties.xPositionReference);
let xChildrenEnd = TransformX(lastChild.properties.x, lastChild.properties.width, lastChild.properties.xPositionReference);
// Find the min and max
for (let i = props.model.children.length - 2; i >= 0; i--) {
const child = props.model.children[i];
const left = TransformX(child.properties.x, child.properties.width, child.properties.xPositionReference);
if (left < xChildrenStart) {
xChildrenStart = left;
}
const right = TransformX(child.properties.x, child.properties.width, child.properties.xPositionReference);
if (right > xChildrenEnd) {
xChildrenEnd = right;
}
}
const yChildren = props.model.properties.height + dimensionMargin;
const textChildren = (xChildrenEnd - xChildrenStart)
.toFixed(2)
.toString();
return { childrenId, xChildrenStart, xChildrenEnd, yChildren, textChildren };
}
function CreateReactCustomSVG(customSVG: string, props: IContainerProperties): React.ReactNode {
return <Interweave
tagName='g'

View file

@ -3,7 +3,6 @@ import { ContainerModel } from '../../../Interfaces/IContainerModel';
import { DIMENSION_MARGIN } from '../../../utils/default';
import { GetAbsolutePosition, MakeBFSIterator } from '../../../utils/itertools';
import { TransformX } from '../../../utils/svg';
import { Properties } from '../../ContainerProperties/ContainerProperties';
import { Dimension } from './Dimension';
interface IDimensionLayerProps {
@ -28,7 +27,7 @@ function GetDimensionsNodes(root: ContainerModel, scale: number): React.ReactNod
}
const absoluteX = GetAbsolutePosition(container)[0];
const x = TransformX(absoluteX, container.properties.width, container.properties.xPositionReference);
const x = TransformX(absoluteX, container.properties.width, container.properties.positionReference);
lastY = container.properties.y + container.properties.height;
if (x < min) {
min = x;

View file

@ -35,6 +35,7 @@ export function Dimension(props: IDimensionProps): JSX.Element {
/// We need to find the points of the notches
// Get the vector of the line
const [deltaX, deltaY] = [(props.xEnd - props.xStart), (props.yEnd - props.yStart)];
const rotation = (Math.atan2(deltaY, deltaX) / (2 * Math.PI));
// Get the unit vector
const norm = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@ -80,9 +81,9 @@ export function Dimension(props: IDimensionProps): JSX.Element {
style={style} />
<text
x={(props.xStart + props.xEnd) / 2}
y={props.yStart}
y={(props.yStart + props.yEnd) / 2}
style={{
transform: `scale(${1 / scale}) translateX(-50%) translateY(-100%)`,
transform: `rotate(${rotation}turn) scale(${1 / scale}) translateX(-50%) translateY(-100%)`,
transformBox: 'fill-box'
}}
>

View file

@ -1,39 +1,328 @@
import * as React from 'react';
import { ContainerModel } from '../../../Interfaces/IContainerModel';
import { DIMENSION_MARGIN } from '../../../utils/default';
import { GetAbsolutePosition, MakeBFSIterator } from '../../../utils/itertools';
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 {
roots: ContainerModel | ContainerModel[] | null
root: ContainerModel
scale: number
}
function GetDimensionsNodes(root: ContainerModel): React.ReactNode[] {
const it = MakeBFSIterator(root);
const MODULE_STROKE_WIDTH = 1;
function Dimensions({ root, scale }: IDimensionLayerProps): React.ReactNode[] {
const it = MakeRecursionDFSIterator(root, 0, [0, 0]);
const dimensions: React.ReactNode[] = [];
for (const { container, depth } of it) {
const width = container.properties.width;
const id = `dim-${container.properties.id}`;
const xStart = GetAbsolutePosition(container)[0];
const xEnd = xStart + width;
const y = (container.properties.y + container.properties.height) + (DIMENSION_MARGIN * (depth + 1));
const strokeWidth = 1;
const text = width
.toFixed(0)
.toString();
dimensions.push(
<Dimension
key={id}
id={id}
xStart={xStart}
yStart={y}
xEnd={xEnd}
yEnd={y}
strokeWidth={strokeWidth}
text={text} />
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 > 0) {
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(<Dimension
key={childrenId}
id={childrenId}
xStart={xChildrenStart + offset}
xEnd={xChildrenEnd + offset}
yStart={containerBottomDim}
yEnd={containerBottomDim}
strokeWidth={MODULE_STROKE_WIDTH}
text={textChildren}
scale={scale} />);
}
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(<Dimension
key={childrenId}
id={childrenId}
xStart={containerRightDim}
yStart={yChildrenStart + offset}
xEnd={containerRightDim}
yEnd={yChildrenEnd + offset}
strokeWidth={MODULE_STROKE_WIDTH}
text={textChildren}
scale={scale}
/>);
}
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) {
if (!childContainer.properties.markPositionToDimensionBorrower) {
continue;
}
const x = TransformX(
childContainer.properties.x,
childContainer.properties.width,
childContainer.properties.positionReference
);
const restoredX = x + childCurrentTransform[0];
marks.push(
restoredX
);
}
return dimensions;
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(
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) {
if (!childContainer.properties.markPositionToDimensionBorrower) {
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 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(
<Dimension
key={idVert}
id={idVert}
xStart={x}
yStart={yStart}
xEnd={x}
yEnd={yEnd}
strokeWidth={MODULE_STROKE_WIDTH}
text={textVert}
scale={scale} />
);
}
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(
<Dimension
key={id}
id={id}
xStart={xStart}
yStart={y}
xEnd={xEnd}
yEnd={y}
strokeWidth={MODULE_STROKE_WIDTH}
text={text}
scale={scale} />
);
}
/**
@ -42,17 +331,9 @@ function GetDimensionsNodes(root: ContainerModel): React.ReactNode[] {
* @returns
*/
export function DimensionLayer(props: IDimensionLayerProps): JSX.Element {
let dimensions: React.ReactNode[] = [];
if (Array.isArray(props.roots)) {
props.roots.forEach(child => {
dimensions.concat(GetDimensionsNodes(child));
});
} else if (props.roots !== null) {
dimensions = GetDimensionsNodes(props.roots);
}
return (
<g>
{dimensions}
{ Dimensions(props) }
</g>
);
}

View file

@ -9,11 +9,12 @@ import { DepthDimensionLayer } from './Elements/DepthDimensionLayer';
import { MAX_FRAMERATE, SHOW_DIMENSIONS_PER_DEPTH } from '../../utils/default';
import { SymbolLayer } from './Elements/SymbolLayer';
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
import { DimensionLayer } from './Elements/DimensionLayer';
interface ISVGProps {
width: number
height: number
children: ContainerModel | ContainerModel[] | null
children: ContainerModel
selected?: ContainerModel
symbols: Map<string, ISymbolModel>
}
@ -69,7 +70,7 @@ export function SVG(props: ISVGProps): JSX.Element {
// console.log(renderCounter.current / ((Date.now() - startTimer.current) / 1000));
UseSVGAutoResizer(setViewer);
UseFitOnce(svgViewer);
UseFitOnce(svgViewer, props.width, props.height);
const xmlns = '<http://www.w3.org/2000/svg>';
const properties = {
@ -79,20 +80,12 @@ export function SVG(props: ISVGProps): JSX.Element {
};
let children: React.ReactNode | React.ReactNode[] = [];
if (Array.isArray(props.children)) {
children = props.children.map(child =>
<Container
key={`container-${child.properties.id}`}
model={child}
scale={scale}
/>);
} else if (props.children !== null) {
children = <Container
key={`container-${props.children.properties.id}`}
model={props.children}
scale={scale}
/>;
}
children = <Container
key={`container-${props.children.properties.id}`}
model={props.children}
depth={0}
scale={scale}
/>;
return (
<div id={ID} className='ml-16'>
@ -123,7 +116,7 @@ export function SVG(props: ISVGProps): JSX.Element {
miniatureProps={{
position: 'left',
background: '#616264',
width: window.innerWidth - 12 - BAR_WIDTH,
width: 120,
height: 120
}}
>
@ -132,6 +125,7 @@ export function SVG(props: ISVGProps): JSX.Element {
{SHOW_DIMENSIONS_PER_DEPTH
? <DepthDimensionLayer scale={scale} roots={props.children} />
: null}
<DimensionLayer scale={scale} root={props.children} />
<SymbolLayer scale={scale} symbols={props.symbols} />
<Selector scale={scale} selected={props.selected} /> {/* leave this at the end so it can be removed during the svg export */}
</svg>
@ -140,9 +134,8 @@ export function SVG(props: ISVGProps): JSX.Element {
);
}
function UseFitOnce(svgViewer: React.RefObject<ReactSVGPanZoom>): void {
function UseFitOnce(svgViewer: React.RefObject<ReactSVGPanZoom>, width: number, height: number): void {
React.useEffect(() => {
svgViewer?.current?.fitToViewer();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [svgViewer, width, height]);
}