Browse Source

Edit edge without endpoint dragging, and pass label in data (#2329)

* { manipulation: { editEdge: { editWithoutDrag: function } } } edits an edge without dragging.
* An example of editing network edges without dragging, enabling label creation / change
codeClimate
David Anderson 8 years ago
committed by Alexander Wunschik
parent
commit
17ce133094
4 changed files with 276 additions and 7 deletions
  1. +1
    -1
      docs/network/manipulation.html
  2. +254
    -0
      examples/network/other/manipulationEditEdgeNoDrag.html
  3. +17
    -5
      lib/network/modules/ManipulationSystem.js
  4. +4
    -1
      lib/network/options.js

+ 1
- 1
docs/network/manipulation.html View File

@ -164,7 +164,7 @@ var options = {
</pre> </pre>
This example code will show a popup if you connect a node to itself to ask you if that was what you wanted. If you do not want the edge created, do not call the callback function or call the callback function <code>null</code> or no argument.</td></tr> This example code will show a popup if you connect a node to itself to ask you if that was what you wanted. If you do not want the edge created, do not call the callback function or call the callback function <code>null</code> or no argument.</td></tr>
<tr><td>editNode</td> <td>Function</td> <td><code>undefined</code></td> <td>Editing of nodes is only possible when a handling function is supplied. If this is not the case, editing of nodes will be disabled. The function will be called when a node is selected and the 'Edit Node' button on the toolbar is pressed. This function will be called like the <code>addNode</code> function with the node's data and a callback function.</td></tr> <tr><td>editNode</td> <td>Function</td> <td><code>undefined</code></td> <td>Editing of nodes is only possible when a handling function is supplied. If this is not the case, editing of nodes will be disabled. The function will be called when a node is selected and the 'Edit Node' button on the toolbar is pressed. This function will be called like the <code>addNode</code> function with the node's data and a callback function.</td></tr>
<tr><td>editEdge</td> <td>Boolean or Function</td> <td><code>true</code></td> <td>If boolean, toggle the editing of edges in the GUI. When a function is supplied, it will be called when an edge is selected and the 'Edit Edge' button on the toolbar is pressed. This function will be called in the same way the <code>addEdge</code> function was called. If the callback is not performed, the edge will remain hanging where it was released. <b>To cancel, call the callback function with <code>null</code> as argument or without arguments</b>.</td></tr>
<tr><td>editEdge</td> <td>Boolean or Function</td> <td><code>true</code></td> <td>If boolean, toggle the editing of edges in the GUI. If a function is supplied, it will be called when an edge is selected and the 'Edit Edge' button on the toolbar is pressed. Initially, the endpoints of the edge may be dragged to connect to a different node, then the function will be called in the same way the <code>addEdge</code> function is called. If an object, if a function is given for the <code>'editWithoutDrag'</code> property, the function will be called immediately (without dragging any endpoints) in the same way the <code>addEdge</code> function is called. If the callback is not performed, the edge will remain hanging where it was released. <b>To cancel, call the callback function with <code>null</code> as argument or without arguments</b>.</td></tr>
<tr><td>deleteNode</td> <td>Boolean or Function</td> <td><code>true</code></td> <td>If boolean, toggle the deletion of nodes in the GUI. If function, it will be called when a node is selected and the 'Delete selected' button is pressed. When using a function, it will receive a callback and an object with an array of selected nodeIds and an array of selected edges Ids. These are the items that will be deleted if the callback is performed.</td></tr> <tr><td>deleteNode</td> <td>Boolean or Function</td> <td><code>true</code></td> <td>If boolean, toggle the deletion of nodes in the GUI. If function, it will be called when a node is selected and the 'Delete selected' button is pressed. When using a function, it will receive a callback and an object with an array of selected nodeIds and an array of selected edges Ids. These are the items that will be deleted if the callback is performed.</td></tr>
<tr><td>deleteEdge</td> <td>Boolean or Function</td> <td><code>true</code></td> <td>If boolean, toggle the deletion of edges in the GUI. If function, it will be called when an edge is selected and the 'Delete selected' button is pressed. When using a function, it will receive a callback and an object with an array of selected nodeIds (empty) and an array of selected edges Ids. These are the items that will be deleted if the callback is performed.</td></tr> <tr><td>deleteEdge</td> <td>Boolean or Function</td> <td><code>true</code></td> <td>If boolean, toggle the deletion of edges in the GUI. If function, it will be called when an edge is selected and the 'Delete selected' button is pressed. When using a function, it will receive a callback and an object with an array of selected nodeIds (empty) and an array of selected edges Ids. These are the items that will be deleted if the callback is performed.</td></tr>
<tr><td>controlNodeStyle</td> <td>Object</td> <td>Object</td><td>You can supply any styling information you'd like here. All fields described in <a href="./nodes.html">the nodes module</a> are allowed except obviously for id, x, y and fixed. <br><br>Default: <tr><td>controlNodeStyle</td> <td>Object</td> <td>Object</td><td>You can supply any styling information you'd like here. All fields described in <a href="./nodes.html">the nodes module</a> are allowed except obviously for id, x, y and fixed. <br><br>Default:

+ 254
- 0
examples/network/other/manipulationEditEdgeNoDrag.html View File

@ -0,0 +1,254 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network | Manipulation | Edit Edge Without Drag</title>
<style type="text/css">
body, select {
font: 10pt sans;
}
#mynetwork {
position:relative;
width: 800px;
height: 600px;
border: 1px solid lightgray;
}
table.legend_table {
font-size: 11px;
border-width:1px;
border-color:#d3d3d3;
border-style:solid;
}
table.legend_table,td {
border-width:1px;
border-color:#d3d3d3;
border-style:solid;
padding: 2px;
}
div.table_content {
width:80px;
text-align:center;
}
div.table_description {
width:100px;
}
#operation {
font-size:28px;
}
#node-popUp {
display:none;
position:absolute;
top:350px;
left:170px;
z-index:299;
width:250px;
height:120px;
background-color: #f9f9f9;
border-style:solid;
border-width:3px;
border-color: #5394ed;
padding:10px;
text-align: center;
}
#edge-popUp {
display:none;
position:absolute;
top:350px;
left:170px;
z-index:299;
width:250px;
height:90px;
background-color: #f9f9f9;
border-style:solid;
border-width:3px;
border-color: #5394ed;
padding:10px;
text-align: center;
}
</style>
<script type="text/javascript" src="../exampleUtil.js"></script>
<script type="text/javascript" src="../../../dist/vis.js"></script>
<link href="../../../dist/vis-network.min.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var nodes = null;
var edges = null;
var network = null;
// randomly create some nodes and edges
var data = getScaleFreeNetwork(25);
var seed = 2;
function setDefaultLocale() {
var defaultLocal = navigator.language;
var select = document.getElementById('locale');
select.selectedIndex = 0; // set fallback value
for (var i = 0, j = select.options.length; i < j; ++i) {
if (select.options[i].getAttribute('value') === defaultLocal) {
select.selectedIndex = i;
break;
}
}
}
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
function draw() {
destroy();
nodes = [];
edges = [];
// create a network
var container = document.getElementById('mynetwork');
var options = {
layout: {randomSeed:seed}, // just to make sure the layout is the same when the locale is changed
locale: document.getElementById('locale').value,
manipulation: {
addNode: function (data, callback) {
// filling in the popup DOM elements
document.getElementById('node-operation').innerHTML = "Add Node";
editNode(data, callback);
},
editNode: function (data, callback) {
// filling in the popup DOM elements
document.getElementById('node-operation').innerHTML = "Edit Node";
editNode(data, callback);
},
addEdge: function (data, callback) {
if (data.from == data.to) {
var r = confirm("Do you want to connect the node to itself?");
if (r != true) {
callback(null);
return;
}
}
document.getElementById('edge-operation').innerHTML = "Add Edge";
editEdgeWithoutDrag(data, callback);
},
editEdge: {
editWithoutDrag: function(data, callback) {
document.getElementById('edge-operation').innerHTML = "Edit Edge";
editEdgeWithoutDrag(data,callback);
}
}
}
};
network = new vis.Network(container, data, options);
}
function editNode(data, callback) {
document.getElementById('node-label').value = data.label;
document.getElementById('node-saveButton').onclick = saveNodeData.bind(this, data, callback);
document.getElementById('node-cancelButton').onclick = clearNodePopUp.bind();
document.getElementById('node-popUp').style.display = 'block';
}
function clearNodePopUp() {
document.getElementById('node-saveButton').onclick = null;
document.getElementById('node-cancelButton').onclick = null;
document.getElementById('node-popUp').style.display = 'none';
}
function cancelNodeEdit(callback) {
clearNodePopUp();
callback(null);
}
function saveNodeData(data, callback) {
data.label = document.getElementById('node-label').value;
clearNodePopUp();
callback(data);
}
function editEdgeWithoutDrag(data, callback) {
// filling in the popup DOM elements
document.getElementById('edge-label').value = data.label;
document.getElementById('edge-saveButton').onclick = saveEdgeData.bind(this, data, callback);
document.getElementById('edge-cancelButton').onclick = cancelEdgeEdit.bind(this,callback);
document.getElementById('edge-popUp').style.display = 'block';
}
function clearEdgePopUp() {
document.getElementById('edge-saveButton').onclick = null;
document.getElementById('edge-cancelButton').onclick = null;
document.getElementById('edge-popUp').style.display = 'none';
}
function cancelEdgeEdit(callback) {
clearEdgePopUp();
callback(null);
}
function saveEdgeData(data, callback) {
if (typeof data.to === 'object')
data.to = data.to.id
if (typeof data.from === 'object')
data.from = data.from.id
data.label = document.getElementById('edge-label').value;
clearEdgePopUp();
callback(data);
}
function init() {
setDefaultLocale();
draw();
}
</script>
<script src="../../googleAnalytics.js"></script>
</head>
<body onload="init();">
<h2>Editing the nodes and edges-without-drag (localized)</h2>
<p style="width: 700px; font-size:14px; text-align: justify;">
The localization is only relevant to the manipulation buttons.
</p>
<p>
<label for="locale">Select a locale:</label>
<select id="locale" onchange="draw();">
<option value="en">en</option>
<option value="de">de</option>
<option value="es">es</option>
<option value="it">it</option>
<option value="nl">nl</option>
<option value="pt-br">pt</option>
<option value="ru">ru</option>
</select>
</p>
<div id="node-popUp">
<span id="node-operation">node</span> <br>
<table style="margin:auto;">
<tr>
<td>id</td><td><input id="node-id" value="new value" /></td>
</tr>
<tr>
<td>label</td><td><input id="node-label" value="new value" /></td>
</tr>
</table>
<input type="button" value="save" id="node-saveButton" />
<input type="button" value="cancel" id="node-cancelButton" />
</div>
<div id="edge-popUp">
<span id="edge-operation">edge</span> <br>
<table style="margin:auto;">
<tr>
<td>label</td><td><input id="edge-label" value="new value" /></td>
</tr></table>
<input type="button" value="save" id="edge-saveButton" />
<input type="button" value="cancel" id="edge-cancelButton" />
</div>
<br />
<div id="mynetwork"></div>
</body>
</html>

+ 17
- 5
lib/network/modules/ManipulationSystem.js View File

@ -340,6 +340,14 @@ class ManipulationSystem {
this._clean(); this._clean();
this.inMode = 'editEdge'; this.inMode = 'editEdge';
if (typeof this.options.editEdge === 'object' && typeof this.options.editEdge.editWithoutDrag === "function") {
this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
if (this.edgeBeingEditedId !== undefined) {
var edge = this.body.edges[this.edgeBeingEditedId];
this._performEditEdge(edge.from, edge.to);
return;
}
}
if (this.guiEnabled === true) { if (this.guiEnabled === true) {
let locale = this.options.locales[this.options.locale]; let locale = this.options.locales[this.options.locale];
this.manipulationDOM = {}; this.manipulationDOM = {};
@ -1114,13 +1122,18 @@ class ManipulationSystem {
* @private * @private
*/ */
_performEditEdge(sourceNodeId, targetNodeId) { _performEditEdge(sourceNodeId, targetNodeId) {
let defaultData = {id: this.edgeBeingEditedId, from: sourceNodeId, to: targetNodeId};
if (typeof this.options.editEdge === 'function') {
if (this.options.editEdge.length === 2) {
this.options.editEdge(defaultData, (finalizedData) => {
let defaultData = {id: this.edgeBeingEditedId, from: sourceNodeId, to: targetNodeId, label: this.body.data.edges._data[this.edgeBeingEditedId].label };
let eeFunct = this.options.editEdge;
if (typeof eeFunct === 'object') {
eeFunct = eeFunct.editWithoutDrag;
}
if (typeof eeFunct === 'function') {
if (eeFunct.length === 2) {
eeFunct(defaultData, (finalizedData) => {
if (finalizedData === null || finalizedData === undefined || this.inMode !== 'editEdge') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback) { if (finalizedData === null || finalizedData === undefined || this.inMode !== 'editEdge') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
this.body.edges[defaultData.id].updateEdgeType(); this.body.edges[defaultData.id].updateEdgeType();
this.body.emitter.emit('_redraw'); this.body.emitter.emit('_redraw');
this.showManipulatorToolbar();
} }
else { else {
this.body.data.edges.getDataSet().update(finalizedData); this.body.data.edges.getDataSet().update(finalizedData);
@ -1144,4 +1157,3 @@ class ManipulationSystem {
} }
export default ManipulationSystem; export default ManipulationSystem;

+ 4
- 1
lib/network/options.js View File

@ -140,7 +140,10 @@ let allOptions = {
addNode: { boolean, 'function': 'function' }, addNode: { boolean, 'function': 'function' },
addEdge: { boolean, 'function': 'function' }, addEdge: { boolean, 'function': 'function' },
editNode: { 'function': 'function' }, editNode: { 'function': 'function' },
editEdge: { boolean, 'function': 'function' },
editEdge: {
editWithoutDrag: { 'function' : 'function' },
__type__: {object, boolean, 'function': 'function' }
},
deleteNode: { boolean, 'function': 'function' }, deleteNode: { boolean, 'function': 'function' },
deleteEdge: { boolean, 'function': 'function' }, deleteEdge: { boolean, 'function': 'function' },
controlNodeStyle: 'get from nodes, will be overwritten below', controlNodeStyle: 'get from nodes, will be overwritten below',

Loading…
Cancel
Save