import * as React from 'react'; import { Interweave, Node } from 'interweave'; import { XPositionReference } from '../../../Enums/XPositionReference'; import { IContainerModel } from '../../../Interfaces/IContainerModel'; import { DIMENSION_MARGIN, SHOW_CHILDREN_DIMENSIONS, SHOW_PARENT_DIMENSION, SHOW_TEXT } from '../../../utils/default'; import { getDepth } from '../../../utils/itertools'; import { Dimension } from './Dimension'; import IProperties from '../../../Interfaces/IProperties'; interface IContainerProps { model: IContainerModel } /** * Render the container * @returns Render the container */ export const Container: React.FC = (props: IContainerProps) => { const containersElements = props.model.children.map(child => ); const xText = props.model.properties.width / 2; const yText = props.model.properties.height / 2; const transform = `translate(${props.model.properties.x}, ${props.model.properties.y})`; // g style const defaultStyle: React.CSSProperties = { transitionProperty: 'all', transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)', transitionDuration: '150ms' }; // Rect style const style = Object.assign( JSON.parse(JSON.stringify(defaultStyle)), props.model.properties.style ); const svg = (props.model.properties.customSVG != null) ? CreateReactCustomSVG(props.model.properties.customSVG, props.model.properties) : ( ); // Dimension props const depth = getDepth(props.model); const dimensionMargin = DIMENSION_MARGIN * (depth + 1); const id = `dim-${props.model.properties.id}`; const xStart: number = 0; const xEnd = props.model.properties.width; const y = -dimensionMargin; const strokeWidth = 1; const text = (props.model.properties.width ?? 0).toString(); let dimensionChildren: JSX.Element | null = null; if (props.model.children.length > 1 && SHOW_CHILDREN_DIMENSIONS) { const { childrenId, xChildrenStart, xChildrenEnd, yChildren, textChildren } = GetChildrenDimensionProps(props, dimensionMargin); dimensionChildren = ; } return ( { SHOW_PARENT_DIMENSION ? : null } { dimensionChildren } { svg } { SHOW_TEXT ? {props.model.properties.displayedText} : null } { containersElements } ); }; 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).toString(); return { childrenId, xChildrenStart, xChildrenEnd, yChildren, textChildren }; } export function transformX(x: number, width: number, xPositionReference = XPositionReference.Left): number { let transformedX = x; if (xPositionReference === XPositionReference.Center) { transformedX += width / 2; } else if (xPositionReference === XPositionReference.Right) { transformedX += width; } return transformedX; } export function restoreX(x: number, width: number, xPositionReference = XPositionReference.Left): number { let transformedX = x; if (xPositionReference === XPositionReference.Center) { transformedX -= width / 2; } else if (xPositionReference === XPositionReference.Right) { transformedX -= width; } return transformedX; } function CreateReactCustomSVG(customSVG: string, props: IProperties): React.ReactNode { return transform(node, children, props)} />; } function transform(node: HTMLElement, children: Node[], props: IProperties): React.ReactNode { const supportedTags = ['line', 'path', 'rect']; if (supportedTags.includes(node.tagName.toLowerCase())) { const attributes: {[att: string]: string | object | null} = {}; node.getAttributeNames().forEach(attName => { const attributeValue = node.getAttribute(attName); if (attributeValue === null) { attributes[attName] = attributeValue; return; } if (attributeValue.startsWith('{userData.') && attributeValue.endsWith('}')) { // support for userData if (props.userData === undefined) { return undefined; } const userDataKey = attributeValue.replace(/userData\./, ''); const prop = Object.entries(props.userData).find(([key]) => `{${key}}` === userDataKey); if (prop !== undefined) { attributes[camelize(attName)] = prop[1]; return; } } if (attributeValue.startsWith('{{') && attributeValue.endsWith('}}')) { // support for object const stringObject = attributeValue.slice(1, -1); const object: JSON = JSON.parse(stringObject); attributes[camelize(attName)] = object; return; } const prop = Object.entries(props).find(([key]) => `{${key}}` === attributeValue); if (prop !== undefined) { attributes[camelize(attName)] = prop[1]; return; } attributes[camelize(attName)] = attributeValue; }); return React.createElement(node.tagName.toLowerCase(), attributes, children); } return undefined; } function camelize(str: string): any { return str.split('-').map((word, index) => index > 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word).join(''); }