-
Notifications
You must be signed in to change notification settings - Fork 863
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(examples): add bezier-js integration example
- Loading branch information
1 parent
72eb5a4
commit 68e53dd
Showing
7 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build/ | ||
dist/ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# JointJS List Demo | ||
|
||
## Setup | ||
|
||
Use Yarn to run this demo. | ||
|
||
You need to build *JointJS* first. Navigate to the root folder and run: | ||
```bash | ||
yarn install | ||
yarn run build | ||
``` | ||
|
||
Navigate to this directory, then run: | ||
```bash | ||
yarn start | ||
``` | ||
|
||
## License | ||
|
||
The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). | ||
|
||
Copyright © 2013-2025 client IO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#paper-container { | ||
position: absolute; | ||
right: 0; | ||
top: 0; | ||
left: 0; | ||
bottom: 0; | ||
overflow: scroll; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"/> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> | ||
<meta name="description" content="The JointJS Bezier-JS example demo serves as a template to help bring your idea to life in no time."/> | ||
<title>Bezier JS Example | JointJS</title> | ||
</head> | ||
<body> | ||
<div id="paper-container"></div> | ||
<script src="dist/bundle.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "@joint/demo-bezier-js", | ||
"version": "4.1.3", | ||
"main": "src/index.js", | ||
"homepage": "https://jointjs.com", | ||
"author": { | ||
"name": "client IO", | ||
"url": "https://client.io" | ||
}, | ||
"license": "MPL-2.0", | ||
"private": true, | ||
"installConfig": { | ||
"hoistingLimits": "workspaces" | ||
}, | ||
"scripts": { | ||
"start": "webpack-dev-server", | ||
"tsc": "tsc" | ||
}, | ||
"dependencies": { | ||
"@joint/core": "workspace:^", | ||
"bezier-js": "^6.1.4" | ||
}, | ||
"devDependencies": { | ||
"css-loader": "3.5.3", | ||
"style-loader": "1.2.1", | ||
"webpack": "^5.61.0", | ||
"webpack-cli": "^4.8.0", | ||
"webpack-dev-server": "^4.2.1" | ||
}, | ||
"volta": { | ||
"node": "16.18.1", | ||
"npm": "8.19.2", | ||
"yarn": "3.4.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
import { dia, shapes, util, g, linkTools } from "@joint/core"; | ||
import { Bezier } from "bezier-js"; | ||
|
||
import "../css/bezier.css"; | ||
|
||
class BezierLinkView extends dia.LinkView { | ||
updateDOMSubtreeAttributes() { | ||
const method = this.model.get("outline") ? outlinePath : offsetPath; | ||
|
||
const thickness1 = 20; | ||
const thickness2 = 30; | ||
const thickness3 = 10; | ||
const fillOpacity = 0.3; | ||
const roundDecimals = 0; | ||
const strokeWidth = 2; | ||
const useFill = method !== offsetPath; | ||
|
||
const { line1, line2, line3 } = this.selectors; | ||
|
||
const path1 = this.getConnection(); | ||
path1.round(roundDecimals); | ||
line1.setAttribute("stroke", "red"); | ||
line1.setAttribute("stroke-width", strokeWidth); | ||
line1.setAttribute("fill", useFill ? "red" : "none"); | ||
line1.setAttribute("fill-opacity", fillOpacity); | ||
line1.setAttribute("fill-rule", "nonzero"); | ||
line1.setAttribute("d", method(path1, thickness1)); | ||
|
||
const path2 = new g.Path(offsetPath(path1, thickness1 + thickness2)); | ||
path2.round(roundDecimals); | ||
line2.setAttribute("stroke", "blue"); | ||
line2.setAttribute("stroke-width", strokeWidth); | ||
line2.setAttribute("fill", useFill ? "blue" : "none"); | ||
line2.setAttribute("fill-opacity", fillOpacity); | ||
line2.setAttribute("fill-rule", "nonzero"); | ||
line2.setAttribute("d", method(path2, thickness2)); | ||
|
||
const path3 = new g.Path(offsetPath(path1, -(thickness1 + thickness3))); | ||
path3.round(roundDecimals); | ||
line3.setAttribute("stroke", "green"); | ||
line3.setAttribute("stroke-width", strokeWidth); | ||
line3.setAttribute("fill", useFill ? "green" : "none"); | ||
line3.setAttribute("fill-opacity", fillOpacity); | ||
line3.setAttribute("fill-rule", "nonzero"); | ||
line3.setAttribute("d", method(path3, thickness3)); | ||
} | ||
} | ||
|
||
const graph = new dia.Graph({}, { cellNamespace: shapes }); | ||
const paper = new dia.Paper({ | ||
width: "100%", | ||
height: "100%", | ||
model: graph, | ||
overflow: true, | ||
cellViewNamespace: shapes, | ||
linkView: BezierLinkView, | ||
}); | ||
|
||
document.getElementById("paper-container").appendChild(paper.el); | ||
|
||
const link1 = new dia.Link({ | ||
type: "bezier", | ||
source: { x: 40, y: 100 }, | ||
target: { x: 740, y: 100 }, | ||
vertices: [{ x: 401, y: 208 }], | ||
// vertices: [{ x: 422, y: 417 }], // rounding issues | ||
// vertices: [{ x: 204, y: 63 }], // can not create offset | ||
connector: { name: "smooth" }, | ||
markup: util.svg` | ||
<path @selector="line1" /> | ||
<path @selector="line2" /> | ||
<path @selector="line3" /> | ||
`, | ||
}); | ||
|
||
const link2 = link1.clone().translate(0, 300).set("outline", true); | ||
graph.resetCells([link1, link2]); | ||
|
||
function offsetPath(path, offset) { | ||
const offsetBezierCurves = pathToBezierCurves(path) | ||
.map((bezier) => { | ||
const polyBezier = bezier.offset(offset); | ||
return polyBezier.map((b) => { | ||
if (isNaN(b.points[0].x)) { | ||
console.warn("Unable to create offset", bezier); | ||
return bezier; | ||
} | ||
return b; | ||
}); | ||
}) | ||
.flat(); | ||
let d = ""; | ||
for (let i = 0; i < offsetBezierCurves.length; i++) { | ||
d += offsetBezierCurves[i].toSVG(); | ||
} | ||
return d; | ||
} | ||
|
||
function outlinePath(path, o) { | ||
const outlines = pathToBezierCurves(path).map((curve1) => { | ||
let curves; | ||
try { | ||
curves = curve1.outline(o).curves; | ||
} catch (e) { | ||
console.warn("Caught exception in bezier-js", curve1); | ||
return curve1; | ||
} | ||
return curves.map((curve2) => { | ||
if (isNaN(curve2.points[0].x)) { | ||
console.warn("Unable to create outline", curve1); | ||
return curve1; | ||
} | ||
return curve2; | ||
}); | ||
}); | ||
let d = "M 0 0"; | ||
for (let i = 0; i < outlines.length; i++) { | ||
const outline = outlines[i]; | ||
for (let j = 0; j < outline.length; j++) { | ||
let segmentPath = outline[j].toSVG(); | ||
if (j > 0) { | ||
// Remove the first moveTo command | ||
let index = segmentPath.search(/[C,Q]/); | ||
if (index > 0) { | ||
segmentPath = segmentPath.slice(index); | ||
} | ||
} | ||
d += segmentPath; | ||
} | ||
} | ||
d += "Z"; | ||
return d; | ||
} | ||
|
||
function pathToBezierCurves(path) { | ||
const segments = path.segments; | ||
const bezierCurves = []; | ||
for (let i = 0; i < segments.length; i++) { | ||
const curve = segments[i]; | ||
// Note: JointJS path use only absolute commands | ||
// it's safe to ignore all | ||
if (curve.type === "M") continue; | ||
const { | ||
start, | ||
end, | ||
controlPoint1 = start, | ||
controlPoint2 = end, | ||
} = curve; | ||
const bezier = new Bezier( | ||
start.x, | ||
start.y, | ||
controlPoint1.x, | ||
controlPoint1.y, | ||
controlPoint2.x, | ||
controlPoint2.y, | ||
end.x, | ||
end.y | ||
); | ||
bezierCurves.push(bezier); | ||
} | ||
return bezierCurves; | ||
} | ||
|
||
// Interactions | ||
|
||
graph.getLinks().forEach((link) => { | ||
const tools = [ | ||
new linkTools.Vertices({ | ||
vertexAdding: true, | ||
redundancyRemoval: false, | ||
}), | ||
new linkTools.SourceArrowhead(), | ||
new linkTools.TargetArrowhead(), | ||
]; | ||
|
||
link.findView(paper).addTools( | ||
new dia.ToolsView({ | ||
tools: tools, | ||
}) | ||
); | ||
}); | ||
|
||
// Failing examples from bezier-js | ||
|
||
// const b1 = new Bezier(40, 100, 159, 323, 277, 545, 394, 545); | ||
// console.log(b1.outline(50)); | ||
// console.log(b1.outlineshapes(50)); | ||
|
||
// const b2 = new Bezier(100, 100, 100, 100, 200, 200, 200, 200); | ||
// console.log(b2.outline(50).curves); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const path = require('path'); | ||
|
||
module.exports = { | ||
resolve: { | ||
extensions: ['.js'] | ||
}, | ||
entry: './src/index.js', | ||
output: { | ||
filename: 'bundle.js', | ||
path: path.resolve(__dirname, 'dist'), | ||
publicPath: '/dist/' | ||
}, | ||
mode: 'development', | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.css$/, | ||
sideEffects: true, | ||
use: ['style-loader', 'css-loader'], | ||
} | ||
] | ||
}, | ||
devServer: { | ||
static: { | ||
directory: __dirname, | ||
}, | ||
compress: true | ||
}, | ||
}; |