init 🚀
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const Handle = styled.div`
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #222;
|
||||
left: 50%;
|
||||
border-radius: 50%;
|
||||
`;
|
||||
|
||||
export default props => <Handle {...props} />;
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import wrapNode from './wrapNode';
|
||||
import Handle from '../Handle';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
background: #ff6060;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
export default wrapNode(({ data, style }) => (
|
||||
<Wrapper style={style}>
|
||||
<Handle style={{ top: 0 }} />
|
||||
{data.label}
|
||||
<Handle style={{ bottom: 0, top: 'auto', transform: 'translate(-50%, 50%)' }} />
|
||||
</Wrapper>
|
||||
));
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import wrapNode from './wrapNode';
|
||||
import Handle from '../Handle';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
background: #9999ff;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
export default wrapNode(({ data, style }) => (
|
||||
<Wrapper style={style}>
|
||||
{data.label}
|
||||
<Handle style={{ bottom: 0, top: 'auto', transform: 'translate(-50%, 50%)' }} />
|
||||
</Wrapper>
|
||||
));
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import wrapNode from './wrapNode';
|
||||
import Handle from '../Handle';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
background: #55ff99;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
export default wrapNode(({ data, style }) => (
|
||||
<Wrapper style={style}>
|
||||
<Handle style={{ top: 0 }} />
|
||||
{data.label}
|
||||
</Wrapper>
|
||||
));
|
||||
@@ -0,0 +1,76 @@
|
||||
import React, { useEffect, useRef, useContext } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import ReactDraggable from 'react-draggable';
|
||||
|
||||
import { GraphContext } from '../../GraphContext';
|
||||
|
||||
const NodeWrapper = styled.div`
|
||||
position: absolute;
|
||||
width: 150px;
|
||||
color: #222;
|
||||
font-family: sans-serif;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
cursor: grab;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2px;
|
||||
user-select: none;
|
||||
pointer-events: all;
|
||||
transform-origin: 0 0;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
`;
|
||||
|
||||
export default NodeComponent => (props) => {
|
||||
const { position, data, onNodeClick } = props;
|
||||
const { id, __width, __height } = data;
|
||||
const nodeElement = useRef(null);
|
||||
const graphContext = useContext(GraphContext);
|
||||
const { x, y, k } = graphContext.transform;
|
||||
|
||||
useEffect(() => {
|
||||
const bounds = nodeElement.current.getBoundingClientRect();
|
||||
|
||||
if (__width !== bounds.width || __height !== bounds.height) {
|
||||
graphContext.updateNodeData(id, { __width: bounds.width, __height: bounds.height });
|
||||
}
|
||||
}, []);
|
||||
|
||||
const nodePosition = {
|
||||
x: (k * position.x) + x,
|
||||
y: (k * position.y) + y
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactDraggable.DraggableCore
|
||||
grid={[1, 1]}
|
||||
onStart={(e) => {
|
||||
const offsetX = e.clientX - position.x - x;
|
||||
const offsetY = e.clientY - position.y - y;
|
||||
|
||||
graphContext.updateNodeData(id, { __offsetX: offsetX, __offsetY: offsetY });
|
||||
}}
|
||||
onDrag={(e, d) => {
|
||||
const { __offsetX = 0, __offsetY = 0 } = data;
|
||||
|
||||
graphContext.updateNodePos(id, {
|
||||
x: e.clientX - x - __offsetX,
|
||||
y: e.clientY - y - __offsetY
|
||||
});
|
||||
}}
|
||||
scale={k}
|
||||
>
|
||||
<NodeWrapper
|
||||
className="node"
|
||||
ref={nodeElement}
|
||||
style={{ transform: `translate(${position.x}px,${position.y}px)` }}
|
||||
onClick={() => onNodeClick(data)}
|
||||
// style={{ transform: `translate(${nodePosition.x}px,${nodePosition.y}px) scale(${k})` }}
|
||||
>
|
||||
<NodeComponent {...props} />
|
||||
</NodeWrapper>
|
||||
</ReactDraggable.DraggableCore>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { Consumer } from '../GraphContext';
|
||||
import DefaultNode from './NodeTypes/DefaultNode';
|
||||
import InputNode from './NodeTypes/InputNode';
|
||||
import OutputNode from './NodeTypes/OutputNode';
|
||||
|
||||
const Nodes = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
transform-origin: 0 0;
|
||||
`;
|
||||
|
||||
class NodeRenderer extends PureComponent {
|
||||
|
||||
renderNode(d, onNodeClick) {
|
||||
const nodeType = d.data.type || 'default';
|
||||
const NodeComponent = this.props.nodeTypes[nodeType];
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
key={d.data.id}
|
||||
position={d.position}
|
||||
data={d.data}
|
||||
style={d.style || {}}
|
||||
onNodeClick={onNodeClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Consumer>
|
||||
{({ transform, nodes, onNodeClick }) => (
|
||||
<Nodes
|
||||
style={{
|
||||
transform: `translate(${transform.x}px,${transform.y}px) scale(${transform.k})`
|
||||
}}
|
||||
>
|
||||
{nodes.map(d => this.renderNode(d, onNodeClick))}
|
||||
</Nodes>
|
||||
)}
|
||||
</Consumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
NodeRenderer.defaultProps = {
|
||||
nodeTypes: {
|
||||
input: InputNode,
|
||||
default: DefaultNode,
|
||||
output: OutputNode
|
||||
}
|
||||
};
|
||||
|
||||
export default NodeRenderer;
|
||||
Reference in New Issue
Block a user