Adding HorizontalLayout
This commit is contained in:
parent
4f1ad26635
commit
4e27c4ef87
90
src/rendering/HorizontalLayout/index.js
Normal file
90
src/rendering/HorizontalLayout/index.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import * as style from 'rendering/style';
|
||||||
|
|
||||||
|
const HorizontalLayout = ({ connectorPath, transforms, children }) => {
|
||||||
|
return <>
|
||||||
|
<path style={ style.connectors } d={ connectorPath }/>
|
||||||
|
{ React.Children.map(children, (child, i) => (
|
||||||
|
<g transform={ transforms[i] }>{ child }</g>
|
||||||
|
)) }
|
||||||
|
</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
HorizontalLayout.defaultProps = {
|
||||||
|
withConnectors: false,
|
||||||
|
spacing: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
HorizontalLayout.propTypes = {
|
||||||
|
spacing: PropTypes.number,
|
||||||
|
withConnectors: PropTypes.bool,
|
||||||
|
connectorPath: PropTypes.string,
|
||||||
|
transforms: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
children: PropTypes.oneOfType([
|
||||||
|
PropTypes.arrayOf(PropTypes.node),
|
||||||
|
PropTypes.node
|
||||||
|
]).isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateOffsetBoxes = (boxes, axisY, spacing) => {
|
||||||
|
let offset = 0;
|
||||||
|
return boxes.map(box => {
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
...box,
|
||||||
|
offsetX: offset,
|
||||||
|
offsetY: axisY - box.axisY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
offset += box.width + spacing;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const calculateChildTransforms = boxes =>
|
||||||
|
boxes.map(box => `translate(${ box.offsetX } ${ box.offsetY })`);
|
||||||
|
const calculateConnectorPath = (boxes, axisY) => {
|
||||||
|
let last = boxes[0];
|
||||||
|
return boxes.slice(1).map(box => {
|
||||||
|
try {
|
||||||
|
return `
|
||||||
|
M${ last.offsetX + last.axisX2 },${ axisY }
|
||||||
|
H${ box.offsetX + box.axisX1 }
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
last = box;
|
||||||
|
}
|
||||||
|
}).join('');
|
||||||
|
};
|
||||||
|
const layout = data => {
|
||||||
|
const { withConnectors, spacing } = {
|
||||||
|
...HorizontalLayout.defaultProps,
|
||||||
|
...data.props
|
||||||
|
};
|
||||||
|
const childBoxes = data.children.map(child => child.box);
|
||||||
|
|
||||||
|
data.box = {
|
||||||
|
width: childBoxes.reduce((width, box) => width + box.width, 0) +
|
||||||
|
(childBoxes.length - 1) * spacing,
|
||||||
|
height: Math.max(...(childBoxes.map(box => box.axisY))) +
|
||||||
|
Math.max(...(childBoxes.map(box => box.height - box.axisY))),
|
||||||
|
axisY: Math.max(...(childBoxes.map(box => box.axisY)))
|
||||||
|
};
|
||||||
|
|
||||||
|
const offsetBoxes = generateOffsetBoxes(childBoxes, data.box.axisY, spacing);
|
||||||
|
data.props = {
|
||||||
|
...data.props,
|
||||||
|
transforms: calculateChildTransforms(offsetBoxes),
|
||||||
|
connectorPath: withConnectors
|
||||||
|
? calculateConnectorPath(offsetBoxes, data.box.axisY)
|
||||||
|
: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HorizontalLayout;
|
||||||
|
export { layout };
|
@ -18,3 +18,8 @@ export const strokeBase = {
|
|||||||
strokeWidth: '2px',
|
strokeWidth: '2px',
|
||||||
stroke: black
|
stroke: black
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const connectors = {
|
||||||
|
fillOpacity: 0,
|
||||||
|
...strokeBase
|
||||||
|
};
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import * as SVG from 'rendering/SVG';
|
import * as SVG from 'rendering/SVG';
|
||||||
import * as Text from 'rendering/Text';
|
import * as Text from 'rendering/Text';
|
||||||
import * as Box from 'rendering/Box';
|
import * as Box from 'rendering/Box';
|
||||||
|
import * as HorizontalLayout from 'rendering/HorizontalLayout';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
SVG,
|
SVG,
|
||||||
Text,
|
Text,
|
||||||
Box
|
Box,
|
||||||
|
HorizontalLayout
|
||||||
};
|
};
|
||||||
|
@ -6,18 +6,37 @@ const parse = expr => {
|
|||||||
type: 'SVG',
|
type: 'SVG',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: 'Box',
|
type: 'HorizontalLayout',
|
||||||
props: {
|
props: {
|
||||||
theme: 'literal'
|
withConnectors: true
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: 'Text',
|
type: 'Box',
|
||||||
props: {
|
props: {
|
||||||
quoted: true
|
theme: 'literal'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
`JS => ${ expr }`
|
{
|
||||||
|
type: 'Text',
|
||||||
|
children: [
|
||||||
|
'JS'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Box',
|
||||||
|
props: {
|
||||||
|
theme: 'literal'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'Text',
|
||||||
|
children: [
|
||||||
|
expr
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -6,18 +6,37 @@ const parse = expr => {
|
|||||||
type: 'SVG',
|
type: 'SVG',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: 'Box',
|
type: 'HorizontalLayout',
|
||||||
props: {
|
props: {
|
||||||
theme: 'literal'
|
withConnectors: true
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: 'Text',
|
type: 'Box',
|
||||||
props: {
|
props: {
|
||||||
quoted: true
|
theme: 'literal'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
`PCRE => ${ expr }`
|
{
|
||||||
|
type: 'Text',
|
||||||
|
children: [
|
||||||
|
'PCRE'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Box',
|
||||||
|
props: {
|
||||||
|
theme: 'literal'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'Text',
|
||||||
|
children: [
|
||||||
|
expr
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user