@@ -10,6 +10,12 @@ const onLoad = (reactFlowInstance) => console.log('flow loaded:', reactFlowInsta
|
||||
|
||||
const initBgColor = '#f0e742';
|
||||
|
||||
const connectionLineStyle = { stroke: '#fff' };
|
||||
const snapGrid = [16, 16];
|
||||
const nodeTypes = {
|
||||
selectorNode: ColorSelectorNode,
|
||||
};
|
||||
|
||||
const CustomNodeFlow = () => {
|
||||
const [elements, setElements] = useState([]);
|
||||
const [bgColor, setBgColor] = useState(initBgColor);
|
||||
@@ -66,14 +72,12 @@ const CustomNodeFlow = () => {
|
||||
onElementsRemove={onElementsRemove}
|
||||
onConnect={onConnect}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
style={{ width: '100%', height: '100%', background: bgColor }}
|
||||
style={{ background: bgColor }}
|
||||
onLoad={onLoad}
|
||||
nodeTypes={{
|
||||
selectorNode: ColorSelectorNode,
|
||||
}}
|
||||
connectionLineStyle={{ stroke: '#fff' }}
|
||||
nodeTypes={nodeTypes}
|
||||
connectionLineStyle={connectionLineStyle}
|
||||
snapToGrid={true}
|
||||
snapGrid={[16, 16]}
|
||||
snapGrid={snapGrid}
|
||||
>
|
||||
<MiniMap
|
||||
nodeColor={(n) => {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function CustomEdge({
|
||||
id, sourceX, sourceY, targetX, targetY, label, style = {}
|
||||
}) {
|
||||
export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY, style = {}, data }) {
|
||||
return (
|
||||
<>
|
||||
<path id={id} style={style} className="react-flow__edge-path" d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`} />
|
||||
<path
|
||||
id={id}
|
||||
style={style}
|
||||
className="react-flow__edge-path"
|
||||
d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`}
|
||||
/>
|
||||
<text>
|
||||
<textPath href={`#${id}`} style={{ fontSize: '12px' }} startOffset="50%" textAnchor="middle">
|
||||
{label}
|
||||
{data.text}
|
||||
</textPath>
|
||||
</text>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,9 +41,13 @@ const initialElements = [
|
||||
labelBgStyle: { fill: '#eee', fillOpacity: 0.7 },
|
||||
arrowHeadType: 'arrowclosed',
|
||||
},
|
||||
{ id: 'e5-8', source: '5', target: '8', type: 'custom', label: 'custom edge' },
|
||||
{ id: 'e5-8', source: '5', target: '8', type: 'custom', data: { text: 'custom edge' } },
|
||||
];
|
||||
|
||||
const edgeTypes = {
|
||||
custom: CustomEdge,
|
||||
};
|
||||
|
||||
const EdgesFlow = () => {
|
||||
const [elements, setElements] = useState(initialElements);
|
||||
|
||||
@@ -57,12 +61,9 @@ const EdgesFlow = () => {
|
||||
onElementsRemove={onElementsRemove}
|
||||
onConnect={onConnect}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
onLoad={onLoad}
|
||||
snapToGrid={true}
|
||||
edgeTypes={{
|
||||
custom: CustomEdge,
|
||||
}}
|
||||
edgeTypes={edgeTypes}
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
@@ -104,6 +104,9 @@ const initialElements = [
|
||||
},
|
||||
];
|
||||
|
||||
const connectionLineStyle = { stroke: '#ddd' };
|
||||
const snapGrid = [16, 16];
|
||||
|
||||
const OverviewFlow = () => {
|
||||
const [elements, setElements] = useState(initialElements);
|
||||
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
|
||||
@@ -119,11 +122,10 @@ const OverviewFlow = () => {
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
onSelectionChange={onSelectionChange}
|
||||
onMoveEnd={onMoveEnd}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
onLoad={onLoad}
|
||||
connectionLineStyle={{ stroke: '#ddd' }}
|
||||
connectionLineStyle={connectionLineStyle}
|
||||
snapToGrid={true}
|
||||
snapGrid={[16, 16]}
|
||||
snapGrid={snapGrid}
|
||||
>
|
||||
<MiniMap
|
||||
nodeColor={(n) => {
|
||||
|
||||
@@ -13,6 +13,8 @@ const initialElements = [
|
||||
|
||||
const isValidConnection = (connection) => connection.target === 'B';
|
||||
|
||||
const onLoad = (reactFlowInstance) => reactFlowInstance.fitView();
|
||||
|
||||
const CustomInput = () => (
|
||||
<>
|
||||
<div>Only connectable with B</div>
|
||||
@@ -28,6 +30,11 @@ const CustomNode = ({ id }) => (
|
||||
</>
|
||||
);
|
||||
|
||||
const nodeTypes = {
|
||||
custominput: CustomInput,
|
||||
customnode: CustomNode,
|
||||
};
|
||||
|
||||
const HorizontalFlow = () => {
|
||||
const [elements, setElements] = useState(initialElements);
|
||||
const onConnect = (params) => setElements((els) => addEdge(params, els));
|
||||
@@ -37,12 +44,9 @@ const HorizontalFlow = () => {
|
||||
elements={elements}
|
||||
onConnect={onConnect}
|
||||
selectNodesOnDrag={false}
|
||||
onLoad={(reactFlowInstance) => reactFlowInstance.fitView()}
|
||||
onLoad={onLoad}
|
||||
className="validationflow"
|
||||
nodeTypes={{
|
||||
custominput: CustomInput,
|
||||
customnode: CustomNode,
|
||||
}}
|
||||
nodeTypes={nodeTypes}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Generated
+96
-114
@@ -4148,9 +4148,9 @@
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.1.0.tgz",
|
||||
"integrity": "sha512-yPyQSmxIXLieEIRikk2w8AEtWkFdfG/LXcw1KvEtK3iP0ENZLW/WYQmdzOKqfSaLhooz4CJ9D+WY79C8ZliACw==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.1.1.tgz",
|
||||
"integrity": "sha512-cQ2HGrtyNJ1IBxpTP1U5m/FkMAJvgw7d2j1q3c9P0XUuYilEgF6e4naTpsgm4iVcQeOnccZlw7XHRIUBy0ymcg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^2.4.0",
|
||||
@@ -4158,46 +4158,46 @@
|
||||
"@octokit/request": "^5.4.0",
|
||||
"@octokit/types": "^5.0.0",
|
||||
"before-after-hook": "^2.1.0",
|
||||
"universal-user-agent": "^5.0.0"
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.3.tgz",
|
||||
"integrity": "sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg==",
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.5.tgz",
|
||||
"integrity": "sha512-70K5u6zd45ItOny6aHQAsea8HHQjlQq85yqOMe+Aj8dkhN2qSJ9T+Q3YjUjEYfPRBcuUWNgMn62DQnP/4LAIiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^5.0.0",
|
||||
"is-plain-object": "^3.0.0",
|
||||
"universal-user-agent": "^5.0.0"
|
||||
"is-plain-object": "^4.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
|
||||
"integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz",
|
||||
"integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.1.tgz",
|
||||
"integrity": "sha512-qgMsROG9K2KxDs12CO3bySJaYoUu2aic90qpFrv7A8sEBzZ7UFGvdgPKiLw5gOPYEYbS0Xf8Tvf84tJutHPulQ==",
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.2.tgz",
|
||||
"integrity": "sha512-SpB/JGdB7bxRj8qowwfAXjMpICUYSJqRDj26MKJAryRQBqp/ZzARsaO2LEFWzDaps0FLQoPYVGppS0HQXkBhdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/request": "^5.3.0",
|
||||
"@octokit/types": "^5.0.0",
|
||||
"universal-user-agent": "^5.0.0"
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.3.tgz",
|
||||
"integrity": "sha512-eKTs91wXnJH8Yicwa30jz6DF50kAh7vkcqCQ9D7/tvBAP5KKkg6I2nNof8Mp/65G0Arjsb4QcOJcIEQY+rK1Rg==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.3.0.tgz",
|
||||
"integrity": "sha512-Ye2ZJreP0ZlqJQz8fz+hXvrEAEYK4ay7br1eDpWzr6j76VXs/gKqxFcH8qRzkB3fo/2xh4Vy9VtGii4ZDc9qlA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^5.0.0"
|
||||
"@octokit/types": "^5.2.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-request-log": {
|
||||
@@ -4207,35 +4207,35 @@
|
||||
"dev": true
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.0.0.tgz",
|
||||
"integrity": "sha512-emS6gysz4E9BNi9IrCl7Pm4kR+Az3MmVB0/DoDCmF4U48NbYG3weKyDlgkrz6Jbl4Mu4nDx8YWZwC4HjoTdcCA==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.2.tgz",
|
||||
"integrity": "sha512-PTI7wpbGEZ2IR87TVh+TNWaLcgX/RsZQalFbQCq8XxYUrQ36RHyERrHSNXFy5gkWpspUAOYRSV707JJv6BhqJA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^5.0.0",
|
||||
"@octokit/types": "^5.1.1",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.5.tgz",
|
||||
"integrity": "sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg==",
|
||||
"version": "5.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.7.tgz",
|
||||
"integrity": "sha512-FN22xUDP0i0uF38YMbOfx6TotpcENP5W8yJM1e/LieGXn6IoRxDMnBf7tx5RKSW4xuUZ/1P04NFZy5iY3Rax1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.0.0",
|
||||
"@octokit/types": "^5.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"is-plain-object": "^3.0.0",
|
||||
"is-plain-object": "^4.0.0",
|
||||
"node-fetch": "^2.3.0",
|
||||
"once": "^1.4.0",
|
||||
"universal-user-agent": "^5.0.0"
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
|
||||
"integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz",
|
||||
"integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -4252,21 +4252,21 @@
|
||||
}
|
||||
},
|
||||
"@octokit/rest": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.0.tgz",
|
||||
"integrity": "sha512-4G/a42lry9NFGuuECnua1R1eoKkdBYJap97jYbWDNYBOUboWcM75GJ1VIcfvwDV/pW0lMPs7CEmhHoVrSV5shg==",
|
||||
"version": "18.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.3.tgz",
|
||||
"integrity": "sha512-GubgemnLvUJlkhouTM2BtX+g/voYT/Mqh0SASGwTnLvSkW1irjt14N911/ABb6m1Hru0TwScOgFgMFggp3igfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/core": "^3.0.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.2.0",
|
||||
"@octokit/plugin-request-log": "^1.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "4.0.0"
|
||||
"@octokit/plugin-rest-endpoint-methods": "4.1.2"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.0.1.tgz",
|
||||
"integrity": "sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.2.0.tgz",
|
||||
"integrity": "sha512-XjOk9y4m8xTLIKPe1NFxNWBdzA2/z3PFFA/bwf4EoH6oS8hM0Y46mEa4Cb+KCyj/tFDznJFahzQ0Aj3o1FYq4A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": ">= 8"
|
||||
@@ -4301,9 +4301,9 @@
|
||||
}
|
||||
},
|
||||
"@sindresorhus/is": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.0.0.tgz",
|
||||
"integrity": "sha512-kqA5I6Yun7PBHk8WN9BBP1c7FfN2SrD05GuVSEYPqDb4nerv7HqYfgBfMIKmT/EuejURkJKLZuLyGKGs6WEG9w==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.0.tgz",
|
||||
"integrity": "sha512-n4J+zu52VdY43kdi/XdI9DzuMr1Mur8zFL5ZRG2opCans9aiFwkPxHYFEb5Xgy7n1Z4K6WfI4FpqUqsh3E8BPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@svgr/babel-plugin-add-jsx-attribute": {
|
||||
@@ -5155,9 +5155,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@welldone-software/why-did-you-render": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-4.2.6.tgz",
|
||||
"integrity": "sha512-BJrqc1gKdE+sLyrICgjcwItuwT5nZorPgpTafpIHSpB1o4K0xY7P6wQfndt/mcXtTPwTQOuSpoyuoASl4b2mxQ==",
|
||||
"version": "4.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-4.2.7.tgz",
|
||||
"integrity": "sha512-La1INHiFnHi9USYGAaRsPhMXMOt2x3qee8cXxRija0h3tQJY1/XmSSelyXDMQkVtDDa61DMfk3H59gxWDmnqsA==",
|
||||
"requires": {
|
||||
"lodash": "^4"
|
||||
}
|
||||
@@ -6232,9 +6232,9 @@
|
||||
}
|
||||
},
|
||||
"cli-spinners": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz",
|
||||
"integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz",
|
||||
"integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==",
|
||||
"dev": true
|
||||
},
|
||||
"cli-table3": {
|
||||
@@ -6838,9 +6838,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"cypress": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/cypress/-/cypress-4.10.0.tgz",
|
||||
"integrity": "sha512-eFv1WPp4zFrAgZ6mwherBGVsTpHvay/hEF5F7U7yfAkTxsUQn/ZG/LdX67fIi3bKDTQXYzFv/CvywlQSeug8Bg==",
|
||||
"version": "4.11.0",
|
||||
"resolved": "https://registry.npmjs.org/cypress/-/cypress-4.11.0.tgz",
|
||||
"integrity": "sha512-6Yd598+KPATM+dU1Ig0g2hbA+R/o1MAKt0xIejw4nZBVLSplCouBzqeKve6XsxGU6n4HMSt/+QYsWfFcoQeSEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cypress/listr-verbose-renderer": "0.4.1",
|
||||
@@ -6867,7 +6867,7 @@
|
||||
"is-installed-globally": "0.3.2",
|
||||
"lazy-ass": "1.6.0",
|
||||
"listr": "0.14.3",
|
||||
"lodash": "4.17.15",
|
||||
"lodash": "4.17.19",
|
||||
"log-symbols": "3.0.0",
|
||||
"minimist": "1.2.5",
|
||||
"moment": "2.26.0",
|
||||
@@ -6919,9 +6919,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty-bytes": {
|
||||
@@ -6974,9 +6974,9 @@
|
||||
}
|
||||
},
|
||||
"d3-selection": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz",
|
||||
"integrity": "sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA=="
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
|
||||
"integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
|
||||
},
|
||||
"d3-timer": {
|
||||
"version": "1.0.9",
|
||||
@@ -7922,9 +7922,9 @@
|
||||
}
|
||||
},
|
||||
"got": {
|
||||
"version": "11.5.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.5.0.tgz",
|
||||
"integrity": "sha512-vOZEcEaK0b6x11uniY0HcblZObKPRO75Jvz53VKuqGSaKCM/zEt0sj2LGYVdqDYJzO3wYdG+FPQQ1hsgoXy7vQ==",
|
||||
"version": "11.5.1",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.5.1.tgz",
|
||||
"integrity": "sha512-reQEZcEBMTGnujmQ+Wm97mJs/OK6INtO6HmLI+xt3+9CvnRwWjXutUvb2mqr+Ao4Lu05Rx6+udx9sOQAmExMxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sindresorhus/is": "^3.0.0",
|
||||
@@ -7934,7 +7934,7 @@
|
||||
"cacheable-lookup": "^5.0.3",
|
||||
"cacheable-request": "^7.0.1",
|
||||
"decompress-response": "^6.0.0",
|
||||
"http2-wrapper": "^1.0.0-beta.4.8",
|
||||
"http2-wrapper": "^1.0.0-beta.5.0",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"responselike": "^2.0.0"
|
||||
@@ -8181,9 +8181,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.0.tgz",
|
||||
"integrity": "sha512-K+LZp6L/6eE5swqIcVXrxl21aGDU4S50gKH0/d96OMQnSBCyGyZl/oZhbkVmdp5sBoINHd4xZvFSARh2dk6DWA==",
|
||||
"version": "7.3.3",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
|
||||
"integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^4.2.1",
|
||||
@@ -8192,7 +8192,7 @@
|
||||
"cli-width": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^3.0.0",
|
||||
"lodash": "^4.17.15",
|
||||
"lodash": "^4.17.19",
|
||||
"mute-stream": "0.0.8",
|
||||
"run-async": "^2.4.0",
|
||||
"rxjs": "^6.6.0",
|
||||
@@ -9105,9 +9105,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"macos-release": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.0.tgz",
|
||||
"integrity": "sha512-ko6deozZYiAkqa/0gmcsz+p4jSy3gY7/ZsCEokPaYd8k+6/aXGkiTgr61+Owup7Sf+xjqW8u2ElhoM9SEcEfuA==",
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz",
|
||||
"integrity": "sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==",
|
||||
"dev": true
|
||||
},
|
||||
"make-dir": {
|
||||
@@ -9490,9 +9490,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ora": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-4.0.4.tgz",
|
||||
"integrity": "sha512-77iGeVU1cIdRhgFzCK8aw1fbtT1B/iZAvWjS+l/o1x0RShMgxHUZaD2yDpWsNCPwXg9z1ZA78Kbdvr8kBmG/Ww==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-4.0.5.tgz",
|
||||
"integrity": "sha512-jCDgm9DqvRcNIAEv2wZPrh7E5PcQiDUnbnWbAfu4NGAE2ZNqPFbDixmWldy1YG2QfLeQhuiu6/h5VRrk6cG50w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^3.0.0",
|
||||
@@ -10937,9 +10937,9 @@
|
||||
}
|
||||
},
|
||||
"registry-auth-token": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz",
|
||||
"integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz",
|
||||
"integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"rc": "^1.2.8"
|
||||
@@ -10978,13 +10978,13 @@
|
||||
}
|
||||
},
|
||||
"release-it": {
|
||||
"version": "13.6.5",
|
||||
"resolved": "https://registry.npmjs.org/release-it/-/release-it-13.6.5.tgz",
|
||||
"integrity": "sha512-m4JcHmwcOTnOfBv2t1jgZ1ddqk9O71/9YZ7T5vClldez8EL+lCtMpBirNJZJwFj39xRAozLya2o0CrI0diyjEg==",
|
||||
"version": "13.6.6",
|
||||
"resolved": "https://registry.npmjs.org/release-it/-/release-it-13.6.6.tgz",
|
||||
"integrity": "sha512-tR0RkcMxc0lhtnPGWE2tBcjAG7Z+NXsQZTGiNr6M/XM5tOL4cSkWPrBo9+vEtVS2S7XlBiLtCZ85jCzcovBnBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@iarna/toml": "2.2.5",
|
||||
"@octokit/rest": "18.0.0",
|
||||
"@octokit/rest": "18.0.3",
|
||||
"async-retry": "1.3.1",
|
||||
"chalk": "4.1.0",
|
||||
"cosmiconfig": "6.0.0",
|
||||
@@ -10996,15 +10996,15 @@
|
||||
"form-data": "3.0.0",
|
||||
"git-url-parse": "11.1.2",
|
||||
"globby": "11.0.1",
|
||||
"got": "11.5.0",
|
||||
"got": "11.5.1",
|
||||
"import-cwd": "3.0.0",
|
||||
"inquirer": "7.3.0",
|
||||
"inquirer": "7.3.3",
|
||||
"is-ci": "2.0.0",
|
||||
"lodash": "4.17.19",
|
||||
"mime-types": "2.1.27",
|
||||
"ora": "4.0.4",
|
||||
"ora": "4.0.5",
|
||||
"os-name": "3.1.0",
|
||||
"parse-json": "5.0.0",
|
||||
"parse-json": "5.0.1",
|
||||
"semver": "7.3.2",
|
||||
"shelljs": "0.8.4",
|
||||
"supports-color": "7.1.0",
|
||||
@@ -11131,21 +11131,6 @@
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
@@ -11156,9 +11141,9 @@
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
|
||||
"integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz",
|
||||
"integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
@@ -11328,9 +11313,9 @@
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.22.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.22.1.tgz",
|
||||
"integrity": "sha512-K9AUQUCJkVqC+A7uUDacfhmpEeAjc2uOmSpvGI5xaYsm8pXgy4ZWEM8wHPfKj11xvCwFZppkRDo8a0RESJXCnw==",
|
||||
"version": "2.23.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.23.0.tgz",
|
||||
"integrity": "sha512-vLNmZFUGVwrnqNAJ/BvuLk1MtWzu4IuoqsH9UWK5AIdO3rt8/CSiJNvPvCIvfzrbNsqKbNzPAG1V2O4eTe2XZg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fsevents": "~2.1.2"
|
||||
@@ -11581,9 +11566,9 @@
|
||||
}
|
||||
},
|
||||
"rollup-plugin-serve": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-serve/-/rollup-plugin-serve-1.0.2.tgz",
|
||||
"integrity": "sha512-kootBwjS+Fez68cjFrJvFVskfUG4IbOmXE4uT3S9rz6T3NSWvw+Ie7jDqn+JQFmfVeTh6498ZzigTwPOxNYfKQ==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-serve/-/rollup-plugin-serve-1.0.3.tgz",
|
||||
"integrity": "sha512-DziGAVsXQVzQuT1v4vcv2l0GURnGYsX8m/FV1XzZ18VG3PWSedLaOSQFiW6RLHF7jB/F+CxlwK4YCUVZs8vxbg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime": ">=2.0.3",
|
||||
@@ -12406,13 +12391,10 @@
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz",
|
||||
"integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-name": "^3.1.0"
|
||||
}
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
|
||||
"dev": true
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
|
||||
+6
-6
@@ -25,9 +25,9 @@
|
||||
"release": "release-it"
|
||||
},
|
||||
"dependencies": {
|
||||
"@welldone-software/why-did-you-render": "^4.2.6",
|
||||
"@welldone-software/why-did-you-render": "^4.2.7",
|
||||
"classcat": "^4.1.0",
|
||||
"d3-selection": "^1.4.1",
|
||||
"d3-selection": "^1.4.2",
|
||||
"d3-zoom": "^1.8.3",
|
||||
"easy-peasy": "^3.3.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -46,13 +46,13 @@
|
||||
"autoprefixer": "^9.8.5",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-preset-react-app": "^9.1.2",
|
||||
"cypress": "^4.10.0",
|
||||
"cypress": "^4.11.0",
|
||||
"postcss-nested": "^4.2.3",
|
||||
"prettier": "2.0.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
"release-it": "^13.6.5",
|
||||
"rollup": "^2.22.1",
|
||||
"release-it": "^13.6.6",
|
||||
"rollup": "^2.23.0",
|
||||
"rollup-plugin-babel": "^4.4.0",
|
||||
"rollup-plugin-bundle-size": "^1.0.3",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
@@ -61,7 +61,7 @@
|
||||
"rollup-plugin-peer-deps-external": "^2.2.3",
|
||||
"rollup-plugin-postcss": "^3.1.3",
|
||||
"rollup-plugin-replace": "^2.2.0",
|
||||
"rollup-plugin-serve": "^1.0.2",
|
||||
"rollup-plugin-serve": "^1.0.3",
|
||||
"rollup-plugin-terser": "^6.1.0",
|
||||
"rollup-plugin-typescript2": "^0.27.1",
|
||||
"rollup-plugin-uglify": "^6.0.4",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import cc from 'classcat';
|
||||
|
||||
import { useStoreState, useStoreActions } from '../../store/hooks';
|
||||
@@ -17,46 +17,48 @@ interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
showInteractive?: boolean;
|
||||
}
|
||||
|
||||
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||
const fitView = useStoreActions((actions) => actions.fitView);
|
||||
const zoomIn = useStoreActions((actions) => actions.zoomIn);
|
||||
const zoomOut = useStoreActions((actions) => actions.zoomOut);
|
||||
const Controls = memo(
|
||||
({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||
const fitView = useStoreActions((actions) => actions.fitView);
|
||||
const zoomIn = useStoreActions((actions) => actions.zoomIn);
|
||||
const zoomOut = useStoreActions((actions) => actions.zoomOut);
|
||||
|
||||
const isInteractive = useStoreState((s) => s.nodesDraggable && s.nodesConnectable && s.elementsSelectable);
|
||||
const mapClasses = cc(['react-flow__controls', className]);
|
||||
const isInteractive = useStoreState((s) => s.nodesDraggable && s.nodesConnectable && s.elementsSelectable);
|
||||
const mapClasses = cc(['react-flow__controls', className]);
|
||||
|
||||
return (
|
||||
<div className={mapClasses} style={style}>
|
||||
{showZoom && (
|
||||
<>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={() => zoomIn()}>
|
||||
<PlusIcon />
|
||||
return (
|
||||
<div className={mapClasses} style={style}>
|
||||
{showZoom && (
|
||||
<>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={() => zoomIn()}>
|
||||
<PlusIcon />
|
||||
</div>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomout" onClick={() => zoomOut()}>
|
||||
<MinusIcon />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{showFitView && (
|
||||
<div
|
||||
className="react-flow__controls-button react-flow__controls-fitview"
|
||||
onClick={() => fitView({ padding: 0.1 })}
|
||||
>
|
||||
<FitviewIcon />
|
||||
</div>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomout" onClick={() => zoomOut()}>
|
||||
<MinusIcon />
|
||||
)}
|
||||
{showInteractive && (
|
||||
<div
|
||||
className="react-flow__controls-button react-flow__controls-interactive"
|
||||
onClick={() => setInteractive(!isInteractive)}
|
||||
>
|
||||
{isInteractive ? <UnlockIcon /> : <LockIcon />}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{showFitView && (
|
||||
<div
|
||||
className="react-flow__controls-button react-flow__controls-fitview"
|
||||
onClick={() => fitView({ padding: 0.1 })}
|
||||
>
|
||||
<FitviewIcon />
|
||||
</div>
|
||||
)}
|
||||
{showInteractive && (
|
||||
<div
|
||||
className="react-flow__controls-button react-flow__controls-interactive"
|
||||
onClick={() => setInteractive(!isInteractive)}
|
||||
>
|
||||
{isInteractive ? <UnlockIcon /> : <LockIcon />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Controls.displayName = 'Controls';
|
||||
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Node } from '../../types';
|
||||
import React, { memo, CSSProperties } from 'react';
|
||||
|
||||
interface MiniMapNodeProps {
|
||||
node: Node;
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
color: string;
|
||||
borderRadius: number;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const MiniMapNode = ({ node, color, borderRadius }: MiniMapNodeProps) => {
|
||||
const {
|
||||
position: { x, y },
|
||||
width,
|
||||
height,
|
||||
} = node.__rf;
|
||||
const { background, backgroundColor } = node.style || {};
|
||||
const MiniMapNode = memo(({ x, y, width, height, style, color, borderRadius }: MiniMapNodeProps) => {
|
||||
const { background, backgroundColor } = style || {};
|
||||
const fill = (color || background || backgroundColor) as string;
|
||||
|
||||
return (
|
||||
@@ -29,7 +26,7 @@ const MiniMapNode = ({ node, color, borderRadius }: MiniMapNodeProps) => {
|
||||
fill={fill}
|
||||
/>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
MiniMapNode.displayName = 'MiniMapNode';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import cc from 'classcat';
|
||||
|
||||
import { useStoreState } from '../../store/hooks';
|
||||
@@ -19,65 +19,76 @@ interface MiniMapProps extends React.HTMLAttributes<SVGSVGElement> {
|
||||
const defaultWidth = 200;
|
||||
const defaultHeight = 150;
|
||||
|
||||
const MiniMap = ({
|
||||
style = { backgroundColor: '#f8f8f8' },
|
||||
className,
|
||||
nodeColor = '#ddd',
|
||||
nodeBorderRadius = 5,
|
||||
maskColor = 'rgba(10, 10, 10, .25)',
|
||||
}: MiniMapProps) => {
|
||||
const containerWidth = useStoreState((s) => s.width);
|
||||
const containerHeight = useStoreState((s) => s.height);
|
||||
const [tX, tY, tScale] = useStoreState((s) => s.transform);
|
||||
const nodes = useStoreState((s) => s.nodes);
|
||||
const MiniMap = memo(
|
||||
({
|
||||
style = { backgroundColor: '#f8f8f8' },
|
||||
className,
|
||||
nodeColor = '#ddd',
|
||||
nodeBorderRadius = 5,
|
||||
maskColor = 'rgba(10, 10, 10, .25)',
|
||||
}: MiniMapProps) => {
|
||||
const containerWidth = useStoreState((s) => s.width);
|
||||
const containerHeight = useStoreState((s) => s.height);
|
||||
const [tX, tY, tScale] = useStoreState((s) => s.transform);
|
||||
const nodes = useStoreState((s) => s.nodes);
|
||||
|
||||
const mapClasses = cc(['react-flow__minimap', className]);
|
||||
const elementWidth = (style.width || defaultWidth)! as number;
|
||||
const elementHeight = (style.height || defaultHeight)! as number;
|
||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
||||
const hasNodes = nodes && nodes.length;
|
||||
const bb = getRectOfNodes(nodes);
|
||||
const viewBB: Rect = {
|
||||
x: -tX / tScale,
|
||||
y: -tY / tScale,
|
||||
width: containerWidth / tScale,
|
||||
height: containerHeight / tScale,
|
||||
};
|
||||
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
||||
const scaledWidth = boundingRect.width / elementWidth;
|
||||
const scaledHeight = boundingRect.height / elementHeight;
|
||||
const viewScale = Math.max(scaledWidth, scaledHeight);
|
||||
const viewWidth = viewScale * elementWidth;
|
||||
const viewHeight = viewScale * elementHeight;
|
||||
const offset = 5 * viewScale;
|
||||
const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset;
|
||||
const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset;
|
||||
const width = viewWidth + offset * 2;
|
||||
const height = viewHeight + offset * 2;
|
||||
const mapClasses = cc(['react-flow__minimap', className]);
|
||||
const elementWidth = (style.width || defaultWidth)! as number;
|
||||
const elementHeight = (style.height || defaultHeight)! as number;
|
||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
||||
const hasNodes = nodes && nodes.length;
|
||||
const bb = getRectOfNodes(nodes);
|
||||
const viewBB: Rect = {
|
||||
x: -tX / tScale,
|
||||
y: -tY / tScale,
|
||||
width: containerWidth / tScale,
|
||||
height: containerHeight / tScale,
|
||||
};
|
||||
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
||||
const scaledWidth = boundingRect.width / elementWidth;
|
||||
const scaledHeight = boundingRect.height / elementHeight;
|
||||
const viewScale = Math.max(scaledWidth, scaledHeight);
|
||||
const viewWidth = viewScale * elementWidth;
|
||||
const viewHeight = viewScale * elementHeight;
|
||||
const offset = 5 * viewScale;
|
||||
const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset;
|
||||
const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset;
|
||||
const width = viewWidth + offset * 2;
|
||||
const height = viewHeight + offset * 2;
|
||||
|
||||
return (
|
||||
<svg
|
||||
width={elementWidth}
|
||||
height={elementHeight}
|
||||
viewBox={`${x} ${y} ${width} ${height}`}
|
||||
style={style}
|
||||
className={mapClasses}
|
||||
>
|
||||
{nodes
|
||||
.filter((node) => !node.isHidden)
|
||||
.map((node) => (
|
||||
<MiniMapNode key={node.id} node={node} color={nodeColorFunc(node)} borderRadius={nodeBorderRadius} />
|
||||
))}
|
||||
<path
|
||||
className="react-flow__minimap-mask"
|
||||
d={`M${x - offset},${y - offset}h${width + offset * 2}v${height + offset * 2}h${-width - offset * 2}z
|
||||
return (
|
||||
<svg
|
||||
width={elementWidth}
|
||||
height={elementHeight}
|
||||
viewBox={`${x} ${y} ${width} ${height}`}
|
||||
style={style}
|
||||
className={mapClasses}
|
||||
>
|
||||
{nodes
|
||||
.filter((node) => !node.isHidden)
|
||||
.map((node) => (
|
||||
<MiniMapNode
|
||||
key={node.id}
|
||||
x={node.__rf.position.x}
|
||||
y={node.__rf.position.y}
|
||||
width={node.__rf.width}
|
||||
height={node.__rf.height}
|
||||
style={node.style}
|
||||
color={nodeColorFunc(node)}
|
||||
borderRadius={nodeBorderRadius}
|
||||
/>
|
||||
))}
|
||||
<path
|
||||
className="react-flow__minimap-mask"
|
||||
d={`M${x - offset},${y - offset}h${width + offset * 2}v${height + offset * 2}h${-width - offset * 2}z
|
||||
M${viewBB.x},${viewBB.y}h${viewBB.width}v${viewBB.height}h${-viewBB.width}z`}
|
||||
fill={maskColor}
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
fill={maskColor}
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
MiniMap.displayName = 'MiniMap';
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ interface EdgeWrapperProps {
|
||||
selected: boolean;
|
||||
elementsSelectable: boolean;
|
||||
isHidden?: boolean;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||
@@ -38,6 +39,7 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||
labelBgStyle,
|
||||
className,
|
||||
isHidden,
|
||||
data,
|
||||
...rest
|
||||
}: EdgeWrapperProps) => {
|
||||
const setSelectedElements = useStoreActions((a) => a.setSelectedElements);
|
||||
@@ -76,6 +78,7 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||
labelStyle={labelStyle}
|
||||
labelShowBg={labelShowBg}
|
||||
labelBgStyle={labelBgStyle}
|
||||
data={data}
|
||||
{...rest}
|
||||
/>
|
||||
</g>
|
||||
|
||||
@@ -166,6 +166,7 @@ function renderEdge(
|
||||
key={edge.id}
|
||||
id={edge.id}
|
||||
type={edge.type}
|
||||
data={edge.data}
|
||||
onClick={props.onElementClick}
|
||||
selected={isSelected}
|
||||
animated={edge.animated}
|
||||
@@ -216,7 +217,7 @@ const EdgeRenderer = memo((props: EdgeRendererProps) => {
|
||||
<svg width={width} height={height} className="react-flow__edges">
|
||||
<MarkerDefinitions color={arrowHeadColor} />
|
||||
<g transform={transformStyle}>
|
||||
{edges.map((e: Edge) => renderEdge(e, props, nodes, selectedElements, elementsSelectable))}
|
||||
{edges.map((edge) => renderEdge(edge, props, nodes, selectedElements, elementsSelectable))}
|
||||
{renderConnectionLine && (
|
||||
<ConnectionLine
|
||||
nodes={nodes}
|
||||
|
||||
@@ -3,94 +3,122 @@ import isEqual from 'fast-deep-equal';
|
||||
|
||||
import { useStoreState, useStoreActions } from '../store/hooks';
|
||||
import { parseElement, isNode, isEdge } from '../utils/graph';
|
||||
import { Elements, Node, Edge } from '../types';
|
||||
import { Elements, Node, Edge, FlowElement } from '../types';
|
||||
|
||||
const useElementUpdater = (elements: Elements): void => {
|
||||
const stateNodes = useStoreState((s) => s.nodes);
|
||||
const stateEdges = useStoreState((s) => s.edges);
|
||||
|
||||
const setNodes = useStoreActions((a) => a.setNodes);
|
||||
const setEdges = useStoreActions((a) => a.setEdges);
|
||||
const useElementUpdater = (propElements: Elements): void => {
|
||||
const stateElements = useStoreState((s) => s.elements);
|
||||
const setElements = useStoreActions((a) => a.setElements);
|
||||
|
||||
useEffect(() => {
|
||||
const nextEdges: Edge[] = elements.filter(isEdge).map((e) => parseElement(e) as Edge);
|
||||
const nextNodes: Node[] = elements.filter(isNode).map((propNode) => {
|
||||
const existingNode = stateNodes.find((n) => n.id === propNode.id);
|
||||
const nextElements: Elements = propElements.map((propElement) => {
|
||||
const existingElement = stateElements.find((el) => el.id === propElement.id);
|
||||
|
||||
if (existingNode) {
|
||||
const data = !isEqual(existingNode.data, propNode.data)
|
||||
? { ...existingNode.data, ...propNode.data }
|
||||
: existingNode.data;
|
||||
if (existingElement) {
|
||||
const data = !isEqual(existingElement.data, propElement.data)
|
||||
? { ...existingElement.data, ...propElement.data }
|
||||
: existingElement.data;
|
||||
|
||||
const style = !isEqual(existingNode.style, propNode.style)
|
||||
? { ...existingNode.style, ...propNode.style }
|
||||
: existingNode.style;
|
||||
const style = !isEqual(existingElement.style, propElement.style)
|
||||
? { ...existingElement.style, ...propElement.style }
|
||||
: existingElement.style;
|
||||
|
||||
const className = existingNode.className === propNode.className ? existingNode.className : propNode.className;
|
||||
const isHidden = existingNode.isHidden === propNode.isHidden ? existingNode.isHidden : propNode.isHidden;
|
||||
const draggable = existingNode.draggable === propNode.draggable ? existingNode.draggable : propNode.draggable;
|
||||
const selectable =
|
||||
existingNode.selectable === propNode.selectable ? existingNode.selectable : propNode.selectable;
|
||||
const connectable =
|
||||
existingNode.connectable === propNode.connectable ? existingNode.connectable : propNode.connectable;
|
||||
|
||||
const positionChanged =
|
||||
existingNode.position.x !== propNode.position.x || existingNode.position.y !== propNode.position.y;
|
||||
|
||||
const nodeProps = {
|
||||
...existingNode,
|
||||
data,
|
||||
const elementProps = {
|
||||
...existingElement,
|
||||
};
|
||||
|
||||
if (positionChanged) {
|
||||
nodeProps.__rf = {
|
||||
...existingNode.__rf,
|
||||
position: propNode.position,
|
||||
};
|
||||
nodeProps.position = propNode.position;
|
||||
if (typeof data !== 'undefined') {
|
||||
elementProps.data = data;
|
||||
}
|
||||
|
||||
if (typeof style !== 'undefined') {
|
||||
nodeProps.style = style;
|
||||
elementProps.style = style;
|
||||
}
|
||||
|
||||
if (typeof className !== 'undefined') {
|
||||
nodeProps.className = className;
|
||||
if (typeof propElement.className !== 'undefined') {
|
||||
elementProps.className = propElement.className;
|
||||
}
|
||||
|
||||
if (typeof isHidden !== 'undefined') {
|
||||
nodeProps.isHidden = isHidden;
|
||||
if (typeof propElement.isHidden !== 'undefined') {
|
||||
elementProps.isHidden = propElement.isHidden;
|
||||
}
|
||||
|
||||
if (typeof draggable !== 'undefined') {
|
||||
nodeProps.draggable = draggable;
|
||||
}
|
||||
if (isNode(existingElement)) {
|
||||
const propNode = propElement as Node;
|
||||
const nodeProps = elementProps as Node;
|
||||
|
||||
if (typeof selectable !== 'undefined') {
|
||||
nodeProps.selectable = selectable;
|
||||
}
|
||||
const positionChanged =
|
||||
existingElement.position.x !== propNode.position.x || existingElement.position.y !== propNode.position.y;
|
||||
|
||||
if (typeof connectable !== 'undefined') {
|
||||
nodeProps.connectable = connectable;
|
||||
}
|
||||
if (positionChanged) {
|
||||
nodeProps.__rf = {
|
||||
...existingElement.__rf,
|
||||
position: propNode.position,
|
||||
};
|
||||
nodeProps.position = propNode.position;
|
||||
}
|
||||
|
||||
return nodeProps;
|
||||
if (typeof propNode.draggable !== 'undefined') {
|
||||
nodeProps.draggable = propNode.draggable;
|
||||
}
|
||||
|
||||
if (typeof propNode.selectable !== 'undefined') {
|
||||
nodeProps.selectable = propNode.selectable;
|
||||
}
|
||||
|
||||
if (typeof propNode.connectable !== 'undefined') {
|
||||
nodeProps.connectable = propNode.connectable;
|
||||
}
|
||||
|
||||
return nodeProps;
|
||||
} else if (isEdge(existingElement)) {
|
||||
const propEdge = propElement as Edge;
|
||||
const edgeProps = elementProps as Edge;
|
||||
|
||||
const labelStyle = !isEqual(existingElement.labelStyle, propEdge.labelStyle)
|
||||
? { ...existingElement.labelStyle, ...propEdge.labelStyle }
|
||||
: existingElement.labelStyle;
|
||||
|
||||
const labelBgStyle = !isEqual(existingElement.labelBgStyle, propEdge.labelBgStyle)
|
||||
? { ...existingElement.labelBgStyle, ...propEdge.labelBgStyle }
|
||||
: existingElement.labelBgStyle;
|
||||
|
||||
if (typeof propEdge.label !== 'undefined') {
|
||||
edgeProps.label = propEdge.label;
|
||||
}
|
||||
|
||||
if (typeof labelStyle !== 'undefined') {
|
||||
edgeProps.labelStyle = labelStyle;
|
||||
}
|
||||
|
||||
if (typeof propEdge.labelShowBg !== 'undefined') {
|
||||
edgeProps.labelShowBg = propEdge.labelShowBg;
|
||||
}
|
||||
|
||||
if (typeof labelBgStyle !== 'undefined') {
|
||||
edgeProps.labelBgStyle = labelBgStyle;
|
||||
}
|
||||
|
||||
if (typeof propEdge.animated !== 'undefined') {
|
||||
edgeProps.animated = propEdge.animated;
|
||||
}
|
||||
|
||||
if (typeof propEdge.arrowHeadType !== 'undefined') {
|
||||
edgeProps.arrowHeadType = propEdge.arrowHeadType;
|
||||
}
|
||||
|
||||
return edgeProps;
|
||||
}
|
||||
}
|
||||
|
||||
return parseElement(propNode) as Node;
|
||||
return parseElement(propElement) as FlowElement;
|
||||
});
|
||||
|
||||
const nodesChanged: boolean = !isEqual(stateNodes, nextNodes);
|
||||
const edgesChanged: boolean = !isEqual(stateEdges, nextEdges);
|
||||
const elementsChanged: boolean = !isEqual(stateElements, nextElements);
|
||||
|
||||
if (nodesChanged) {
|
||||
setNodes(nextNodes);
|
||||
if (elementsChanged) {
|
||||
setElements(nextElements);
|
||||
}
|
||||
|
||||
if (edgesChanged) {
|
||||
setEdges(nextEdges);
|
||||
}
|
||||
}, [elements, stateNodes, stateEdges]);
|
||||
}, [propElements, stateElements]);
|
||||
};
|
||||
|
||||
export default useElementUpdater;
|
||||
|
||||
+15
-19
@@ -1,4 +1,4 @@
|
||||
import { createStore, Action, action, Thunk, thunk } from 'easy-peasy';
|
||||
import { createStore, Action, action, Thunk, thunk, computed, Computed } from 'easy-peasy';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
||||
import { zoom, zoomIdentity } from 'd3-zoom';
|
||||
@@ -7,7 +7,7 @@ import { select } from 'd3-selection';
|
||||
import { getDimensions, clamp } from '../utils';
|
||||
import { getHandleBounds } from '../components/Nodes/utils';
|
||||
|
||||
import { getNodesInside, getConnectedEdges, getRectOfNodes } from '../utils/graph';
|
||||
import { getNodesInside, getConnectedEdges, getRectOfNodes, isNode, isEdge } from '../utils/graph';
|
||||
import {
|
||||
ElementId,
|
||||
Elements,
|
||||
@@ -55,8 +55,9 @@ export interface StoreModel {
|
||||
width: number;
|
||||
height: number;
|
||||
transform: Transform;
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
elements: Elements;
|
||||
nodes: Computed<StoreModel, Node[]>;
|
||||
edges: Computed<StoreModel, Edge[]>;
|
||||
selectedElements: Elements | null;
|
||||
selectedNodesBbox: Rect;
|
||||
|
||||
@@ -89,9 +90,7 @@ export interface StoreModel {
|
||||
|
||||
setOnConnect: Action<StoreModel, OnConnectFunc>;
|
||||
|
||||
setNodes: Action<StoreModel, Node[]>;
|
||||
|
||||
setEdges: Action<StoreModel, Edge[]>;
|
||||
setElements: Action<StoreModel, Elements>;
|
||||
|
||||
updateNodeDimensions: Action<StoreModel, NodeDimensionUpdate>;
|
||||
|
||||
@@ -138,8 +137,9 @@ export const storeModel: StoreModel = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
transform: [0, 0, 1],
|
||||
nodes: [],
|
||||
edges: [],
|
||||
elements: [],
|
||||
nodes: computed([(state) => state.elements], (elements) => elements.filter((el) => isNode(el)) as Node[]),
|
||||
edges: computed([(state) => state.elements], (elements) => elements.filter((el) => isEdge(el)) as Edge[]),
|
||||
selectedElements: null,
|
||||
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
||||
|
||||
@@ -181,12 +181,8 @@ export const storeModel: StoreModel = {
|
||||
state.onConnect = onConnect;
|
||||
}),
|
||||
|
||||
setNodes: action((state, nodes) => {
|
||||
state.nodes = nodes;
|
||||
}),
|
||||
|
||||
setEdges: action((state, edges) => {
|
||||
state.edges = edges;
|
||||
setElements: action((state, elements) => {
|
||||
state.elements = elements;
|
||||
}),
|
||||
|
||||
updateNodeDimensions: action((state, { id, nodeElement }) => {
|
||||
@@ -207,8 +203,8 @@ export const storeModel: StoreModel = {
|
||||
target: getHandleBounds('.target', nodeElement, bounds, state.transform[2]),
|
||||
};
|
||||
|
||||
state.nodes.forEach((n) => {
|
||||
if (n.id === id) {
|
||||
state.elements.forEach((n) => {
|
||||
if (n.id === id && isNode(n)) {
|
||||
n.__rf = {
|
||||
...n.__rf,
|
||||
...dimensions,
|
||||
@@ -230,8 +226,8 @@ export const storeModel: StoreModel = {
|
||||
};
|
||||
}
|
||||
|
||||
state.nodes.forEach((n) => {
|
||||
if (n.id === id) {
|
||||
state.elements.forEach((n) => {
|
||||
if (n.id === id && isNode(n)) {
|
||||
n.__rf = {
|
||||
...n.__rf,
|
||||
position,
|
||||
|
||||
+7
-1
@@ -2,7 +2,9 @@ import { CSSProperties, MouseEvent } from 'react';
|
||||
|
||||
export type ElementId = string;
|
||||
|
||||
export type Elements = Array<Node | Edge>;
|
||||
export type FlowElement = Node | Edge;
|
||||
|
||||
export type Elements = Array<FlowElement>;
|
||||
|
||||
export type Transform = [number, number, number];
|
||||
|
||||
@@ -64,6 +66,8 @@ export interface Edge {
|
||||
animated?: boolean;
|
||||
arrowHeadType?: ArrowHeadType;
|
||||
isHidden?: boolean;
|
||||
data?: any;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export enum BackgroundVariant {
|
||||
@@ -95,6 +99,7 @@ export interface EdgeProps {
|
||||
style?: CSSProperties;
|
||||
arrowHeadType?: ArrowHeadType;
|
||||
markerEndId?: string;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface EdgeBezierProps extends EdgeProps {
|
||||
@@ -227,6 +232,7 @@ export interface EdgeCompProps {
|
||||
onClick?: (edge: Edge) => void;
|
||||
animated?: boolean;
|
||||
selected?: boolean;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface EdgeTextProps {
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ export const project = (position: XYPosition): XYPosition => {
|
||||
|
||||
export const parseElement = (element: Node | Edge): Node | Edge => {
|
||||
if (!element.id) {
|
||||
throw new Error('All elements (nodes and edges) need to have an id.');
|
||||
throw new Error('All nodes and edges need to have an id.');
|
||||
}
|
||||
|
||||
if (isEdge(element)) {
|
||||
|
||||
Reference in New Issue
Block a user