svg-layout-designer-react/src/utils/default.ts
2023-07-10 13:29:24 +00:00

332 lines
10 KiB
TypeScript

import { PositionReference } from '../Enums/PositionReference';
import { type IAvailableContainer } from '../Interfaces/IAvailableContainer';
import { type IAvailableSymbol } from '../Interfaces/IAvailableSymbol';
import { type IConfiguration } from '../Interfaces/IConfiguration';
import { ContainerModel, type IContainerModel } from '../Interfaces/IContainerModel';
import { type IContainerProperties } from '../Interfaces/IContainerProperties';
import { type IEditorState } from '../Interfaces/IEditorState';
import { type ISymbolModel } from '../Interfaces/ISymbolModel';
import { Orientation } from '../Enums/Orientation';
import { AppState } from '../Enums/AppState';
import { type IDimensionOptions } from '../Interfaces/IDimensionOptions';
import { type IDimensionStyle } from '../Interfaces/IDimensionStyle';
/// EDITOR DEFAULTS ///
/** Enable fast boot and disable main menu (0 = disabled, 1 = loading, 2 = loaded) */
export const FAST_BOOT = import.meta.env.PROD
? AppState.Loaded
: AppState.MainMenu;
/** Disable any call to the API (default = false) */
export const DISABLE_API = false;
export const DEFAULT_LANGUAGE = 'fr';
/**
* Replace the SVG viewer by a canvas
* Better compatibility with Gecko and WebKit engines like Firefox and Safari.
* EXPERIMENTAL: svg export wont work and it won't be possible to insert a custom svg)
*/
export const USE_EXPERIMENTAL_CANVAS_API = false;
/** Enable keyboard shortcuts (default = true) */
export const ENABLE_SHORTCUTS = true;
/** Size of the history (recommanded = 200) */
export const MAX_HISTORY = 200;
/** Apply beheviors on children (recommanded = true) */
export const APPLY_BEHAVIORS_ON_CHILDREN = true;
/** Framerate of the svg controller (recommanded = 60) */
export const MAX_FRAMERATE = 120;
/// CONTAINER DEFAULTS ///
/** Enable the swap behavior (kinda broken recommanded = false) */
export const ENABLE_SWAP = false;
/** Enable the rigid behavior (recommanded = true) */
export const ENABLE_RIGID = true;
/**
* Enable the hard rigid behavior
* disallowing the container to overlap (ENABLE_RIGID must be true)
* (recommanded = false)
*/
export const ENABLE_HARD_RIGID = false;
/** Enalbe the text in the containers */
export const SHOW_TEXT = false;
export const SHOW_SELECTOR_TEXT = true;
export const DEFAULTCHILDTYPE_ALLOW_CYCLIC = false;
export const DEFAULTCHILDTYPE_MAX_DEPTH = 10;
/// DIMENSIONS DEFAULTS ///
export const SHOW_SELF_DIMENSIONS = true;
export const SHOW_SELF_MARGINS_DIMENSIONS = true;
export const SHOW_CHILDREN_DIMENSIONS = true;
export const SHOW_BORROWER_DIMENSIONS = true;
export const DIMENSION_MARGIN = 70;
export const SYMBOL_DIMENSION_MARGIN = 30;
export const SYMBOL_MARGIN = 25;
export const NOTCHES_LENGTH = 10;
export const DEFAULT_DIMENSION_SYMBOL_STYLE: IDimensionStyle = {
color: '#000000'
};
/// SYMBOL DEFAULTS ///
export const DEFAULT_SYMBOL_WIDTH = 32;
export const DEFAULT_SYMBOL_IS_VERTICAL = false;
export const DEFAULT_SYMBOL_HEIGHT = 32;
/**
* Returns the default editor state given the configuration
*/
export function GetDefaultEditorState(configuration: IConfiguration): IEditorState {
if (configuration.MainContainer.Width === undefined ||
configuration.MainContainer.Height === undefined) {
throw new Error('Cannot initialize project! Main container has an undefined size');
}
const containerConfig = configuration.AvailableContainers.find(
config => config.Type === configuration.MainContainer.Type
);
let mainContainerConfig: IContainerProperties;
if (containerConfig !== undefined) {
const clone = structuredClone(containerConfig);
const extendedContainerConfig = Object.assign(clone, configuration.MainContainer);
if (containerConfig.Style !== undefined) {
const styleClone = structuredClone(containerConfig.Style);
extendedContainerConfig.Style = Object.assign(styleClone, configuration.MainContainer.Style);
}
if (extendedContainerConfig.Width === undefined ||
extendedContainerConfig.Height === undefined) {
throw new Error('Cannot initialize project! Main container has an undefined size');
}
mainContainerConfig = GetDefaultContainerProps(
extendedContainerConfig.Type,
0,
null,
0,
0,
extendedContainerConfig.Width,
extendedContainerConfig.Height,
extendedContainerConfig
);
} else {
mainContainerConfig = GetDefaultContainerProps(
configuration.MainContainer.Type,
0,
null,
0,
0,
configuration.MainContainer.Width,
configuration.MainContainer.Height,
configuration.MainContainer
);
}
const mainContainer = new ContainerModel(mainContainerConfig);
const containers = new Map<string, IContainerModel>();
containers.set(mainContainer.properties.id, mainContainer);
const typeCounters = {};
(typeCounters as any)[mainContainer.properties.type] = 0;
return {
configuration,
history: [
{
lastAction: '',
mainContainer: mainContainer.properties.id,
containers,
typeCounters,
symbols: new Map()
}
],
historyCurrentStep: 0,
version: APP_VERSION ?? 'test-version'
};
}
/**
* Default config when the API is not available
*/
export const DEFAULT_CONFIG: IConfiguration = {
/* eslint-disable @typescript-eslint/naming-convention */
AvailableContainers: [
{
Type: 'Container',
MaxWidth: 200,
Height: 100,
Style: {
fillOpacity: 0,
stroke: 'green'
}
}
],
AvailableSymbols: [],
Categories: [],
Patterns: [],
MainContainer: {
Type: 'Container',
Width: 800,
Height: 100,
Style: {
fillOpacity: 0,
stroke: 'black'
}
}
/* eslint-enable */
};
const DEFAULT_CONTAINER_STYLE = {
stroke: 'black',
fillOpacity: 1,
fill: 'white',
strokeWidth: 2
};
export const DEFAULT_DIMENSION_OPTION: IDimensionOptions = {
positions: [],
color: '#000000',
width: 2
};
/**
* Default Main container properties
*/
export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = {
id: 'main',
type: 'container',
parentId: '',
linkedSymbolId: '',
displayedText: 'main',
orientation: Orientation.Horizontal,
x: 0,
y: 0,
margin: {},
minWidth: 1,
maxWidth: Number.MAX_SAFE_INTEGER,
minHeight: 1,
maxHeight: Number.MAX_SAFE_INTEGER,
width: Number(DEFAULT_CONFIG.MainContainer.Width),
height: Number(DEFAULT_CONFIG.MainContainer.Height),
isAnchor: false,
isFlex: false,
positionReference: PositionReference.TopLeft,
hideChildrenInTreeview: false,
dimensionOptions: {
childrenDimensions: clone(DEFAULT_DIMENSION_OPTION),
selfDimensions: clone(DEFAULT_DIMENSION_OPTION),
selfMarginsDimensions: clone(DEFAULT_DIMENSION_OPTION),
markPosition: [],
dimensionWithMarks: clone(DEFAULT_DIMENSION_OPTION)
},
warning: '',
style: DEFAULT_CONTAINER_STYLE
};
/**
* Returns the default properties of a newly created container
* @param type Type of the container
* @param typeCount index of the container
* @param parent Parent of the container
* @param x horizontal offset
* @param y vertical offset
* @param width
* @param height
* @param containerConfig default config of the container sent by the API
* @returns {IContainerProperties} Default properties of a newly created container
*/
export function GetDefaultContainerProps(
type: string,
typeCount: number,
parent: IContainerModel | undefined | null,
x: number,
y: number,
width: number,
height: number,
containerConfig: IAvailableContainer
): IContainerProperties {
const orientation = containerConfig.Orientation ?? Orientation.Horizontal;
return ({
id: `${type}-${typeCount}`,
type,
parentId: parent?.properties.id ?? '',
linkedSymbolId: '',
displayedText: `${containerConfig.DisplayedText ?? type}-${typeCount}`,
orientation,
x,
y,
margin: containerConfig.Margin ?? {},
width,
height,
isAnchor: containerConfig.IsAnchor ?? false,
isFlex: containerConfig.IsFlex ?? false,
positionReference: containerConfig.PositionReference ?? PositionReference.TopLeft,
minWidth: containerConfig.MinWidth ?? 1,
maxWidth: containerConfig.MaxWidth ?? Number.MAX_SAFE_INTEGER,
minHeight: containerConfig.MinWidth ?? 1,
maxHeight: containerConfig.MaxWidth ?? Number.MAX_SAFE_INTEGER,
hideChildrenInTreeview: containerConfig.HideChildrenInTreeview ?? false,
dimensionOptions: {
childrenDimensions: {
...containerConfig.DimensionOptions?.childrenDimensions,
positions: containerConfig.DimensionOptions?.childrenDimensions?.positions ?? []
},
selfDimensions: {
...containerConfig.DimensionOptions?.selfDimensions,
positions: containerConfig.DimensionOptions?.selfDimensions?.positions ?? []
},
selfMarginsDimensions: {
...containerConfig.DimensionOptions?.selfMarginsDimensions,
positions: containerConfig.DimensionOptions?.selfMarginsDimensions?.positions ?? []
},
markPosition: containerConfig.DimensionOptions?.markPosition ?? [],
dimensionWithMarks: {
...containerConfig.DimensionOptions?.dimensionWithMarks,
positions: containerConfig.DimensionOptions?.dimensionWithMarks?.positions ?? []
}
},
warning: '',
customSVG: containerConfig.CustomSVG,
style: Object.assign(structuredClone(DEFAULT_CONTAINER_STYLE), structuredClone(containerConfig.Style)),
userData: structuredClone(containerConfig.UserData)
});
}
export function GetDefaultSymbolModel(
name: string,
newCounters: Record<string, number>,
type: string,
symbolConfig: IAvailableSymbol
): ISymbolModel {
const id = `${name}-${newCounters[type]}`;
return {
id,
displayedText: symbolConfig.DisplayedText ?? id,
type: name,
config: structuredClone(symbolConfig),
offset: 0,
isVertical: symbolConfig.isVertical ?? DEFAULT_SYMBOL_IS_VERTICAL,
width: symbolConfig.Width ?? DEFAULT_SYMBOL_WIDTH,
height: symbolConfig.Height ?? DEFAULT_SYMBOL_HEIGHT,
linkedContainers: new Set(),
showDimension: false
};
}
/**
* Macro function for JSON.parse(JSON.stringify(obj))
*/
function clone<T>(object: T): T {
return JSON.parse(JSON.stringify(object));
}