Implement Pattern
This commit is contained in:
parent
c0a7a26874
commit
f6e4238b3d
4 changed files with 290 additions and 77 deletions
|
@ -11,6 +11,7 @@ import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
|||
import Swal from 'sweetalert2';
|
||||
import { ApplyMargin, TransformX } from '../../../utils/svg';
|
||||
import { PropertyType } from '../../../Enums/PropertyType';
|
||||
import { ContainerOrPattern, GetPattern, IPattern } from '../../../Interfaces/IPattern';
|
||||
|
||||
/**
|
||||
* Select a container
|
||||
|
@ -220,82 +221,7 @@ export function AddContainers(
|
|||
// Iterate over the containers
|
||||
availableContainers.forEach((availableContainer, typeIndex) => {
|
||||
// Get the preset properties from the API
|
||||
const type = availableContainer.Type;
|
||||
|
||||
const defaultConfig = configuration.AvailableContainers
|
||||
.find(option => option.Type === type);
|
||||
|
||||
if (defaultConfig === undefined) {
|
||||
throw new Error(`[AddContainer] Object type not found among default config. Found: ${type}`);
|
||||
}
|
||||
|
||||
const containerConfig = Object.assign(defaultConfig, availableContainer);
|
||||
|
||||
// Default margin
|
||||
const left: number = containerConfig.Margin?.left ?? 0;
|
||||
const bottom: number = containerConfig.Margin?.bottom ?? 0;
|
||||
const top: number = containerConfig.Margin?.top ?? 0;
|
||||
const right: number = containerConfig.Margin?.right ?? 0;
|
||||
|
||||
// Default coordinates
|
||||
let x = containerConfig.X ?? 0;
|
||||
let y = containerConfig.Y ?? 0;
|
||||
let width = containerConfig.Width ?? containerConfig.MaxWidth ?? containerConfig.MinWidth ?? parentClone.properties.width;
|
||||
let height = containerConfig.Height ?? parentClone.properties.height;
|
||||
|
||||
({ x, y, width, height } = ApplyMargin(x, y, width, height, left, bottom, top, right));
|
||||
|
||||
// Apply an add method (append or insert/replace)
|
||||
x = ApplyAddMethod(index + typeIndex, containerConfig, parentClone, x);
|
||||
|
||||
// Set the counter of the object type in order to assign an unique id
|
||||
UpdateCounters(newCounters, type);
|
||||
const count = newCounters[type];
|
||||
|
||||
const defaultProperties = GetDefaultContainerProps(
|
||||
type,
|
||||
count,
|
||||
parentClone,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
containerConfig
|
||||
);
|
||||
|
||||
// Create the container
|
||||
const newContainer = new ContainerModel(
|
||||
parentClone,
|
||||
defaultProperties,
|
||||
[],
|
||||
{
|
||||
type
|
||||
}
|
||||
);
|
||||
|
||||
// Add it to the parent
|
||||
if (index === parentClone.children.length) {
|
||||
parentClone.children.push(newContainer);
|
||||
} else {
|
||||
parentClone.children.splice(index, 0, newContainer);
|
||||
}
|
||||
|
||||
// Sort the parent children by x
|
||||
UpdateParentChildrenList(parentClone);
|
||||
|
||||
/// Handle behaviors here ///
|
||||
|
||||
// Apply the behaviors (flex, rigid, anchor)
|
||||
ApplyBehaviors(newContainer, current.symbols);
|
||||
|
||||
// Then, apply the behaviors on its siblings (mostly for flex)
|
||||
ApplyBehaviorsOnSiblingsChildren(newContainer, current.symbols);
|
||||
|
||||
// Initialize default children of the container
|
||||
InitializeDefaultChild(configuration, containerConfig, newContainer, newCounters);
|
||||
|
||||
// Add to the list of container id for logging purpose
|
||||
containerIds.push(newContainer.properties.id);
|
||||
AddNewContainerToParent(availableContainer, configuration, parentClone, index, typeIndex, newCounters, current.symbols, containerIds);
|
||||
});
|
||||
|
||||
// Update the state
|
||||
|
@ -311,6 +237,113 @@ export function AddContainers(
|
|||
return history;
|
||||
}
|
||||
|
||||
function AddNewContainerToParent(
|
||||
availableContainer: IAvailableContainer,
|
||||
configuration: IConfiguration,
|
||||
parentClone: IContainerModel,
|
||||
index: number,
|
||||
typeIndex: number,
|
||||
newCounters: Record<string, number>,
|
||||
symbols: Map<string, ISymbolModel>,
|
||||
containerIds: string[],
|
||||
initChilds: boolean = true
|
||||
): ContainerModel {
|
||||
const type = availableContainer.Type;
|
||||
|
||||
const defaultConfig = configuration.AvailableContainers
|
||||
.find(option => option.Type === type);
|
||||
|
||||
if (defaultConfig === undefined) {
|
||||
throw new Error(`[AddContainer] Object type not found among default config. Found: ${type}`);
|
||||
}
|
||||
|
||||
const containerConfig = Object.assign(defaultConfig, availableContainer);
|
||||
|
||||
// Default margin
|
||||
const left: number = containerConfig.Margin?.left ?? 0;
|
||||
const bottom: number = containerConfig.Margin?.bottom ?? 0;
|
||||
const top: number = containerConfig.Margin?.top ?? 0;
|
||||
const right: number = containerConfig.Margin?.right ?? 0;
|
||||
|
||||
// Default coordinates
|
||||
let x = containerConfig.X ?? 0;
|
||||
let y = containerConfig.Y ?? 0;
|
||||
let width = containerConfig.Width ?? containerConfig.MaxWidth ?? containerConfig.MinWidth ?? parentClone.properties.width;
|
||||
let height = containerConfig.Height ?? parentClone.properties.height;
|
||||
|
||||
({ x, y, width, height } = ApplyMargin(x, y, width, height, left, bottom, top, right));
|
||||
|
||||
// Apply an add method (append or insert/replace)
|
||||
x = ApplyAddMethod(index + typeIndex, containerConfig, parentClone, x);
|
||||
|
||||
// Set the counter of the object type in order to assign an unique id
|
||||
UpdateCounters(newCounters, type);
|
||||
const count = newCounters[type];
|
||||
|
||||
const defaultProperties = GetDefaultContainerProps(
|
||||
type,
|
||||
count,
|
||||
parentClone,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
containerConfig
|
||||
);
|
||||
|
||||
// Create the container
|
||||
const newContainer = new ContainerModel(
|
||||
parentClone,
|
||||
defaultProperties,
|
||||
[],
|
||||
{
|
||||
type
|
||||
}
|
||||
);
|
||||
|
||||
// Add it to the parent
|
||||
if (index === parentClone.children.length) {
|
||||
parentClone.children.push(newContainer);
|
||||
} else {
|
||||
parentClone.children.splice(index, 0, newContainer);
|
||||
}
|
||||
|
||||
// Sort the parent children by x
|
||||
UpdateParentChildrenList(parentClone);
|
||||
|
||||
/// Handle behaviors here ///
|
||||
// Apply the behaviors (flex, rigid, anchor)
|
||||
ApplyBehaviors(newContainer, symbols);
|
||||
|
||||
// Then, apply the behaviors on its siblings (mostly for flex)
|
||||
ApplyBehaviorsOnSiblingsChildren(newContainer, symbols);
|
||||
|
||||
// Initialize default children of the container
|
||||
if (initChilds) {
|
||||
if (containerConfig.DefaultChildType !== undefined) {
|
||||
InitializeDefaultChild(
|
||||
newContainer,
|
||||
configuration,
|
||||
containerConfig,
|
||||
newCounters
|
||||
);
|
||||
} else {
|
||||
InitializeChildrenWithPattern(
|
||||
newContainer,
|
||||
configuration,
|
||||
containerConfig,
|
||||
newCounters,
|
||||
symbols
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to the list of container id for logging purpose
|
||||
containerIds.push(newContainer.properties.id);
|
||||
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add a new container at `index` in children of parent of `parentId`
|
||||
* @param index Index where to insert to the new container
|
||||
|
@ -380,9 +413,9 @@ function UpdateParentChildrenList(parentClone: IContainerModel | null | undefine
|
|||
* @returns
|
||||
*/
|
||||
function InitializeDefaultChild(
|
||||
newContainer: ContainerModel,
|
||||
configuration: IConfiguration,
|
||||
containerConfig: IAvailableContainer,
|
||||
newContainer: ContainerModel,
|
||||
newCounters: Record<string, number>
|
||||
): void {
|
||||
if (containerConfig.DefaultChildType === undefined) {
|
||||
|
@ -404,6 +437,7 @@ function InitializeDefaultChild(
|
|||
|
||||
seen.add(currentConfig.Type);
|
||||
|
||||
/// TODO: REFACTOR this with AddContainerToParent ///
|
||||
const left: number = currentConfig.Margin?.left ?? 0;
|
||||
const bottom: number = currentConfig.Margin?.bottom ?? 0;
|
||||
const top: number = currentConfig.Margin?.top ?? 0;
|
||||
|
@ -440,6 +474,7 @@ function InitializeDefaultChild(
|
|||
|
||||
// And push it the the parent children
|
||||
parent.children.push(newChildContainer);
|
||||
/// ///
|
||||
|
||||
// iterate
|
||||
depth++;
|
||||
|
@ -449,6 +484,116 @@ function InitializeDefaultChild(
|
|||
}
|
||||
}
|
||||
|
||||
function InitializeChildrenWithPattern(
|
||||
newContainer: ContainerModel,
|
||||
configuration: IConfiguration,
|
||||
containerConfig: IAvailableContainer,
|
||||
newCounters: Record<string, number>,
|
||||
symbols: Map<string, ISymbolModel>
|
||||
): void {
|
||||
const patternId = containerConfig.Pattern;
|
||||
|
||||
if (patternId === undefined || patternId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const configs: Map<string, IAvailableContainer> = new Map(configuration.AvailableContainers.map(config => [config.Type, config]));
|
||||
const patterns: Map<string, IPattern> = new Map(configuration.Patterns.map(pattern => [pattern.id, pattern]));
|
||||
const containerOrPattern = GetPattern(patternId, configs, patterns);
|
||||
const pattern = containerOrPattern as IPattern;
|
||||
|
||||
// Will store the ids of the iterated IAvailableContainer types
|
||||
const debugContainerArr: string[] = [];
|
||||
|
||||
if (pattern.children === undefined) {
|
||||
const container = containerOrPattern as IAvailableContainer;
|
||||
// Add Container
|
||||
AddNewContainerToParent(
|
||||
container,
|
||||
configuration,
|
||||
newContainer,
|
||||
0, 0,
|
||||
newCounters,
|
||||
symbols,
|
||||
debugContainerArr
|
||||
);
|
||||
}
|
||||
|
||||
// BFS over patterns
|
||||
const rootNode: Node = {
|
||||
containerOrPattern: pattern,
|
||||
parent: newContainer
|
||||
};
|
||||
|
||||
const queue: Node[] = [rootNode];
|
||||
while (queue.length > 0) {
|
||||
let levelSize = queue.length;
|
||||
while (levelSize-- !== 0) {
|
||||
const node = queue.shift() as Node;
|
||||
|
||||
const pattern = node.containerOrPattern as IPattern;
|
||||
|
||||
if (pattern.children === undefined) {
|
||||
// Add Container
|
||||
const containerConfig = node.containerOrPattern as IAvailableContainer;
|
||||
AddNewContainerToParent(
|
||||
containerConfig,
|
||||
configuration,
|
||||
node.parent,
|
||||
0, 0,
|
||||
newCounters,
|
||||
symbols,
|
||||
debugContainerArr
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let parent = node.parent;
|
||||
if (pattern.wrapper !== undefined) {
|
||||
// Add Container
|
||||
const container = configs.get(pattern.wrapper);
|
||||
if (container === undefined) {
|
||||
console.warn(`[InitializeChildrenFromPattern] IAvailableContainer from pattern was not found in the configuration: ${pattern.wrapper}.
|
||||
Process will ignore the container.`);
|
||||
} else {
|
||||
parent = AddNewContainerToParent(
|
||||
container,
|
||||
configuration,
|
||||
parent,
|
||||
0, 0,
|
||||
newCounters,
|
||||
symbols,
|
||||
debugContainerArr,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = pattern.children.length - 1; i >= 0; i--) {
|
||||
const childId: string = pattern.children[i];
|
||||
|
||||
const child = GetPattern(childId, configs, patterns);
|
||||
|
||||
if (child === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const nextNode: Node = {
|
||||
containerOrPattern: child,
|
||||
parent
|
||||
};
|
||||
|
||||
queue.push(nextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Node {
|
||||
containerOrPattern: ContainerOrPattern
|
||||
parent: IContainerModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new offset by applying an Add method (append, insert etc.)
|
||||
* See AddMethod
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue