I am playing around with JointJS and React. I am using this code (with some minor modifications)
I created 2 projects: (1) without and (2) with react.
In both cases I am able to render the graph with elements inside.
In the project that does not use react the 'collapse' works fine.
In the project that uses react the 'collapse' works to some extent: I can hide the subgraph but I cannot show it again. I am getting the following error in the console:
Uncaught Error: dia.ElementView: markup required
Below the code that I used in the 'react' project.
Declaration of 'GroupView' and adding the namespaces to the graph and paper didn't help.
import * as joint from "jointjs";
function GraphPage() {
useEffect(() => {
customElement();
}, []);
return <div id="paper"></div>;
}
function customElement() {
joint.shapes.example = {};
joint.shapes.example.Group = joint.dia.Element.define(
"example.Group",
{
size: {
width: 100,
height: 40,
},
attrs: {
body: {
refWidth: "100%",
refHeight: "100%",
fill: "white",
stroke: "black",
strokeWidth: 2,
},
tool: {
r: 10,
cx: 20,
cy: 20,
fill: "white",
stroke: "blue",
strokeWidth: 2,
cursor: "pointer",
event: "element:collapse",
},
},
},
{
markup: [
{
tagName: "rect",
selector: "body",
},
{
tagName: "circle",
selector: "tool",
},
],
}
);
joint.shapes.example.GroupView = joint.dia.ElementView;
var namespace = joint.shapes;
var graph = new joint.dia.Graph({}, { cellNamespace: namespace });
var paper = new joint.dia.Paper({
el: document.getElementById("paper"),
model: graph,
cellViewNamespace: namespace,
defaultConnectionPoint: { name: "boundary" },
defaultAnchor: { name: "center" },
});
// Setup
var e1 = new joint.shapes.example.Group();
e1.position(100, 100);
var a1 = new joint.shapes.standard.Rectangle();
var a2 = new joint.shapes.standard.Rectangle();
a1.size(50, 50);
a2.size(70, 30);
var l1 = new joint.shapes.standard.Link();
l1.source(a1).target(a2);
graph.addCells([e1, a1, a2, l1]);
e1.embed(a1);
e1.embed(a2);
a1.position(20, 10, { parentRelative: true });
a2.position(90, 30, { parentRelative: true });
e1.fitEmbeds({ padding: { top: 40, left: 10, right: 10, bottom: 10 } });
var e2 = new joint.shapes.example.Group();
e2.position(500, 200);
var a3 = new joint.shapes.standard.Rectangle();
var a4 = new joint.shapes.standard.Rectangle();
a3.size(50, 50);
a4.size(70, 30);
var l2 = new joint.shapes.standard.Link();
l2.source(a3).target(a4);
graph.addCells([e2, a3, a4, l2]);
e2.embed(a3);
e2.embed(a4);
a3.position(20, 10, { parentRelative: true });
a4.position(90, -20, { parentRelative: true });
e2.fitEmbeds({ padding: { top: 40, left: 10, right: 10, bottom: 10 } });
toggleCollapse(e2);
var l = new joint.shapes.standard.Link();
l.source(e1).target(e2);
l.addTo(graph);
// Collapse / Expand
function toggleCollapse(group) {
var graph = group.graph;
if (!graph) return;
var embeds;
if (group.get("collapsed")) {
// EXPAND
var subgraph = group.get("subgraph");
// deserialize subgraph
var tmpGraph = new joint.dia.Graph();
tmpGraph.addCells(subgraph);
embeds = tmpGraph.getCells();
tmpGraph.removeCells(embeds);
// set relative position to parent
embeds.forEach(function (embed) {
if (embed.isLink()) return;
var diff = embed.position().offset(group.position());
embed.position(diff.x, diff.y);
});
graph.addCells(embeds);
embeds.forEach(function (embed) {
if (embed.isElement()) {
group.embed(embed);
} else {
embed.reparent();
}
});
group.set("collapsed", false);
group.fitEmbeds({
padding: { top: 40, left: 10, right: 10, bottom: 10 },
});
group.attr("tool/stroke", "blue");
} else {
// COLLAPSE
embeds = graph.getSubgraph(group.getEmbeddedCells());
embeds.sort(function (a) {
return a.isLink() ? 1 : -1;
});
graph.removeCells(embeds);
// get relative position to parent
embeds.forEach(function (embed) {
if (embed.isLink()) return;
var diff = embed.position().difference(group.position());
embed.position(diff.x, diff.y);
});
// serialize subgraph
group.set(
"subgraph",
embeds.map(function (embed) {
return embed.toJSON();
})
);
group.resize(100, 100);
group.set("collapsed", true);
group.size(100, 40);
group.attr("tool/stroke", "red");
}
}
// event handler for task group button
paper.on("element:collapse", function (elementView, evt) {
evt.stopPropagation();
toggleCollapse(elementView.model);
});
}