From 726bc2e0b3eecda2dbf8c6b001574939e21da006 Mon Sep 17 00:00:00 2001 From: Joey Ballentine Date: Sat, 12 Mar 2022 14:33:41 -0500 Subject: [PATCH 1/4] Add Unreal Engine style bezier edge --- CONTRIBUTING.md | 2 +- example/package-lock.json | 476 +++++---------------- example/src/index.tsx | 46 +- src/components/Edges/QuarticBezierEdge.tsx | 105 +++++ src/components/Edges/index.ts | 3 +- src/container/EdgeRenderer/utils.ts | 19 +- src/container/ReactFlow/index.tsx | 40 +- src/types/edges.ts | 7 +- 8 files changed, 260 insertions(+), 438 deletions(-) create mode 100644 src/components/Edges/QuarticBezierEdge.tsx diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 71e694c9..ecc8e16c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,5 +27,5 @@ Please use a meaningful commit message and add a little description of your chan 1. Install dependencies `npm install` and example dependencies `cd example && npm install` 2. Run library start task `npm start` and example start task `cd example && npm start` -3. No you can test your changes with the exisiting examples. Feel free to add a new one if it's needed for your changes +3. Now you can test your changes with the existing examples. Feel free to add a new one if it's needed for your changes 4. Run tests `npm test` and add new ones if you are introducing a new feature diff --git a/example/package-lock.json b/example/package-lock.json index 3e210183..3967ea69 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -27,7 +27,7 @@ }, "..": { "name": "react-flow-renderer", - "version": "10.0.0-next.38", + "version": "10.0.0-next.51", "license": "MIT", "dependencies": { "@babel/runtime": "^7.16.7", @@ -43,7 +43,6 @@ "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", - "@rollup/plugin-alias": "^3.1.9", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-node-resolve": "^13.1.3", @@ -63,7 +62,6 @@ "react-dom": "^17.0.2", "release-it": "^14.12.4", "rollup": "^2.66.1", - "rollup-plugin-bundle-size": "^1.0.3", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-serve": "^1.1.0", @@ -1982,20 +1980,6 @@ "@octokit/openapi-types": "^11.2.0" } }, - "../node_modules/@rollup/plugin-alias": { - "version": "3.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, "../node_modules/@rollup/plugin-babel": { "version": "5.3.0", "dev": true, @@ -4616,18 +4600,6 @@ "pend": "~1.2.0" } }, - "../node_modules/figures": { - "version": "1.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "../node_modules/fill-range": { "version": "7.0.1", "dev": true, @@ -4966,17 +4938,6 @@ "dev": true, "license": "ISC" }, - "../node_modules/gzip-size": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "duplexer": "^0.1.1" - }, - "engines": { - "node": ">=0.12.0" - } - }, "../node_modules/has": { "version": "1.0.3", "dev": true, @@ -4988,25 +4949,6 @@ "node": ">= 0.4.0" } }, - "../node_modules/has-ansi": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "../node_modules/has-flag": { "version": "3.0.0", "dev": true, @@ -6051,81 +5993,6 @@ "version": "0.1.0", "dev": true }, - "../node_modules/maxmin": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^1.0.0", - "figures": "^1.0.1", - "gzip-size": "^3.0.0", - "pretty-bytes": "^3.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "../node_modules/maxmin/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/maxmin/node_modules/ansi-styles": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/maxmin/node_modules/chalk": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/maxmin/node_modules/pretty-bytes": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/maxmin/node_modules/strip-ansi": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/maxmin/node_modules/supports-color": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "../node_modules/mdn-data": { "version": "2.0.14", "dev": true, @@ -6331,14 +6198,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "../node_modules/number-is-nan": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "../node_modules/object-assign": { "version": "4.1.1", "license": "MIT", @@ -8312,65 +8171,6 @@ "fsevents": "~2.3.2" } }, - "../node_modules/rollup-plugin-bundle-size": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^1.1.3", - "maxmin": "^2.1.0" - } - }, - "../node_modules/rollup-plugin-bundle-size/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/rollup-plugin-bundle-size/node_modules/ansi-styles": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/rollup-plugin-bundle-size/node_modules/chalk": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/rollup-plugin-bundle-size/node_modules/strip-ansi": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../node_modules/rollup-plugin-bundle-size/node_modules/supports-color": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "../node_modules/rollup-plugin-livereload": { "version": "2.0.5", "dev": true, @@ -28148,12 +27948,14 @@ "acorn-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "requires": {} }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "requires": {} }, "acorn-node": { "version": "1.8.2", @@ -28248,7 +28050,8 @@ "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} }, "ansi-escapes": { "version": "4.3.2", @@ -28541,7 +28344,8 @@ "babel-plugin-named-asset-import": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==" + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "requires": {} }, "babel-plugin-polyfill-corejs2": { "version": "0.3.1", @@ -29235,7 +29039,8 @@ "css-prefers-color-scheme": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==" + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "requires": {} }, "css-select": { "version": "2.1.0", @@ -29323,7 +29128,8 @@ "cssnano-utils": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.2.tgz", - "integrity": "sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ==" + "integrity": "sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ==", + "requires": {} }, "csso": { "version": "4.2.0", @@ -30175,7 +29981,8 @@ "eslint-plugin-react-hooks": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", - "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==" + "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "requires": {} }, "eslint-plugin-testing-library": { "version": "5.0.5", @@ -31081,7 +30888,8 @@ "icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} }, "idb": { "version": "6.1.5", @@ -32077,7 +31885,8 @@ "jest-pnp-resolver": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==" + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "requires": {} }, "jest-regex-util": { "version": "27.5.1", @@ -33575,7 +33384,8 @@ "postcss-browser-comments": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==" + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "requires": {} }, "postcss-calc": { "version": "8.2.4", @@ -33640,7 +33450,8 @@ "postcss-custom-media": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz", - "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==" + "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==", + "requires": {} }, "postcss-custom-properties": { "version": "12.1.4", @@ -33669,22 +33480,26 @@ "postcss-discard-comments": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.3.tgz", - "integrity": "sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q==" + "integrity": "sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q==", + "requires": {} }, "postcss-discard-duplicates": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.3.tgz", - "integrity": "sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw==" + "integrity": "sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw==", + "requires": {} }, "postcss-discard-empty": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.3.tgz", - "integrity": "sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA==" + "integrity": "sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA==", + "requires": {} }, "postcss-discard-overridden": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.4.tgz", - "integrity": "sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg==" + "integrity": "sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg==", + "requires": {} }, "postcss-double-position-gradients": { "version": "3.0.5", @@ -33705,7 +33520,8 @@ "postcss-flexbugs-fixes": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==" + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "requires": {} }, "postcss-focus-visible": { "version": "6.0.4", @@ -33726,12 +33542,14 @@ "postcss-font-variant": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==" + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "requires": {} }, "postcss-gap-properties": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz", - "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==" + "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==", + "requires": {} }, "postcss-image-set-function": { "version": "4.0.6", @@ -33744,7 +33562,8 @@ "postcss-initial": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==" + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "requires": {} }, "postcss-js": { "version": "4.0.0", @@ -33784,12 +33603,14 @@ "postcss-logical": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==" + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "requires": {} }, "postcss-media-minmax": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==" + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "requires": {} }, "postcss-merge-longhand": { "version": "5.0.6", @@ -33850,7 +33671,8 @@ "postcss-modules-extract-imports": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==" + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -33907,7 +33729,8 @@ "postcss-normalize-charset": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.3.tgz", - "integrity": "sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA==" + "integrity": "sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA==", + "requires": {} }, "postcss-normalize-display-values": { "version": "5.0.3", @@ -33992,12 +33815,14 @@ "postcss-overflow-shorthand": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz", - "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==" + "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==", + "requires": {} }, "postcss-page-break": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==" + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "requires": {} }, "postcss-place": { "version": "7.0.4", @@ -34080,7 +33905,8 @@ "postcss-replace-overflow-wrap": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==" + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "requires": {} }, "postcss-selector-not": { "version": "5.0.0", @@ -34505,7 +34331,6 @@ "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", "@babel/runtime": "^7.16.7", - "@rollup/plugin-alias": "^3.1.9", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-node-resolve": "^13.1.3", @@ -34529,7 +34354,6 @@ "react-draggable": "^4.4.4", "release-it": "^14.12.4", "rollup": "^2.66.1", - "rollup-plugin-bundle-size": "^1.0.3", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-serve": "^1.1.0", @@ -35674,7 +35498,8 @@ }, "@octokit/plugin-request-log": { "version": "1.0.4", - "dev": true + "dev": true, + "requires": {} }, "@octokit/plugin-rest-endpoint-methods": { "version": "5.13.0", @@ -35722,13 +35547,6 @@ "@octokit/openapi-types": "^11.2.0" } }, - "@rollup/plugin-alias": { - "version": "3.1.9", - "dev": true, - "requires": { - "slash": "^3.0.0" - } - }, "@rollup/plugin-babel": { "version": "5.3.0", "dev": true, @@ -35806,35 +35624,43 @@ }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-remove-jsx-attribute": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-remove-jsx-empty-expression": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-replace-jsx-attribute-value": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-svg-dynamic-title": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-svg-em-dimensions": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-transform-react-native-svg": { "version": "6.0.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-plugin-transform-svg-component": { "version": "6.2.0", - "dev": true + "dev": true, + "requires": {} }, "@svgr/babel-preset": { "version": "6.2.0", @@ -36930,7 +36756,8 @@ }, "cssnano-utils": { "version": "2.0.1", - "dev": true + "dev": true, + "requires": {} }, "csso": { "version": "4.2.0", @@ -37402,14 +37229,6 @@ "pend": "~1.2.0" } }, - "figures": { - "version": "1.7.0", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, "fill-range": { "version": "7.0.1", "dev": true, @@ -37613,13 +37432,6 @@ "version": "4.2.6", "dev": true }, - "gzip-size": { - "version": "3.0.0", - "dev": true, - "requires": { - "duplexer": "^0.1.1" - } - }, "has": { "version": "1.0.3", "dev": true, @@ -37627,19 +37439,6 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "dev": true - } - } - }, "has-flag": { "version": "3.0.0", "dev": true @@ -37690,7 +37489,8 @@ }, "icss-utils": { "version": "5.1.0", - "dev": true + "dev": true, + "requires": {} }, "ieee754": { "version": "1.2.1", @@ -38285,55 +38085,6 @@ "version": "0.1.0", "dev": true }, - "maxmin": { - "version": "2.1.0", - "dev": true, - "requires": { - "chalk": "^1.0.0", - "figures": "^1.0.1", - "gzip-size": "^3.0.0", - "pretty-bytes": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "pretty-bytes": { - "version": "3.0.1", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "dev": true - } - } - }, "mdn-data": { "version": "2.0.14", "dev": true @@ -38450,10 +38201,6 @@ "boolbase": "^1.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "dev": true - }, "object-assign": { "version": "4.1.1" }, @@ -38974,19 +38721,23 @@ }, "postcss-discard-comments": { "version": "5.0.1", - "dev": true + "dev": true, + "requires": {} }, "postcss-discard-duplicates": { "version": "5.0.1", - "dev": true + "dev": true, + "requires": {} }, "postcss-discard-empty": { "version": "5.0.1", - "dev": true + "dev": true, + "requires": {} }, "postcss-discard-overridden": { "version": "5.0.1", - "dev": true + "dev": true, + "requires": {} }, "postcss-load-config": { "version": "3.1.0", @@ -39068,7 +38819,8 @@ }, "postcss-modules-extract-imports": { "version": "3.0.0", - "dev": true + "dev": true, + "requires": {} }, "postcss-modules-local-by-default": { "version": "4.0.0", @@ -39102,7 +38854,8 @@ }, "postcss-normalize-charset": { "version": "5.0.1", - "dev": true + "dev": true, + "requires": {} }, "postcss-normalize-display-values": { "version": "5.0.1", @@ -39637,46 +39390,6 @@ "fsevents": "~2.3.2" } }, - "rollup-plugin-bundle-size": { - "version": "1.0.3", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "maxmin": "^2.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "dev": true - } - } - }, "rollup-plugin-livereload": { "version": "2.0.5", "dev": true, @@ -40499,7 +40212,8 @@ }, "ws": { "version": "7.5.0", - "dev": true + "dev": true, + "requires": {} }, "xdg-basedir": { "version": "4.0.0", @@ -40553,7 +40267,8 @@ "dev": true }, "zustand": { - "version": "3.6.9" + "version": "3.6.9", + "requires": {} } } }, @@ -41439,7 +41154,8 @@ "style-loader": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==" + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "requires": {} }, "stylehacks": { "version": "5.0.3", @@ -42186,7 +41902,8 @@ "ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==" + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "requires": {} } } }, @@ -42612,7 +42329,8 @@ "ws": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==" + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "requires": {} }, "xml-name-validator": { "version": "3.0.0", diff --git a/example/src/index.tsx b/example/src/index.tsx index 7119f09f..1208c967 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -1,40 +1,40 @@ import { ChangeEvent } from 'react'; import ReactDOM from 'react-dom'; -import { BrowserRouter, Route, Routes, useNavigate, useLocation } from 'react-router-dom'; - -import Overview from './Overview'; +import { BrowserRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import Basic from './Basic'; -import UpdateNode from './UpdateNode'; -import Stress from './Stress'; -import CustomNode from './CustomNode'; -import FloatingEdges from './FloatingEdges'; -import Layouting from './Layouting'; -import NestedNodes from './NestedNodes'; -import Hidden from './Hidden'; -import UpdatableEdge from './UpdatableEdge'; -import TouchDevice from './TouchDevice'; -import Subflow from './Subflow'; -import Interaction from './Interaction'; -import Empty from './Empty'; -import DragHandle from './DragHandle'; -import Undirectional from './Undirectional'; -import Provider from './Provider'; +import ControlledUncontrolled from './ControlledUncontrolled'; import CustomConnectionLine from './CustomConnectionLine'; -import UseZoomPanHelper from './UseZoomPanHelper'; +import CustomNode from './CustomNode'; +import DefaultNodes from './DefaultNodes'; +import DragHandle from './DragHandle'; import DragNDrop from './DragNDrop'; -import UseUpdateNodeInternals from './UseUpdateNodeInternals'; import Edges from './Edges'; import EdgeTypes from './EdgeTypes'; +import Empty from './Empty'; +import FloatingEdges from './FloatingEdges'; +import Hidden from './Hidden'; +import './index.css'; +import Interaction from './Interaction'; +import Layouting from './Layouting'; import MultiFlows from './MultiFlows'; +import NestedNodes from './NestedNodes'; import NodeTypeChange from './NodeTypeChange'; import NodeTypesObjectChange from './NodeTypesObjectChange'; +import Overview from './Overview'; +import Provider from './Provider'; import SaveRestore from './SaveRestore'; +import Stress from './Stress'; +import Subflow from './Subflow'; import SwitchFlow from './Switch'; +import TouchDevice from './TouchDevice'; +import Undirectional from './Undirectional'; +import UpdatableEdge from './UpdatableEdge'; +import UpdateNode from './UpdateNode'; +import UseUpdateNodeInternals from './UseUpdateNodeInternals'; +import UseZoomPanHelper from './UseZoomPanHelper'; import Validation from './Validation'; -import DefaultNodes from './DefaultNodes'; -import ControlledUncontrolled from './ControlledUncontrolled'; -import './index.css'; + const routes = [ { diff --git a/src/components/Edges/QuarticBezierEdge.tsx b/src/components/Edges/QuarticBezierEdge.tsx new file mode 100644 index 00000000..1d0a4492 --- /dev/null +++ b/src/components/Edges/QuarticBezierEdge.tsx @@ -0,0 +1,105 @@ +import React, { memo } from 'react'; +import { EdgeProps, Position } from '../../types'; +import EdgeText from './EdgeText'; +import { getCenter } from './utils'; + + +interface GetBezierPathParams { + sourceX: number; + sourceY: number; + sourcePosition?: Position; + targetX: number; + targetY: number; + targetPosition?: Position; + curvature?: number; +} + +export function getQuarticBezierPath({ + sourceX, + sourceY, + sourcePosition = Position.Bottom, + targetX, + targetY, + targetPosition = Position.Top, + curvature = 0.5 +}: GetBezierPathParams): string { + const leftAndRight = [Position.Left, Position.Right]; + + // Distance between the source and target + const distanceX = sourceX - targetX; + // A scalar value to fix the curve size getting larger + const scalar = Math.min(curvature, Math.max(0, distanceX / 10000)); + + const cX = sourceX + Math.abs(targetX - sourceX) * (curvature - scalar); + const cY = targetX - Math.abs(targetX - sourceX) * (curvature - scalar); + + let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; + + if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { + path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; + } else if (leftAndRight.includes(targetPosition)) { + path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; + } else if (leftAndRight.includes(sourcePosition)) { + path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; + } + + return path; +} + +export default memo( + ({ + sourceX, + sourceY, + targetX, + targetY, + sourcePosition = Position.Bottom, + targetPosition = Position.Top, + label, + labelStyle, + labelShowBg, + labelBgStyle, + labelBgPadding, + labelBgBorderRadius, + style, + markerEnd, + markerStart, + curvature, + }: EdgeProps) => { + const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); + const path = getQuarticBezierPath({ + sourceX, + sourceY, + sourcePosition, + targetX, + targetY, + targetPosition, + curvature, + }); + + const text = label ? ( + + ) : null; + + return ( + <> + + {text} + + ); + } +); diff --git a/src/components/Edges/index.ts b/src/components/Edges/index.ts index 65beb017..508fe21e 100644 --- a/src/components/Edges/index.ts +++ b/src/components/Edges/index.ts @@ -1,4 +1,5 @@ export { default as BezierEdge } from './BezierEdge'; -export { default as StepEdge } from './StepEdge'; +export { default as QuarticBezierEdge } from './QuarticBezierEdge'; export { default as SmoothStepEdge } from './SmoothStepEdge'; +export { default as StepEdge } from './StepEdge'; export { default as StraightEdge } from './StraightEdge'; diff --git a/src/container/EdgeRenderer/utils.ts b/src/container/EdgeRenderer/utils.ts index dac372ee..3f2e22be 100644 --- a/src/container/EdgeRenderer/utils.ts +++ b/src/container/EdgeRenderer/utils.ts @@ -1,20 +1,18 @@ import { ComponentType } from 'react'; - -import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges'; +import { BezierEdge, QuarticBezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../../components/Edges'; import wrapEdge from '../../components/Edges/wrapEdge'; -import { rectToBox } from '../../utils'; - import { - EdgeTypes, EdgeProps, + EdgeTypes, HandleElement, - Position, - XYPosition, - Transform, - Rect, - NodeInternals, NodeHandleBounds, + NodeInternals, + Position, + Rect, + Transform, + XYPosition, } from '../../types'; +import { rectToBox } from '../../utils'; export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypes; @@ -24,6 +22,7 @@ export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypes { straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType), step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType), smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdge) as ComponentType), + quartic: wrapEdge((edgeTypes.quartic || QuarticBezierEdge) as ComponentType), }; const wrappedTypes = {} as EdgeTypes; diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index 222075b9..43a8734b 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -1,31 +1,28 @@ -import React, { forwardRef } from 'react'; import cc from 'classcat'; - -import GraphView from '../GraphView'; -import StoreUpdater from '../../components/StoreUpdater'; +import React, { forwardRef } from 'react'; +import Attribution from '../../components/Attribution'; +import { BezierEdge, QuarticBezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../../components/Edges'; import DefaultNode from '../../components/Nodes/DefaultNode'; import InputNode from '../../components/Nodes/InputNode'; import OutputNode from '../../components/Nodes/OutputNode'; -import { createNodeTypes } from '../NodeRenderer/utils'; import SelectionListener from '../../components/SelectionListener'; -import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges'; -import Attribution from '../../components/Attribution'; -import { createEdgeTypes } from '../EdgeRenderer/utils'; -import Wrapper from './Wrapper'; -import injectStyle, { useNodeOrEdgeTypes } from './utils'; - -import { - ConnectionMode, - ConnectionLineType, - PanOnScrollMode, - ReactFlowProps, - ReactFlowRefType, - NodeTypes, - EdgeTypes, -} from '../../types'; - +import StoreUpdater from '../../components/StoreUpdater'; import css from '../../style.css'; import theme from '../../theme-default.css'; +import { + ConnectionLineType, ConnectionMode, EdgeTypes, NodeTypes, PanOnScrollMode, + ReactFlowProps, + ReactFlowRefType +} from '../../types'; +import { createEdgeTypes } from '../EdgeRenderer/utils'; +import GraphView from '../GraphView'; +import { createNodeTypes } from '../NodeRenderer/utils'; +import injectStyle, { useNodeOrEdgeTypes } from './utils'; +import Wrapper from './Wrapper'; + + + + if (__INJECT_STYLES__) { injectStyle(css as unknown as string); @@ -43,6 +40,7 @@ const defaultEdgeTypes = { straight: StraightEdge, step: StepEdge, smoothstep: SmoothStepEdge, + quartic: QuarticBezierEdge, }; const initSnapGrid: [number, number] = [15, 15]; diff --git a/src/types/edges.ts b/src/types/edges.ts index 56500c37..48757d7f 100644 --- a/src/types/edges.ts +++ b/src/types/edges.ts @@ -1,9 +1,9 @@ -import { CSSProperties, ReactNode, HTMLAttributes } from 'react'; - -import { Position } from './utils'; +import { CSSProperties, HTMLAttributes, ReactNode } from 'react'; import { Connection } from './general'; import { HandleElement } from './handles'; import { Node } from './nodes'; +import { Position } from './utils'; + // interface for the user edge items export interface Edge { @@ -62,6 +62,7 @@ export interface EdgeProps { targetHandleId?: string | null; markerStart?: string; markerEnd?: string; + curvature?: number; } export type EdgeMouseHandler = (event: React.MouseEvent, edge: Edge) => void; From 3c96b07c9c27d328ea070b5571690d2d77ffe108 Mon Sep 17 00:00:00 2001 From: Joey Ballentine Date: Mon, 14 Mar 2022 00:56:23 -0400 Subject: [PATCH 2/4] Rename to "unreal" edge, fix for both horizontal and vertical handles --- example/src/EdgeTypes/utils.ts | 8 ++++---- example/src/Edges/index.tsx | 19 +++++------------- ...ticBezierEdge.tsx => UnrealBezierEdge.tsx} | 20 ++++++++++++------- src/components/Edges/index.ts | 2 +- src/container/EdgeRenderer/utils.ts | 4 ++-- src/container/ReactFlow/index.tsx | 4 ++-- 6 files changed, 27 insertions(+), 30 deletions(-) rename src/components/Edges/{QuarticBezierEdge.tsx => UnrealBezierEdge.tsx} (71%) diff --git a/example/src/EdgeTypes/utils.ts b/example/src/EdgeTypes/utils.ts index 22896aa0..3c679060 100644 --- a/example/src/EdgeTypes/utils.ts +++ b/example/src/EdgeTypes/utils.ts @@ -1,4 +1,4 @@ -import { Node, Edge, Position } from 'react-flow-renderer'; +import { Edge, Node, Position } from 'react-flow-renderer'; const nodeWidth = 80; const nodeGapWidth = nodeWidth * 2; @@ -9,10 +9,10 @@ const sourceTargetPositions = [ { source: Position.Right, target: Position.Left }, ]; const nodeColors = [ - ['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'], - ['#0f4c75', '#1b5d8b', '#276fa1', '#3282b8'], + ['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4', '#c4fff7'], + ['#0f4c75', '#1b5d8b', '#276fa1', '#3282b8', '#4fa6e0'], ]; -const edgeTypes = ['default', 'step', 'smoothstep', 'straight']; +const edgeTypes = ['default', 'step', 'smoothstep', 'straight', 'unreal']; const offsets = [ { x: 0, diff --git a/example/src/Edges/index.tsx b/example/src/Edges/index.tsx index d6e0a83d..6d7b9b08 100644 --- a/example/src/Edges/index.tsx +++ b/example/src/Edges/index.tsx @@ -1,23 +1,12 @@ import { MouseEvent } from 'react'; - import ReactFlow, { - addEdge, - MiniMap, - Controls, - Background, - ReactFlowInstance, - EdgeTypes, - Connection, - Edge, - MarkerType, - Node, - useNodesState, - useEdgesState, + addEdge, Background, Connection, Controls, Edge, EdgeTypes, MarkerType, MiniMap, Node, ReactFlowInstance, useEdgesState, useNodesState } from 'react-flow-renderer'; - import CustomEdge from './CustomEdge'; import CustomEdge2 from './CustomEdge2'; + + const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView(); const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); @@ -26,6 +15,7 @@ const initialNodes: Node[] = [ { id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } }, { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } }, { id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } }, + { id: '2b', data: { label: 'Node 2b' }, position: { x: -80, y: 100 } }, { id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } }, { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } }, { id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } }, @@ -39,6 +29,7 @@ const initialNodes: Node[] = [ const initialEdges: Edge[] = [ { id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)', className: 'normal-edge' }, { id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' }, + { id: 'e2a-2b', source: '2a', target: '2b', type: 'unreal', label: 'unreal bezier edge', className: 'unreal-edge' }, { id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' }, { id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' }, { id: 'e3-3a', source: '3', target: '3a', type: 'straight', label: 'label only edge', style: { stroke: 'none' } }, diff --git a/src/components/Edges/QuarticBezierEdge.tsx b/src/components/Edges/UnrealBezierEdge.tsx similarity index 71% rename from src/components/Edges/QuarticBezierEdge.tsx rename to src/components/Edges/UnrealBezierEdge.tsx index 1d0a4492..c4bc04fc 100644 --- a/src/components/Edges/QuarticBezierEdge.tsx +++ b/src/components/Edges/UnrealBezierEdge.tsx @@ -14,7 +14,7 @@ interface GetBezierPathParams { curvature?: number; } -export function getQuarticBezierPath({ +export function getUnrealBezierPath({ sourceX, sourceY, sourcePosition = Position.Bottom, @@ -27,16 +27,22 @@ export function getQuarticBezierPath({ // Distance between the source and target const distanceX = sourceX - targetX; + const distanceY = sourceY - targetY; + // A scalar value to fix the curve size getting larger - const scalar = Math.min(curvature, Math.max(0, distanceX / 10000)); + const scalarX = Math.min(curvature, Math.max(0, distanceX / 10000)); + const scalarY = Math.min(curvature, Math.max(0, distanceY / 10000)); - const cX = sourceX + Math.abs(targetX - sourceX) * (curvature - scalar); - const cY = targetX - Math.abs(targetX - sourceX) * (curvature - scalar); + const hx1 = sourceX + Math.abs(targetX - sourceX) * (curvature - scalarX); + const hx2 = targetX - Math.abs(targetX - sourceX) * (curvature - scalarX); - let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; + const hy1 = sourceY + Math.abs(targetY - sourceY) * (curvature - scalarY); + const hy2 = targetY - Math.abs(targetY - sourceY) * (curvature - scalarY); + + let path = `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}`; if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; + path = `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}`; } else if (leftAndRight.includes(targetPosition)) { path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(sourcePosition)) { @@ -66,7 +72,7 @@ export default memo( curvature, }: EdgeProps) => { const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); - const path = getQuarticBezierPath({ + const path = getUnrealBezierPath({ sourceX, sourceY, sourcePosition, diff --git a/src/components/Edges/index.ts b/src/components/Edges/index.ts index 508fe21e..727f889b 100644 --- a/src/components/Edges/index.ts +++ b/src/components/Edges/index.ts @@ -1,5 +1,5 @@ export { default as BezierEdge } from './BezierEdge'; -export { default as QuarticBezierEdge } from './QuarticBezierEdge'; export { default as SmoothStepEdge } from './SmoothStepEdge'; export { default as StepEdge } from './StepEdge'; export { default as StraightEdge } from './StraightEdge'; +export { default as UnrealBezierEdge } from './UnrealBezierEdge'; diff --git a/src/container/EdgeRenderer/utils.ts b/src/container/EdgeRenderer/utils.ts index 3f2e22be..c00dd6aa 100644 --- a/src/container/EdgeRenderer/utils.ts +++ b/src/container/EdgeRenderer/utils.ts @@ -1,5 +1,5 @@ import { ComponentType } from 'react'; -import { BezierEdge, QuarticBezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../../components/Edges'; +import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, UnrealBezierEdge } from '../../components/Edges'; import wrapEdge from '../../components/Edges/wrapEdge'; import { EdgeProps, @@ -22,7 +22,7 @@ export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypes { straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType), step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType), smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdge) as ComponentType), - quartic: wrapEdge((edgeTypes.quartic || QuarticBezierEdge) as ComponentType), + unreal: wrapEdge((edgeTypes.unreal || UnrealBezierEdge) as ComponentType), }; const wrappedTypes = {} as EdgeTypes; diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index 43a8734b..d5a6ea38 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -1,7 +1,7 @@ import cc from 'classcat'; import React, { forwardRef } from 'react'; import Attribution from '../../components/Attribution'; -import { BezierEdge, QuarticBezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../../components/Edges'; +import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, UnrealBezierEdge } from '../../components/Edges'; import DefaultNode from '../../components/Nodes/DefaultNode'; import InputNode from '../../components/Nodes/InputNode'; import OutputNode from '../../components/Nodes/OutputNode'; @@ -40,7 +40,7 @@ const defaultEdgeTypes = { straight: StraightEdge, step: StepEdge, smoothstep: SmoothStepEdge, - quartic: QuarticBezierEdge, + unreal: UnrealBezierEdge, }; const initSnapGrid: [number, number] = [15, 15]; From b362c1185174fdb3fcecaca0c975464dadd9c3e5 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 14 Mar 2022 16:01:00 +0100 Subject: [PATCH 3/4] refactor(edges): use new edge as default, add simplebezier --- example/src/EdgeTypes/utils.ts | 2 +- example/src/Edges/index.tsx | 28 ++- src/components/ConnectionLine/index.tsx | 2 +- src/components/Edges/BezierEdge.tsx | 211 ++++++++--------- ...ealBezierEdge.tsx => SimpleBezierEdge.tsx} | 212 +++++++++--------- src/components/Edges/index.ts | 4 +- src/container/EdgeRenderer/utils.ts | 4 +- src/container/ReactFlow/index.tsx | 16 +- src/index.ts | 2 +- 9 files changed, 248 insertions(+), 233 deletions(-) rename src/components/Edges/{UnrealBezierEdge.tsx => SimpleBezierEdge.tsx} (65%) diff --git a/example/src/EdgeTypes/utils.ts b/example/src/EdgeTypes/utils.ts index 3c679060..a6d898d7 100644 --- a/example/src/EdgeTypes/utils.ts +++ b/example/src/EdgeTypes/utils.ts @@ -12,7 +12,7 @@ const nodeColors = [ ['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4', '#c4fff7'], ['#0f4c75', '#1b5d8b', '#276fa1', '#3282b8', '#4fa6e0'], ]; -const edgeTypes = ['default', 'step', 'smoothstep', 'straight', 'unreal']; +const edgeTypes = ['default', 'step', 'smoothstep', 'straight', 'simplebezier']; const offsets = [ { x: 0, diff --git a/example/src/Edges/index.tsx b/example/src/Edges/index.tsx index 6d7b9b08..d527ae45 100644 --- a/example/src/Edges/index.tsx +++ b/example/src/Edges/index.tsx @@ -1,12 +1,22 @@ import { MouseEvent } from 'react'; import ReactFlow, { - addEdge, Background, Connection, Controls, Edge, EdgeTypes, MarkerType, MiniMap, Node, ReactFlowInstance, useEdgesState, useNodesState + addEdge, + Background, + Connection, + Controls, + Edge, + EdgeTypes, + MarkerType, + MiniMap, + Node, + Position, + ReactFlowInstance, + useEdgesState, + useNodesState, } from 'react-flow-renderer'; import CustomEdge from './CustomEdge'; import CustomEdge2 from './CustomEdge2'; - - const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView(); const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); @@ -15,7 +25,7 @@ const initialNodes: Node[] = [ { id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } }, { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } }, { id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } }, - { id: '2b', data: { label: 'Node 2b' }, position: { x: -80, y: 100 } }, + { id: '2b', data: { label: 'Node 2b' }, position: { x: -80, y: 100 }, targetPosition: Position.Left }, { id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } }, { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } }, { id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } }, @@ -29,7 +39,13 @@ const initialNodes: Node[] = [ const initialEdges: Edge[] = [ { id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)', className: 'normal-edge' }, { id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' }, - { id: 'e2a-2b', source: '2a', target: '2b', type: 'unreal', label: 'unreal bezier edge', className: 'unreal-edge' }, + { + id: 'e2a-2b', + source: '2a', + target: '2b', + type: 'simplebezier', + label: 'simple bezier edge', + }, { id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' }, { id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' }, { id: 'e3-3a', source: '3', target: '3a', type: 'straight', label: 'label only edge', style: { stroke: 'none' } }, @@ -99,7 +115,7 @@ const edgeTypes: EdgeTypes = { }; const EdgesFlow = () => { - const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); + const [nodes, , onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)); diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index f3839442..0654a4b4 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -2,7 +2,7 @@ import React, { useRef, CSSProperties } from 'react'; import shallow from 'zustand/shallow'; import { useStore } from '../../store'; -import { getBezierPath } from '../Edges/BezierEdge'; +import { getBezierPath } from '../Edges/SimpleBezierEdge'; import { getSmoothStepPath } from '../Edges/SmoothStepEdge'; import { HandleElement, diff --git a/src/components/Edges/BezierEdge.tsx b/src/components/Edges/BezierEdge.tsx index 7edb5a42..9daf07bb 100644 --- a/src/components/Edges/BezierEdge.tsx +++ b/src/components/Edges/BezierEdge.tsx @@ -1,101 +1,110 @@ -import React, { memo } from 'react'; - -import EdgeText from './EdgeText'; -import { getCenter } from './utils'; -import { EdgeProps, Position } from '../../types'; - -interface GetBezierPathParams { - sourceX: number; - sourceY: number; - sourcePosition?: Position; - targetX: number; - targetY: number; - targetPosition?: Position; - centerX?: number; - centerY?: number; -} - -export function getBezierPath({ - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - centerX, - centerY, -}: GetBezierPathParams): string { - const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); - const leftAndRight = [Position.Left, Position.Right]; - - const cX = typeof centerX !== 'undefined' ? centerX : _centerX; - const cY = typeof centerY !== 'undefined' ? centerY : _centerY; - - let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; - - if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(sourcePosition)) { - path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; - } - - return path; -} - -export default memo( - ({ - sourceX, - sourceY, - targetX, - targetY, - sourcePosition = Position.Bottom, - targetPosition = Position.Top, - label, - labelStyle, - labelShowBg, - labelBgStyle, - labelBgPadding, - labelBgBorderRadius, - style, - markerEnd, - markerStart, - }: EdgeProps) => { - const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); - const path = getBezierPath({ - sourceX, - sourceY, - sourcePosition, - targetX, - targetY, - targetPosition, - }); - - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - - ); - } -); +import React, { memo } from 'react'; +import { EdgeProps, Position } from '../../types'; +import EdgeText from './EdgeText'; +import { getCenter } from './utils'; + +interface GetBezierPathParams { + sourceX: number; + sourceY: number; + sourcePosition?: Position; + targetX: number; + targetY: number; + targetPosition?: Position; + curvature?: number; +} + +export function getBezierPath({ + sourceX, + sourceY, + sourcePosition = Position.Bottom, + targetX, + targetY, + targetPosition = Position.Top, + curvature = 0.5, +}: GetBezierPathParams): string { + const leftAndRight = [Position.Left, Position.Right]; + + // Distance between the source and target + const distanceX = sourceX - targetX; + const distanceY = sourceY - targetY; + + // // A scalar value to fix the curve size getting larger + const scalarX = Math.min(curvature, Math.max(0, distanceX / 10000)); + const scalarY = Math.min(curvature, Math.max(0, distanceY / 10000)); + + const hx1 = sourceX + Math.abs(targetX - sourceX) * (curvature - scalarX); + const hx2 = targetX - Math.abs(targetX - sourceX) * (curvature - scalarX); + + const hy1 = sourceY + Math.abs(targetY - sourceY) * (curvature - scalarY); + const hy2 = targetY - Math.abs(targetY - sourceY) * (curvature - scalarY); + + let path = `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}`; + + if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { + path = `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}`; + } else if (leftAndRight.includes(targetPosition)) { + path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; + } else if (leftAndRight.includes(sourcePosition)) { + path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; + } + + return path; +} + +export default memo( + ({ + sourceX, + sourceY, + targetX, + targetY, + sourcePosition = Position.Bottom, + targetPosition = Position.Top, + label, + labelStyle, + labelShowBg, + labelBgStyle, + labelBgPadding, + labelBgBorderRadius, + style, + markerEnd, + markerStart, + curvature, + }: EdgeProps) => { + const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); + const path = getBezierPath({ + sourceX, + sourceY, + sourcePosition, + targetX, + targetY, + targetPosition, + curvature, + }); + + const text = label ? ( + + ) : null; + + return ( + <> + + {text} + + ); + } +); diff --git a/src/components/Edges/UnrealBezierEdge.tsx b/src/components/Edges/SimpleBezierEdge.tsx similarity index 65% rename from src/components/Edges/UnrealBezierEdge.tsx rename to src/components/Edges/SimpleBezierEdge.tsx index c4bc04fc..7edb5a42 100644 --- a/src/components/Edges/UnrealBezierEdge.tsx +++ b/src/components/Edges/SimpleBezierEdge.tsx @@ -1,111 +1,101 @@ -import React, { memo } from 'react'; -import { EdgeProps, Position } from '../../types'; -import EdgeText from './EdgeText'; -import { getCenter } from './utils'; - - -interface GetBezierPathParams { - sourceX: number; - sourceY: number; - sourcePosition?: Position; - targetX: number; - targetY: number; - targetPosition?: Position; - curvature?: number; -} - -export function getUnrealBezierPath({ - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - curvature = 0.5 -}: GetBezierPathParams): string { - const leftAndRight = [Position.Left, Position.Right]; - - // Distance between the source and target - const distanceX = sourceX - targetX; - const distanceY = sourceY - targetY; - - // A scalar value to fix the curve size getting larger - const scalarX = Math.min(curvature, Math.max(0, distanceX / 10000)); - const scalarY = Math.min(curvature, Math.max(0, distanceY / 10000)); - - const hx1 = sourceX + Math.abs(targetX - sourceX) * (curvature - scalarX); - const hx2 = targetX - Math.abs(targetX - sourceX) * (curvature - scalarX); - - const hy1 = sourceY + Math.abs(targetY - sourceY) * (curvature - scalarY); - const hy2 = targetY - Math.abs(targetY - sourceY) * (curvature - scalarY); - - let path = `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}`; - - if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}`; - } else if (leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(sourcePosition)) { - path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; - } - - return path; -} - -export default memo( - ({ - sourceX, - sourceY, - targetX, - targetY, - sourcePosition = Position.Bottom, - targetPosition = Position.Top, - label, - labelStyle, - labelShowBg, - labelBgStyle, - labelBgPadding, - labelBgBorderRadius, - style, - markerEnd, - markerStart, - curvature, - }: EdgeProps) => { - const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); - const path = getUnrealBezierPath({ - sourceX, - sourceY, - sourcePosition, - targetX, - targetY, - targetPosition, - curvature, - }); - - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - - ); - } -); +import React, { memo } from 'react'; + +import EdgeText from './EdgeText'; +import { getCenter } from './utils'; +import { EdgeProps, Position } from '../../types'; + +interface GetBezierPathParams { + sourceX: number; + sourceY: number; + sourcePosition?: Position; + targetX: number; + targetY: number; + targetPosition?: Position; + centerX?: number; + centerY?: number; +} + +export function getBezierPath({ + sourceX, + sourceY, + sourcePosition = Position.Bottom, + targetX, + targetY, + targetPosition = Position.Top, + centerX, + centerY, +}: GetBezierPathParams): string { + const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); + const leftAndRight = [Position.Left, Position.Right]; + + const cX = typeof centerX !== 'undefined' ? centerX : _centerX; + const cY = typeof centerY !== 'undefined' ? centerY : _centerY; + + let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; + + if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { + path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; + } else if (leftAndRight.includes(targetPosition)) { + path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; + } else if (leftAndRight.includes(sourcePosition)) { + path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; + } + + return path; +} + +export default memo( + ({ + sourceX, + sourceY, + targetX, + targetY, + sourcePosition = Position.Bottom, + targetPosition = Position.Top, + label, + labelStyle, + labelShowBg, + labelBgStyle, + labelBgPadding, + labelBgBorderRadius, + style, + markerEnd, + markerStart, + }: EdgeProps) => { + const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); + const path = getBezierPath({ + sourceX, + sourceY, + sourcePosition, + targetX, + targetY, + targetPosition, + }); + + const text = label ? ( + + ) : null; + + return ( + <> + + {text} + + ); + } +); diff --git a/src/components/Edges/index.ts b/src/components/Edges/index.ts index 727f889b..e4d30109 100644 --- a/src/components/Edges/index.ts +++ b/src/components/Edges/index.ts @@ -1,5 +1,5 @@ -export { default as BezierEdge } from './BezierEdge'; +export { default as SimpleBezierEdge } from './SimpleBezierEdge'; export { default as SmoothStepEdge } from './SmoothStepEdge'; export { default as StepEdge } from './StepEdge'; export { default as StraightEdge } from './StraightEdge'; -export { default as UnrealBezierEdge } from './UnrealBezierEdge'; +export { default as BezierEdge } from './BezierEdge'; diff --git a/src/container/EdgeRenderer/utils.ts b/src/container/EdgeRenderer/utils.ts index c00dd6aa..450995e2 100644 --- a/src/container/EdgeRenderer/utils.ts +++ b/src/container/EdgeRenderer/utils.ts @@ -1,5 +1,5 @@ import { ComponentType } from 'react'; -import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, UnrealBezierEdge } from '../../components/Edges'; +import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges'; import wrapEdge from '../../components/Edges/wrapEdge'; import { EdgeProps, @@ -22,7 +22,7 @@ export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypes { straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType), step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType), smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdge) as ComponentType), - unreal: wrapEdge((edgeTypes.unreal || UnrealBezierEdge) as ComponentType), + simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdge) as ComponentType), }; const wrappedTypes = {} as EdgeTypes; diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index d5a6ea38..0a133393 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -1,7 +1,7 @@ import cc from 'classcat'; import React, { forwardRef } from 'react'; import Attribution from '../../components/Attribution'; -import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, UnrealBezierEdge } from '../../components/Edges'; +import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges'; import DefaultNode from '../../components/Nodes/DefaultNode'; import InputNode from '../../components/Nodes/InputNode'; import OutputNode from '../../components/Nodes/OutputNode'; @@ -10,9 +10,13 @@ import StoreUpdater from '../../components/StoreUpdater'; import css from '../../style.css'; import theme from '../../theme-default.css'; import { - ConnectionLineType, ConnectionMode, EdgeTypes, NodeTypes, PanOnScrollMode, + ConnectionLineType, + ConnectionMode, + EdgeTypes, + NodeTypes, + PanOnScrollMode, ReactFlowProps, - ReactFlowRefType + ReactFlowRefType, } from '../../types'; import { createEdgeTypes } from '../EdgeRenderer/utils'; import GraphView from '../GraphView'; @@ -20,10 +24,6 @@ import { createNodeTypes } from '../NodeRenderer/utils'; import injectStyle, { useNodeOrEdgeTypes } from './utils'; import Wrapper from './Wrapper'; - - - - if (__INJECT_STYLES__) { injectStyle(css as unknown as string); injectStyle(theme as unknown as string); @@ -40,7 +40,7 @@ const defaultEdgeTypes = { straight: StraightEdge, step: StepEdge, smoothstep: SmoothStepEdge, - unreal: UnrealBezierEdge, + simplebezier: SimpleBezierEdge, }; const initSnapGrid: [number, number] = [15, 15]; diff --git a/src/index.ts b/src/index.ts index 6f29e003..03a8a0ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ export { default as Handle } from './components/Handle'; export { default as EdgeText } from './components/Edges/EdgeText'; export { default as StraightEdge } from './components/Edges/StraightEdge'; export { default as StepEdge } from './components/Edges/StepEdge'; -export { default as BezierEdge, getBezierPath } from './components/Edges/BezierEdge'; +export { default as BezierEdge, getBezierPath } from './components/Edges/SimpleBezierEdge'; export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge'; export * from './additional-components'; From bc5d1df10e24b55e4d1a91ab79e6aa9fcd417dec Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 14 Mar 2022 16:27:44 +0100 Subject: [PATCH 4/4] refactor(edges): add BaseEdge --- example/src/Edges/index.tsx | 2 +- src/components/ConnectionLine/index.tsx | 5 +- src/components/Edges/BaseEdge.tsx | 39 ++++++++ src/components/Edges/BezierEdge.tsx | 58 ++++++------ src/components/Edges/SimpleBezierEdge.tsx | 103 ++-------------------- src/components/Edges/SmoothStepEdge.tsx | 29 +++--- src/components/Edges/StraightEdge.tsx | 28 +++--- src/index.ts | 3 +- src/types/edges.ts | 19 +++- 9 files changed, 124 insertions(+), 162 deletions(-) create mode 100644 src/components/Edges/BaseEdge.tsx diff --git a/example/src/Edges/index.tsx b/example/src/Edges/index.tsx index d527ae45..35d6aaa4 100644 --- a/example/src/Edges/index.tsx +++ b/example/src/Edges/index.tsx @@ -25,7 +25,7 @@ const initialNodes: Node[] = [ { id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } }, { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } }, { id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } }, - { id: '2b', data: { label: 'Node 2b' }, position: { x: -80, y: 100 }, targetPosition: Position.Left }, + { id: '2b', data: { label: 'Node 2b' }, position: { x: -40, y: 300 } }, { id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } }, { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } }, { id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } }, diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index 0654a4b4..4a4db773 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -2,7 +2,7 @@ import React, { useRef, CSSProperties } from 'react'; import shallow from 'zustand/shallow'; import { useStore } from '../../store'; -import { getBezierPath } from '../Edges/SimpleBezierEdge'; +import { getBezierPath } from '../Edges/BezierEdge'; import { getSmoothStepPath } from '../Edges/SmoothStepEdge'; import { HandleElement, @@ -13,6 +13,7 @@ import { ReactFlowState, Position, } from '../../types'; +import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge'; interface ConnectionLineProps { connectionNodeId: string; @@ -112,6 +113,8 @@ export default ({ }); } else if (connectionLineType === ConnectionLineType.SmoothStep) { dAttr = getSmoothStepPath(pathParams); + } else if (connectionLineType === ConnectionLineType.SimpleBezier) { + dAttr = getSimpleBezierPath(pathParams); } else { dAttr = `M${sourceX},${sourceY} ${targetX},${targetY}`; } diff --git a/src/components/Edges/BaseEdge.tsx b/src/components/Edges/BaseEdge.tsx new file mode 100644 index 00000000..19d0ab37 --- /dev/null +++ b/src/components/Edges/BaseEdge.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import EdgeText from './EdgeText'; +import { BaseEdgeProps } from '../../types'; + +export default ({ + path, + centerX, + centerY, + label, + labelStyle, + labelShowBg, + labelBgStyle, + labelBgPadding, + labelBgBorderRadius, + style, + markerEnd, + markerStart, +}: BaseEdgeProps) => { + const text = label ? ( + + ) : null; + + return ( + <> + + {text} + + ); +}; diff --git a/src/components/Edges/BezierEdge.tsx b/src/components/Edges/BezierEdge.tsx index 9daf07bb..b3ab9047 100644 --- a/src/components/Edges/BezierEdge.tsx +++ b/src/components/Edges/BezierEdge.tsx @@ -1,9 +1,10 @@ import React, { memo } from 'react'; -import { EdgeProps, Position } from '../../types'; -import EdgeText from './EdgeText'; -import { getCenter } from './utils'; -interface GetBezierPathParams { +import BaseEdge from './BaseEdge'; +import { getCenter } from './utils'; +import { EdgeProps, Position } from '../../types'; + +export interface GetBezierPathParams { sourceX: number; sourceY: number; sourcePosition?: Position; @@ -11,6 +12,8 @@ interface GetBezierPathParams { targetY: number; targetPosition?: Position; curvature?: number; + centerX?: number; + centerY?: number; } export function getBezierPath({ @@ -21,14 +24,24 @@ export function getBezierPath({ targetY, targetPosition = Position.Top, curvature = 0.5, + centerX, + centerY, }: GetBezierPathParams): string { const leftAndRight = [Position.Left, Position.Right]; + const hasCurvature = curvature > 0; + let cX, + cY = 0; + + if (!hasCurvature) { + const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); + cX = typeof centerX !== 'undefined' ? centerX : _centerX; + cY = typeof centerY !== 'undefined' ? centerY : _centerY; + } - // Distance between the source and target const distanceX = sourceX - targetX; const distanceY = sourceY - targetY; - // // A scalar value to fix the curve size getting larger + // A scalar value to fix the curve size getting larger const scalarX = Math.min(curvature, Math.max(0, distanceX / 10000)); const scalarY = Math.min(curvature, Math.max(0, distanceY / 10000)); @@ -38,10 +51,14 @@ export function getBezierPath({ const hy1 = sourceY + Math.abs(targetY - sourceY) * (curvature - scalarY); const hy2 = targetY - Math.abs(targetY - sourceY) * (curvature - scalarY); - let path = `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}`; + let path = hasCurvature + ? `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}` + : `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}`; + path = hasCurvature + ? `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}` + : `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(targetPosition)) { path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(sourcePosition)) { @@ -81,30 +98,21 @@ export default memo( curvature, }); - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - ); } ); diff --git a/src/components/Edges/SimpleBezierEdge.tsx b/src/components/Edges/SimpleBezierEdge.tsx index 7edb5a42..1bc671c9 100644 --- a/src/components/Edges/SimpleBezierEdge.tsx +++ b/src/components/Edges/SimpleBezierEdge.tsx @@ -1,101 +1,12 @@ import React, { memo } from 'react'; -import EdgeText from './EdgeText'; -import { getCenter } from './utils'; -import { EdgeProps, Position } from '../../types'; +import BezierEdge, { getBezierPath, GetBezierPathParams } from './BezierEdge'; +import { EdgeProps } from '../../types'; -interface GetBezierPathParams { - sourceX: number; - sourceY: number; - sourcePosition?: Position; - targetX: number; - targetY: number; - targetPosition?: Position; - centerX?: number; - centerY?: number; +export function getSimpleBezierPath(props: GetBezierPathParams): string { + return getBezierPath({ ...props, curvature: 0 }); } -export function getBezierPath({ - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - centerX, - centerY, -}: GetBezierPathParams): string { - const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); - const leftAndRight = [Position.Left, Position.Right]; - - const cX = typeof centerX !== 'undefined' ? centerX : _centerX; - const cY = typeof centerY !== 'undefined' ? centerY : _centerY; - - let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; - - if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(sourcePosition)) { - path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; - } - - return path; -} - -export default memo( - ({ - sourceX, - sourceY, - targetX, - targetY, - sourcePosition = Position.Bottom, - targetPosition = Position.Top, - label, - labelStyle, - labelShowBg, - labelBgStyle, - labelBgPadding, - labelBgBorderRadius, - style, - markerEnd, - markerStart, - }: EdgeProps) => { - const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); - const path = getBezierPath({ - sourceX, - sourceY, - sourcePosition, - targetX, - targetY, - targetPosition, - }); - - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - - ); - } -); +export default memo((props: EdgeProps) => { + return ; +}); diff --git a/src/components/Edges/SmoothStepEdge.tsx b/src/components/Edges/SmoothStepEdge.tsx index 0736683a..4eb1ba6b 100644 --- a/src/components/Edges/SmoothStepEdge.tsx +++ b/src/components/Edges/SmoothStepEdge.tsx @@ -1,8 +1,8 @@ import React, { memo } from 'react'; -import EdgeText from './EdgeText'; import { getCenter } from './utils'; import { EdgeSmoothStepProps, Position } from '../../types'; +import BaseEdge from './BaseEdge'; // These are some helper methods for drawing the round corners // The name indicates the direction of the path. "bottomLeftCorner" goes @@ -21,7 +21,7 @@ const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${ const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}`; const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}`; -interface GetSmoothStepPathParams { +export interface GetSmoothStepPathParams { sourceX: number; sourceY: number; sourcePosition?: Position; @@ -146,30 +146,21 @@ export default memo( borderRadius, }); - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - ); } ); diff --git a/src/components/Edges/StraightEdge.tsx b/src/components/Edges/StraightEdge.tsx index b7f0fac1..45357615 100644 --- a/src/components/Edges/StraightEdge.tsx +++ b/src/components/Edges/StraightEdge.tsx @@ -1,6 +1,6 @@ import React, { memo } from 'react'; -import EdgeText from './EdgeText'; +import BaseEdge from './BaseEdge'; import { EdgeProps } from '../../types'; export default memo( @@ -24,31 +24,23 @@ export default memo( const xOffset = Math.abs(targetX - sourceX) / 2; const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset; + const path = `M ${sourceX},${sourceY}L ${targetX},${targetY}`; - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - ); } ); diff --git a/src/index.ts b/src/index.ts index 03a8a0ef..826673c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,8 @@ export { default as Handle } from './components/Handle'; export { default as EdgeText } from './components/Edges/EdgeText'; export { default as StraightEdge } from './components/Edges/StraightEdge'; export { default as StepEdge } from './components/Edges/StepEdge'; -export { default as BezierEdge, getBezierPath } from './components/Edges/SimpleBezierEdge'; +export { default as BezierEdge, getBezierPath } from './components/Edges/BezierEdge'; +export { default as SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge'; export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge'; export * from './additional-components'; diff --git a/src/types/edges.ts b/src/types/edges.ts index 48757d7f..2f83eac7 100644 --- a/src/types/edges.ts +++ b/src/types/edges.ts @@ -4,7 +4,6 @@ import { HandleElement } from './handles'; import { Node } from './nodes'; import { Position } from './utils'; - // interface for the user edge items export interface Edge { id: string; @@ -65,6 +64,23 @@ export interface EdgeProps { curvature?: number; } +export type BaseEdgeProps = Pick< + EdgeProps, + | 'label' + | 'labelStyle' + | 'labelShowBg' + | 'labelBgStyle' + | 'labelBgPadding' + | 'labelBgBorderRadius' + | 'style' + | 'markerStart' + | 'markerEnd' +> & { + centerX: number; + centerY: number; + path: string; +}; + export type EdgeMouseHandler = (event: React.MouseEvent, edge: Edge) => void; export interface WrapEdgeProps { @@ -127,6 +143,7 @@ export enum ConnectionLineType { Straight = 'straight', Step = 'step', SmoothStep = 'smoothstep', + SimpleBezier = 'simplebezier', } export type ConnectionLineComponentProps = {