Merged PR 212: Optimize FindChildrenById from O(n) to O(1)

Optimize FindChildrenById from O(n) to O(1):
- Deprecate FindContainerByIdDFS
- Container: Replace Children to string[]
- Add HashMap to IHistoryState that contains all containers

To access a container by id now cost O(1) without any additional cost

+ Implement CICD for SVGLibs
This commit is contained in:
Eric Nguyen 2022-10-12 09:39:54 +00:00
parent 466ef2b08b
commit c256a76e01
45 changed files with 775 additions and 450 deletions

View file

@ -4,8 +4,10 @@ import { IContainerModel } from '../../../Interfaces/IContainerModel';
import { IContainerProperties } from '../../../Interfaces/IContainerProperties';
import { Camelize } from '../../../utils/stringtools';
import { SHOW_TEXT } from '../../../utils/default';
import { FindContainerById } from '../../../utils/itertools';
interface IContainerProps {
containers: Map<string, IContainerModel>
model: IContainerModel
depth: number
scale: number
@ -18,13 +20,22 @@ interface IContainerProps {
*/
export function Container(props: IContainerProps): JSX.Element {
const containersElements = props.model.children.map(
child => <Container
key={`container-${child.properties.id}`}
model={child}
depth={props.depth + 1}
scale={props.scale}
selectContainer={props.selectContainer}
/>);
childId => {
const child = FindContainerById(props.containers, childId);
if (child === undefined) {
return <></>;
}
return <Container
key={`container-${child.properties.id}`}
containers={props.containers}
model={child}
depth={props.depth + 1}
scale={props.scale}
selectContainer={props.selectContainer}
/>;
});
const width: number = props.model.properties.width;
const height: number = props.model.properties.height;

View file

@ -1,17 +1,22 @@
import * as React from 'react';
import { ContainerModel } from '../../../Interfaces/IContainerModel';
import { ContainerModel, IContainerModel } from '../../../Interfaces/IContainerModel';
import { DIMENSION_MARGIN } from '../../../utils/default';
import { GetAbsolutePosition, MakeBFSIterator } from '../../../utils/itertools';
import { TransformX } from '../../../utils/svg';
import { Dimension } from './Dimension';
interface IDimensionLayerProps {
containers: Map<string, IContainerModel>
roots: ContainerModel | ContainerModel[] | null
scale?: number
}
function GetDimensionsNodes(root: ContainerModel, scale: number): React.ReactNode[] {
const it = MakeBFSIterator(root);
function GetDimensionsNodes(
containers: Map<string, IContainerModel>,
root: ContainerModel,
scale: number
): React.ReactNode[] {
const it = MakeBFSIterator(root, containers);
const dimensions: React.ReactNode[] = [];
let currentDepth = 0;
let min = Infinity;
@ -53,10 +58,10 @@ export function DepthDimensionLayer(props: IDimensionLayerProps): JSX.Element {
const scale = props.scale ?? 1;
if (Array.isArray(props.roots)) {
props.roots.forEach(child => {
dimensions.concat(GetDimensionsNodes(child, scale));
dimensions.concat(GetDimensionsNodes(props.containers, child, scale));
});
} else if (props.roots !== null) {
dimensions = GetDimensionsNodes(props.roots, scale);
dimensions = GetDimensionsNodes(props.containers, props.roots, scale);
}
return (
<g>

View file

@ -3,11 +3,12 @@ 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 { FindContainerById, MakeRecursionDFSIterator, Pairwise } from '../../../utils/itertools';
import { TransformX, TransformY } from '../../../utils/svg';
import { Dimension } from './Dimension';
interface IDimensionLayerProps {
containers: Map<string, IContainerModel>
root: ContainerModel
scale: number
}
@ -51,8 +52,8 @@ function ActionByPosition(
* @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]);
function Dimensions({ containers, root, scale }: IDimensionLayerProps): React.ReactNode[] {
const it = MakeRecursionDFSIterator(root, containers, 0, [0, 0]);
const dimensions: React.ReactNode[] = [];
const topDim = root.properties.y;
const leftDim = root.properties.x;
@ -75,7 +76,8 @@ function Dimensions({ root, scale }: IDimensionLayerProps): React.ReactNode[] {
container.properties.showSelfDimensions,
AddHorizontalSelfDimension,
AddVerticalSelfDimension,
[container,
[
container,
currentTransform,
dimensions,
scale]
@ -88,7 +90,9 @@ function Dimensions({ root, scale }: IDimensionLayerProps): React.ReactNode[] {
container.properties.showDimensionWithMarks,
AddHorizontalBorrowerDimension,
AddVerticalBorrowerDimension,
[container,
[
containers,
container,
depth,
currentTransform,
dimensions,
@ -102,7 +106,9 @@ function Dimensions({ root, scale }: IDimensionLayerProps): React.ReactNode[] {
container.properties.showChildrenDimensions,
AddHorizontalChildrenDimension,
AddVerticalChildrenDimension,
[container,
[
containers,
container,
currentTransform,
dimensions,
scale]
@ -130,6 +136,7 @@ export function DimensionLayer(props: IDimensionLayerProps): JSX.Element {
function AddHorizontalChildrenDimension(
yDim: number,
containers: Map<string, IContainerModel>,
container: IContainerModel,
currentTransform: [number, number],
dimensions: React.ReactNode[],
@ -137,13 +144,25 @@ function AddHorizontalChildrenDimension(
): void {
const childrenId = `dim-y${yDim.toFixed(0)}-children-${container.properties.id}`;
const lastChild = container.children[container.children.length - 1];
const lastChildId = container.children[container.children.length - 1];
const lastChild = FindContainerById(containers, lastChildId);
if (lastChild === undefined) {
return;
}
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 childId = container.children[i];
const child = FindContainerById(containers, childId);
if (child === undefined) {
continue;
}
const left = TransformX(child.properties.x, child.properties.width, child.properties.positionReference);
if (left < xChildrenStart) {
xChildrenStart = left;
@ -178,6 +197,7 @@ function AddHorizontalChildrenDimension(
function AddVerticalChildrenDimension(
xDim: number,
containers: Map<string, IContainerModel>,
container: IContainerModel,
currentTransform: [number, number],
dimensions: React.ReactNode[],
@ -185,13 +205,25 @@ function AddVerticalChildrenDimension(
): void {
const childrenId = `dim-x${xDim.toFixed(0)}-children-${container.properties.id}`;
const lastChild = container.children[container.children.length - 1];
const lastChildId = container.children[container.children.length - 1];
const lastChild = FindContainerById(containers, lastChildId);
if (lastChild === undefined) {
return;
}
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 childId = container.children[i];
const child = FindContainerById(containers, childId);
if (child === undefined) {
continue;
}
const top = TransformY(child.properties.y, child.properties.height, child.properties.positionReference);
if (top < yChildrenStart) {
yChildrenStart = top;
@ -227,13 +259,14 @@ function AddVerticalChildrenDimension(
function AddHorizontalBorrowerDimension(
yDim: number,
containers: Map<string, IContainerModel>,
container: IContainerModel,
depth: number,
currentTransform: [number, number],
dimensions: React.ReactNode[],
scale: number
): void {
const it = MakeRecursionDFSIterator(container, depth, currentTransform);
const it = MakeRecursionDFSIterator(container, containers, depth, currentTransform);
const marks = []; // list of vertical lines for the dimension
for (const {
container: childContainer, currentTransform: childCurrentTransform
@ -279,13 +312,14 @@ function AddHorizontalBorrowerDimension(
function AddVerticalBorrowerDimension(
xDim: number,
containers: Map<string, IContainerModel>,
container: IContainerModel,
depth: number,
currentTransform: [number, number],
dimensions: React.ReactNode[],
scale: number
): void {
const it = MakeRecursionDFSIterator(container, depth, currentTransform);
const it = MakeRecursionDFSIterator(container, containers, depth, currentTransform);
const marks = []; // list of vertical lines for the dimension
for (const {
container: childContainer, currentTransform: childCurrentTransform

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import { ReactSVGPanZoom, Tool, TOOL_PAN, Value } from 'react-svg-pan-zoom';
import { Container } from './Elements/Container';
import { ContainerModel } from '../../Interfaces/IContainerModel';
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
import { Selector } from './Elements/Selector/Selector';
import { DepthDimensionLayer } from './Elements/DepthDimensionLayer';
import { MAX_FRAMERATE, SHOW_DIMENSIONS_PER_DEPTH } from '../../utils/default';
@ -15,17 +15,13 @@ interface ISVGProps {
viewerHeight: number
width: number
height: number
containers: Map<string, IContainerModel>
children: ContainerModel
selected?: ContainerModel
symbols: Map<string, ISymbolModel>
selectContainer: (containerId: string) => void
}
interface Viewer {
viewerWidth: number
viewerHeight: number
}
export const ID = 'svg';
export function SVG(props: ISVGProps): JSX.Element {
@ -55,6 +51,7 @@ export function SVG(props: ISVGProps): JSX.Element {
let children: React.ReactNode | React.ReactNode[] = [];
children = <Container
key={`container-${props.children.properties.id}`}
containers={props.containers}
model={props.children}
depth={0}
scale={scale}
@ -97,9 +94,9 @@ export function SVG(props: ISVGProps): JSX.Element {
<svg {...properties}>
{children}
{SHOW_DIMENSIONS_PER_DEPTH
? <DepthDimensionLayer scale={scale} roots={props.children} />
? <DepthDimensionLayer containers={props.containers} scale={scale} roots={props.children} />
: null}
<DimensionLayer scale={scale} root={props.children} />
<DimensionLayer containers={props.containers} 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>