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 Swal from 'sweetalert2';
|
||||||
import { ApplyMargin, TransformX } from '../../../utils/svg';
|
import { ApplyMargin, TransformX } from '../../../utils/svg';
|
||||||
import { PropertyType } from '../../../Enums/PropertyType';
|
import { PropertyType } from '../../../Enums/PropertyType';
|
||||||
|
import { ContainerOrPattern, GetPattern, IPattern } from '../../../Interfaces/IPattern';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select a container
|
* Select a container
|
||||||
|
@ -220,6 +221,33 @@ export function AddContainers(
|
||||||
// Iterate over the containers
|
// Iterate over the containers
|
||||||
availableContainers.forEach((availableContainer, typeIndex) => {
|
availableContainers.forEach((availableContainer, typeIndex) => {
|
||||||
// Get the preset properties from the API
|
// Get the preset properties from the API
|
||||||
|
AddNewContainerToParent(availableContainer, configuration, parentClone, index, typeIndex, newCounters, current.symbols, containerIds);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the state
|
||||||
|
history.push({
|
||||||
|
lastAction: `Add [${containerIds.join(', ')}] in ${parentClone.properties.id}`,
|
||||||
|
mainContainer: clone,
|
||||||
|
selectedContainerId: parentClone.properties.id,
|
||||||
|
typeCounters: newCounters,
|
||||||
|
symbols: structuredClone(current.symbols),
|
||||||
|
selectedSymbolId: current.selectedSymbolId
|
||||||
|
});
|
||||||
|
|
||||||
|
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 type = availableContainer.Type;
|
||||||
|
|
||||||
const defaultConfig = configuration.AvailableContainers
|
const defaultConfig = configuration.AvailableContainers
|
||||||
|
@ -284,31 +312,36 @@ export function AddContainers(
|
||||||
UpdateParentChildrenList(parentClone);
|
UpdateParentChildrenList(parentClone);
|
||||||
|
|
||||||
/// Handle behaviors here ///
|
/// Handle behaviors here ///
|
||||||
|
|
||||||
// Apply the behaviors (flex, rigid, anchor)
|
// Apply the behaviors (flex, rigid, anchor)
|
||||||
ApplyBehaviors(newContainer, current.symbols);
|
ApplyBehaviors(newContainer, symbols);
|
||||||
|
|
||||||
// Then, apply the behaviors on its siblings (mostly for flex)
|
// Then, apply the behaviors on its siblings (mostly for flex)
|
||||||
ApplyBehaviorsOnSiblingsChildren(newContainer, current.symbols);
|
ApplyBehaviorsOnSiblingsChildren(newContainer, symbols);
|
||||||
|
|
||||||
// Initialize default children of the container
|
// Initialize default children of the container
|
||||||
InitializeDefaultChild(configuration, containerConfig, newContainer, newCounters);
|
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
|
// Add to the list of container id for logging purpose
|
||||||
containerIds.push(newContainer.properties.id);
|
containerIds.push(newContainer.properties.id);
|
||||||
});
|
|
||||||
|
|
||||||
// Update the state
|
return newContainer;
|
||||||
history.push({
|
|
||||||
lastAction: `Add [${containerIds.join(', ')}] in ${parentClone.properties.id}`,
|
|
||||||
mainContainer: clone,
|
|
||||||
selectedContainerId: parentClone.properties.id,
|
|
||||||
typeCounters: newCounters,
|
|
||||||
symbols: structuredClone(current.symbols),
|
|
||||||
selectedSymbolId: current.selectedSymbolId
|
|
||||||
});
|
|
||||||
|
|
||||||
return history;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -380,9 +413,9 @@ function UpdateParentChildrenList(parentClone: IContainerModel | null | undefine
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function InitializeDefaultChild(
|
function InitializeDefaultChild(
|
||||||
|
newContainer: ContainerModel,
|
||||||
configuration: IConfiguration,
|
configuration: IConfiguration,
|
||||||
containerConfig: IAvailableContainer,
|
containerConfig: IAvailableContainer,
|
||||||
newContainer: ContainerModel,
|
|
||||||
newCounters: Record<string, number>
|
newCounters: Record<string, number>
|
||||||
): void {
|
): void {
|
||||||
if (containerConfig.DefaultChildType === undefined) {
|
if (containerConfig.DefaultChildType === undefined) {
|
||||||
|
@ -404,6 +437,7 @@ function InitializeDefaultChild(
|
||||||
|
|
||||||
seen.add(currentConfig.Type);
|
seen.add(currentConfig.Type);
|
||||||
|
|
||||||
|
/// TODO: REFACTOR this with AddContainerToParent ///
|
||||||
const left: number = currentConfig.Margin?.left ?? 0;
|
const left: number = currentConfig.Margin?.left ?? 0;
|
||||||
const bottom: number = currentConfig.Margin?.bottom ?? 0;
|
const bottom: number = currentConfig.Margin?.bottom ?? 0;
|
||||||
const top: number = currentConfig.Margin?.top ?? 0;
|
const top: number = currentConfig.Margin?.top ?? 0;
|
||||||
|
@ -440,6 +474,7 @@ function InitializeDefaultChild(
|
||||||
|
|
||||||
// And push it the the parent children
|
// And push it the the parent children
|
||||||
parent.children.push(newChildContainer);
|
parent.children.push(newChildContainer);
|
||||||
|
/// ///
|
||||||
|
|
||||||
// iterate
|
// iterate
|
||||||
depth++;
|
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.)
|
* Returns a new offset by applying an Add method (append, insert etc.)
|
||||||
* See AddMethod
|
* See AddMethod
|
||||||
|
|
|
@ -67,6 +67,8 @@ export interface IAvailableContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (optional)
|
* (optional)
|
||||||
|
* Disabled when Pattern is used.
|
||||||
|
*
|
||||||
* Replace a <rect> by a customized "SVG". It is not really an svg but it at least allows
|
* Replace a <rect> by a customized "SVG". It is not really an svg but it at least allows
|
||||||
* to draw some patterns that can be bind to the properties of the container
|
* to draw some patterns that can be bind to the properties of the container
|
||||||
* Use {prop} to bind a property. Use {{ styleProp }} to use an object.
|
* Use {prop} to bind a property. Use {{ styleProp }} to use an object.
|
||||||
|
@ -81,6 +83,13 @@ export interface IAvailableContainer {
|
||||||
*/
|
*/
|
||||||
DefaultChildType?: string
|
DefaultChildType?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow to use a Pattern to create the list of children
|
||||||
|
* Cannot be used with DefaultChildType,
|
||||||
|
* DefaultChildType will be disabled for this container and the children
|
||||||
|
*/
|
||||||
|
Pattern?: string
|
||||||
|
|
||||||
/** if true, show the dimension of the container */
|
/** if true, show the dimension of the container */
|
||||||
ShowSelfDimensions?: boolean
|
ShowSelfDimensions?: boolean
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { IAvailableContainer } from './IAvailableContainer';
|
import { IAvailableContainer } from './IAvailableContainer';
|
||||||
import { IAvailableSymbol } from './IAvailableSymbol';
|
import { IAvailableSymbol } from './IAvailableSymbol';
|
||||||
|
import { IPattern } from './IPattern';
|
||||||
|
|
||||||
/** Model of configuration for the application to configure it */
|
/** Model of configuration for the application to configure it */
|
||||||
export interface IConfiguration {
|
export interface IConfiguration {
|
||||||
AvailableContainers: IAvailableContainer[] // TODO: Use a Map<string, IAvailableContainer>
|
AvailableContainers: IAvailableContainer[] // TODO: Use a Map<string, IAvailableContainer>
|
||||||
AvailableSymbols: IAvailableSymbol[] // TODO: Use a Map<string, IAvailableContainer>
|
AvailableSymbols: IAvailableSymbol[] // TODO: Use a Map<string, IAvailableContainer>
|
||||||
|
Patterns: IPattern[]
|
||||||
MainContainer: IAvailableContainer
|
MainContainer: IAvailableContainer
|
||||||
}
|
}
|
||||||
|
|
57
src/Interfaces/IPattern.ts
Normal file
57
src/Interfaces/IPattern.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import { IAvailableContainer } from './IAvailableContainer';
|
||||||
|
|
||||||
|
export interface IPattern {
|
||||||
|
/**
|
||||||
|
* Unique id for the pattern
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text to display in the sidebar
|
||||||
|
*/
|
||||||
|
text: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IAvailableContainer id used to wrap the children.
|
||||||
|
*/
|
||||||
|
wrapper: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of ids of Pattern or IAvailableContainer
|
||||||
|
* If a IAvailableContainer and a Pattern have the same id,
|
||||||
|
* IAvailableContainer will be prioritized
|
||||||
|
*/
|
||||||
|
children: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ContainerOrPattern = IAvailableContainer | IPattern;
|
||||||
|
|
||||||
|
export function GetPattern(
|
||||||
|
id: string,
|
||||||
|
configs: Map<string, IAvailableContainer>,
|
||||||
|
patterns: Map<string, IPattern>
|
||||||
|
): ContainerOrPattern | undefined {
|
||||||
|
let containerOrPattern: ContainerOrPattern | undefined = configs.get(id);
|
||||||
|
containerOrPattern = containerOrPattern ?? patterns.get(id);
|
||||||
|
return containerOrPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function IsPattern(
|
||||||
|
id: string,
|
||||||
|
configs: Map<string, IAvailableContainer>,
|
||||||
|
patterns: Map<string, IPattern>
|
||||||
|
): boolean {
|
||||||
|
let containerOrPattern: ContainerOrPattern | undefined = configs.get(id);
|
||||||
|
|
||||||
|
if (containerOrPattern !== undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
containerOrPattern = patterns.get(id);
|
||||||
|
|
||||||
|
if (containerOrPattern === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue