Adding Loop rendering component

This commit is contained in:
Jeff Avallone 2019-01-31 18:20:58 -05:00
parent c1716570a8
commit f4e7bc0e76
4 changed files with 143 additions and 7 deletions

View File

@ -4,11 +4,11 @@ import {
tan,
grey,
blue,
fontFamily,
fontSizeSmall,
strokeBase
strokeBase,
infoText
} from 'rendering/style';
export { infoText };
export const literal = {
fill: blue,
strokeWidth: '1px',
@ -31,7 +31,3 @@ export const capture = {
export const anchor = {
fill: brown
};
export const infoText = {
fontSize: fontSizeSmall,
fontFamily
};

133
src/rendering/Loop/index.js Normal file
View File

@ -0,0 +1,133 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getBBox } from 'layout';
import * as style from 'rendering/style';
const radius = 10;
const arrowSize = 5;
const Loop = ({
label,
labelTransform,
contentTransform,
loopPaths,
children
}) => {
const labelProps = {
transform: labelTransform,
style: style.infoText
};
return <>
<path style={ style.connectors } d={ loopPaths }/>
{ label && <text { ...labelProps }>{ label }</text> }
<g transform={ contentTransform }>
{ children }
</g>
</>;
};
Loop.propTypes = {
label: PropTypes.string,
greedy: PropTypes.bool,
skip: PropTypes.bool,
repeat: PropTypes.bool,
labelTransform: PropTypes.string,
contentTransform: PropTypes.string,
loopPaths: PropTypes.string,
children: PropTypes.node.isRequired
};
const generateOffsetBox = (box, { skip, repeat }) => {
let x = 0;
let y = 0;
if (skip) {
x = 1.5 * radius;
y = radius;
} else if (repeat) {
x = radius;
}
return {
...box,
x, y,
axisX1: x + box.axisX1,
axisX2: x + box.axisX2,
axisY: y + box.axisY
};
};
const skipPath = (box, greedy) => {
const vert = Math.max(0, box.axisY - box.y - radius);
const horiz = box.width - radius;
return `
M 0,${ box.axisY }
q ${ radius },0 ${ radius },${ -radius }
v ${ -vert }
q 0,${ -radius } ${ radius },${ -radius }
h ${ horiz }
q ${ radius },0 ${ radius },${ radius }
v ${ vert }
q 0,${ radius } ${ radius },${ radius }
` + (greedy ? '' : `
M ${ radius },${ box.axisY - 1.5 * radius }
l ${ arrowSize },${ arrowSize }
z
l ${ -arrowSize },${ arrowSize }
`);
};
const repeatPath = (box, greedy) => {
const vert = box.y + box.height - box.axisY - radius;
return `
M ${ box.x },${ box.axisY }
q ${ -radius },0 ${ -radius },${ radius }
v ${ vert }
q 0,${ radius } ${ radius },${ radius }
h ${ box.width }
q ${ radius },0 ${ radius },${ -radius }
v ${ -vert }
q 0,${ -radius } ${ -radius },${ -radius }
` + (greedy ? `
m ${ radius },${ 1.5 * radius }
l ${ arrowSize },${ -arrowSize }
z
l ${ -arrowSize },${ -arrowSize }
` : '');
};
const layout = data => {
const { label, greedy, skip, repeat } = data.props || {};
const childBox = generateOffsetBox(data.children[0].box, { skip, repeat });
const labelBox = label ?
getBBox(<text style={ style.infoText }>{ label }</text>) :
{ width: 0, height: 0 };
const width = childBox.width + childBox.x * 2;
const height = childBox.height + labelBox.height +
(skip ? 10 : 0) + (repeat ? 10 : 0);
data.box = {
width,
height,
axisY: childBox.axisY,
axisX1: childBox.axisX1,
axisX2: childBox.axisX2
};
data.props = {
...data.props,
labelTransform: `translate(${ width - labelBox.width } ${ height })`,
contentTransform: `translate(${ childBox.x } ${ childBox.y })`,
loopPaths: [
skip && skipPath(childBox, greedy),
repeat && repeatPath(childBox, greedy)
].filter(Boolean).join('')
};
return data;
};
export default Loop;
export { layout };

View File

@ -23,3 +23,8 @@ export const connectors = {
fillOpacity: 0,
...strokeBase
};
export const infoText = {
fontSize: fontSizeSmall,
fontFamily
};

View File

@ -2,6 +2,7 @@ import * as SVG from 'rendering/SVG';
import * as Pin from 'rendering/Pin';
import * as Text from 'rendering/Text';
import * as Box from 'rendering/Box';
import * as Loop from 'rendering/Loop';
import * as HorizontalLayout from 'rendering/HorizontalLayout';
import * as VerticalLayout from 'rendering/VerticalLayout';
@ -10,6 +11,7 @@ export default {
Pin,
Text,
Box,
Loop,
HorizontalLayout,
VerticalLayout
};