Drawflow
Drawflow copied to clipboard
Is it possible to connect nodes that are not on the same level in the DOM?
First thank you for this very nice project! Let me explain my need on an example. Suppose the DOM tree is
body
div
div of id A
div of id B
I want to connect A and B. Is it possible?
I tried to connect it but I get the error
Uncaught (in promise) TypeError: this.drawflow.drawflow[t] is undefined
getNodeFromId https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.js:1
addConnection https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.js:1
How did you add the node?
When a node is added with the addnode function they are always at the same level.
What if a node can have several levels. Example:
editor.addNode('node1', 0, 1, 150, 300, 'node1', {}, '<div>Hi!</div>');
editor.addNode('node2', 0, 1, 300, 300, 'node2', {}, '<div><div><div><div><div>Hii!</div></div></div></div></div>');
Thank you for your answer. OK I see. I added the node via the DOM (appendChild), that is maybe one source of the problem. Nodes are created via DOM manipulations.
When a node has a deeper level, its container may have other children too so unfortunately
editor.addNode('node2', 0, 1, 300, 300, 'node2', {}, '<div><div><div><div><div>Hii!</div></div></div></div></div>');
will not work, because it will consider node2 has the whole container instead of just the inner element.
- Do you think it would be possible to adapt the library so that nodes are not at the same level?
- Do you think it would be possible to modify DrawFlow in order to refer to elements directly rather than to their ids?
editor.addConnection(element1, element2) instead of
editor.addConnection(element1.id, element2.id)
Anyway, thank you for your nice library that works when it is used "in the standard way".
What is the reason for having several nodes at different levels? Maybe there is some other solution.
I think the library could be adapted, even though you would have to touch a lot of code. You can fork and try.
The reason is that the organization of nodes at different levels enable to benefit from CSS layouting. In the same time, I need to connect two nodes. See picture, where the left part is organized via CSS, and I want to connect some inner node of it to the node of the right.
Are they multiple nodes? If there are multiple nodes, have you thought about adding a new editor to a drawflow node? Maybe that could be your solution.
If it's not multiple nodes and it's just style, does it mean something like this?
Thank you! Maybe your solution could work indeed! In your example, the connections are:
- Yes ====> Yes Randomized Facts
- No =====> New Block 5 Right?
Is it possible for the edges (connections) to go over the block "Ask questions"?
Yes it's possible.
In this case I use an output displacement technique. I use the class link followed by the output to which it is directed to move the element.
editor.on('nodeCreated', (id) => {
const links = document.querySelectorAll(`#node-${id} .drawflow_content_node .link`);
links.forEach((item) => {
const target = document.querySelector(`#node-${id} .outputs .${item.classList[1]}`);
if(target != null) {
const pos = item.getBoundingClientRect();
const targetPos = target.getBoundingClientRect();
target.style.top = `${pos.y - targetPos.y}px`;
target.style.left = `${pos.x - targetPos.x}px`;
}
})
})
editor.start();
editor.addNode('question', 1, 3, 300, 200, 'question', {}, `
<div class="title">Ask question</div>
<div class="panel">Nice to meet yout (name)...</div>
<div class="panel">Custom API</div>
<div class="multiple">
<div class="panel">Yes<div class="link output_1"></div></div>
<div class="panel">No<div class="link output_2"></div></div>
<div class="panel">No Match<div class="link output_3"></div></div>
</div>
` );
In this case it is only done for the outputs and new nodes, the same would have to be done with the import event.
I put the complete code of the example.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.css"/>
<script src="https://cdn.jsdelivr.net/gh/jerosoler/Drawflow/dist/drawflow.min.js"></script>
</head>
<body>
<div id="drawflow"></div>
<style>
#drawflow {
position: relative;
text-align:initial;
width: 100%;
height: 800px;
border: 1px solid red;
font-size: 14px;
}
.multiple {
border-radius: 4px;
}
.multiple .panel {
margin: 0px;
border-radius: 0px;
}
.panel {
display: block;
position: relative;
background: white;
padding: 10px;
margin: 10px 0px;
border-radius: 4px;
border: 1px solid #eaeef3;
}
.link {
position: absolute;
right: 5px;
top: 15px;
display: block;
width: 10px;
height: 10px;
}
.drawflow .drawflow-node .output, .drawflow .drawflow-node .input {
width: 8px;
height: 8px;
border: 2px solid #75889a;
}
.drawflow .inputs {
position: absolute;
top: 10px;
opacity: 1;
}
.drawflow .connection .main-path {
stroke-width: 2px;
}
.drawflow .drawflow-node {
border: 2px solid white;
width: 260px;
}
.drawflow .drawflow-node .title {
font-weight: bold;
}
.drawflow-node.question {
outline: 2px solid #eaeef3;
background: #eaeef3;
}
.drawflow-node.question .title {
color: #75889a;
}
.drawflow-node.yes {
outline: 2px solid #e9f0e9;
background: #e9f0e9;
}
.drawflow-node.yes .title {
color: #758375;
}
.drawflow-node.newblock .inputs {
top: 50px;
}
.drawflow-node.newblock {
outline: 2px solid #eaeef3;
background: #eaeef3;
}
.drawflow-node.newblock .title {
color: #75889a;
}
.drawflow-node.no .inputs {
top: 50px;
}
.drawflow-node.no {
outline: 2px solid #ffdee6;
background: #ffdee6;
}
.drawflow-node.no .title {
color: #ad516a;
}
.drawflow .drawflow-node {
z-index: initial;
}
</style>
<script>
var id = document.getElementById("drawflow");
const editor = new Drawflow(id);
editor.on('nodeCreated', (id) => {
const links = document.querySelectorAll(`#node-${id} .drawflow_content_node .link`);
links.forEach((item) => {
const target = document.querySelector(`#node-${id} .outputs .${item.classList[1]}`);
if(target != null) {
const pos = item.getBoundingClientRect();
const targetPos = target.getBoundingClientRect();
target.style.top = `${pos.y - targetPos.y}px`;
target.style.left = `${pos.x - targetPos.x}px`;
}
})
})
editor.start();
editor.addNode('question', 1, 3, 300, 200, 'question', {}, `
<div class="title">Ask question</div>
<div class="panel">Nice to meet yout (name)...</div>
<div class="panel">Custom API</div>
<div class="multiple">
<div class="panel">Yes<div class="link output_1"></div></div>
<div class="panel">No<div class="link output_2"></div></div>
<div class="panel">No Match<div class="link output_3"></div></div>
</div>
` );
editor.addNode('yes', 1, 0, 850, 200, 'yes', {}, `
<div class="title">Yes Randomized Facts</div>
<div class="panel">Did you know.... Vieflow power over 6000 Alexa Skills and Google Actions</div>
` );
editor.addNode('newblock', 1, 0, 850, 370, 'newblock', {}, `
<div class="title">New Block 5</div>
<div class="panel">Connect a flow to this step</div>
` );
editor.addNode('no', 1, 1, 850, 500, 'no', {}, `
<div class="title">No - Goodbye</div>
<div class="panel">No problem. Bye for now!<div class="link output_1"></div></div>
` );
editor.addConnection(1, 2, 'output_1', 'input_1');
editor.addConnection(1, 3, 'output_2', 'input_1');
//editor.addConnection(1, 4, 'output_3', 'input_1');
</script>
</body>
</html>
Thank you! I will study that! Then my need would be:
- to disable all the editing functionalities (in my need, the graph just evolves by clicking on nodes)
- to hide nodes (and the related links)
- it would be easier also to nodes via DOM like
editor.addNode(domElement)
and to refer to DOM elements directlyeditor.addConnection(domElement1, domElement2)
, because here, it requires the user to handle ids manually (generation of fake ids etc.) But this depends on the usage. Adding as it is now is good too.
Also, your library deserves a nice tutorial! :) Have a nice day!
Hi @jerosoler , using above example, creating node using json structure but those connecting lines are not placing properly.
like nodeCreated event for addNode is there any event available while creating nodes using json
PFB angular example in stackbliz
angular-stackbliz-example