Merged PR 18: Add support for custom SVG
Some checks failed
continuous-integration/drone/push Build is failing

Add support for custom SVG
Add userData back into IProperties
Added library interweave
Update example
This commit is contained in:
Eric Nguyen 2022-08-17 13:43:24 +00:00
parent 82eae4971e
commit e96e4f123b
8 changed files with 109 additions and 9 deletions

View file

@ -1,9 +1,11 @@
import * as React from 'react';
import { Interweave, Node } from 'interweave';
import { XPositionReference } from '../../../Enums/XPositionReference';
import { IContainerModel } from '../../../Interfaces/IContainerModel';
import { DIMENSION_MARGIN } from '../../../utils/default';
import { getDepth } from '../../../utils/itertools';
import { Dimension } from './Dimension';
import IProperties from '../../../Interfaces/IProperties';
interface IContainerProps {
model: IContainerModel
@ -33,6 +35,14 @@ export const Container: React.FC<IContainerProps> = (props: IContainerProps) =>
props.model.properties.style
);
const svg = (props.model.properties.customSVG != null)
? CreateReactCustomSVG(props.model.properties.customSVG, props.model.properties)
: (<rect
width={props.model.properties.width}
height={props.model.properties.height}
style={style}
>
</rect>);
// Dimension props
const depth = getDepth(props.model);
const dimensionMargin = DIMENSION_MARGIN * (depth + 1);
@ -79,12 +89,7 @@ export const Container: React.FC<IContainerProps> = (props: IContainerProps) =>
text={text}
/>
{ dimensionChildren }
<rect
width={props.model.properties.width}
height={props.model.properties.height}
style={style}
>
</rect>
{ svg }
<text
x={xText}
y={yText}
@ -141,3 +146,63 @@ export function restoreX(x: number, width: number, xPositionReference = XPositio
}
return transformedX;
}
function CreateReactCustomSVG(customSVG: string, props: IProperties): React.ReactNode {
return <Interweave
tagName='g'
disableLineBreaks={true}
content={customSVG}
allowElements={true}
transform={(node, children) => 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('');
}