Browse Source

fixed a number of bugs in manipulation

flowchartTest
Alex de Mulder 9 years ago
parent
commit
a150b7cb27
9 changed files with 777 additions and 789 deletions
  1. +687
    -672
      dist/vis.js
  2. +1
    -1
      dist/vis.min.css
  3. +2
    -5
      examples/network/01_basic_usage.html
  4. +1
    -40
      examples/network/21_data_manipulation.html
  5. +7
    -7
      examples/network/39_newClustering.html
  6. +70
    -61
      lib/network/modules/ManipulationSystem.js
  7. +0
    -1
      lib/network/modules/SelectionHandler.js
  8. +8
    -0
      lib/network/modules/components/edges/BezierEdgeDynamic.js
  9. +1
    -2
      lib/network/modules/components/physics/SpringSolver.js

+ 687
- 672
dist/vis.js
File diff suppressed because it is too large
View File


+ 1
- 1
dist/vis.min.css
File diff suppressed because it is too large
View File


+ 2
- 5
examples/network/01_basic_usage.html View File

@ -29,7 +29,7 @@
// create an array with edges
var edges = [
{from: 1, to: 1},
{from: 1, to: 1, id:'e1'},
{from: 1, to: 3, dashes:{pattern:[10,15,2,5]}},
{from: 1, to: 2},
{from: 2, to: 4},
@ -44,10 +44,7 @@
edges: edges
};
var options = {
configure:'edges',
edges:{
dashes:true,
},
manipulation:true
// physics:{stabilization:true}
}
var network = new vis.Network(container, data, options);

+ 1
- 40
examples/network/21_data_manipulation.html View File

@ -115,46 +115,7 @@
};
var options = {
stabilize: false,
dataManipulation: true,
onAdd: function(data,callback) {
var span = document.getElementById('operation');
var idInput = document.getElementById('node-id');
var labelInput = document.getElementById('node-label');
var saveButton = document.getElementById('saveButton');
var cancelButton = document.getElementById('cancelButton');
var div = document.getElementById('network-popUp');
span.innerHTML = "Add Node";
idInput.value = data.id;
labelInput.value = data.label;
saveButton.onclick = saveData.bind(this,data,callback);
cancelButton.onclick = clearPopUp.bind();
div.style.display = 'block';
},
onEdit: function(data,callback) {
var span = document.getElementById('operation');
var idInput = document.getElementById('node-id');
var labelInput = document.getElementById('node-label');
var saveButton = document.getElementById('saveButton');
var cancelButton = document.getElementById('cancelButton');
var div = document.getElementById('network-popUp');
span.innerHTML = "Edit Node";
idInput.value = data.id;
labelInput.value = data.label;
saveButton.onclick = saveData.bind(this,data,callback);
cancelButton.onclick = clearPopUp.bind();
div.style.display = 'block';
},
onConnect: function(data,callback) {
if (data.from == data.to) {
var r=confirm("Do you want to connect the node to itself?");
if (r==true) {
callback(data);
}
}
else {
callback(data);
}
}
manipulation: true
};
network = new vis.Network(container, data, options);

+ 7
- 7
examples/network/39_newClustering.html View File

@ -80,13 +80,13 @@
network.clustering.clusterOutliers({clusterNodeProperties: {shape:'database',borderWidth:3}})
// network.clusterByConnection(2, clusterOptions);
// network.clusterByConnection(9, {
// joinCondition:function(parentOptions,childOptions) {return true;},
// processProperties:function (properties, childNodes, childEdges) {
// return properties;
// },
// clusterNodeProperties: {id:'bla2', label:"bla2", borderWidth:8}
// });
network.clusterByConnection(9, {
joinCondition:function(parentOptions,childOptions) {return true;},
processProperties:function (properties, childNodes, childEdges) {
return properties;
},
clusterNodeProperties: {id:'bla2', label:"bla2", borderWidth:8}
});
network.body.emitter.on("select", function(params) {
console.log("here1234")
if (params.nodes.length == 1) {

+ 70
- 61
lib/network/modules/ManipulationSystem.js View File

@ -54,7 +54,7 @@ class ManipulationSystem {
controlNodeStyle:{
shape:'dot',
size:6,
color: {background: '#ff0000', border: '#3c3c3c', highlight: {background: '#07f968'}},
color: {background: '#ff0000', border: '#3c3c3c', highlight: {background: '#07f968', border: '#3c3c3c'}},
borderWidth: 2,
borderWidthSelected: 2
}
@ -96,16 +96,16 @@ class ManipulationSystem {
let closeDiv = this.closeDiv;
let editModeDiv = this.editModeDiv;
if (this.editMode === true) {
toolbar.style.display = "block";
closeDiv.style.display = "block";
editModeDiv.style.display = "none";
toolbar.style.display = 'block';
closeDiv.style.display = 'block';
editModeDiv.style.display = 'none';
this._bindHammerToDiv(closeDiv, this.toggleEditMode.bind(this));
this.showManipulatorToolbar();
}
else {
toolbar.style.display = "none";
closeDiv.style.display = "none";
editModeDiv.style.display = "block";
toolbar.style.display = 'none';
closeDiv.style.display = 'none';
editModeDiv.style.display = 'block';
this._createEditButton();
}
}
@ -199,7 +199,7 @@ class ManipulationSystem {
*
* @private
*/
editNode() {
editNodeMode() {
if (typeof this.options.handlerFunctions.editNode === 'function') {
let node = this.selectionHandler._getSelectedNode();
if (node.isCluster !== true) {
@ -218,7 +218,7 @@ class ManipulationSystem {
}
}
else {
alert(this.options.locales[this.options.locale]["editClusterError"]);
alert(this.options.locales[this.options.locale]['editClusterError']);
}
}
else {
@ -248,8 +248,12 @@ class ManipulationSystem {
}
// temporarily overload functions
this._temporaryBindUI('onTouch', this._handleConnect.bind(this));
this._temporaryBindUI('onDragEnd', this._finishConnect.bind(this));
this._temporaryBindUI('onTouch', this._handleConnect.bind(this));
this._temporaryBindUI('onDragEnd', this._finishConnect.bind(this));
this._temporaryBindUI('onDrag', this._dragControlNode.bind(this));
this._temporaryBindUI('onRelease', this._finishConnect.bind(this));
this._temporaryBindUI('onDragStart', () => {});
this._temporaryBindUI('onHold', () => {});
}
@ -326,7 +330,7 @@ class ManipulationSystem {
if (selectedNodes.length > 0) {
for (let i = 0; i < selectedNodes.length; i++) {
if (this.body.nodes[selectedNodes[i]].isCluster === true) {
alert(this.options.locales[this.options.locale]["deleteClusterError"]);
alert(this.options.locales[this.options.locale]['deleteClusterError']);
return;
}
}
@ -347,7 +351,7 @@ class ManipulationSystem {
deleteFunction(data, (finalizedData) => {
this.body.data.edges.remove(finalizedData.edges);
this.body.data.nodes.remove(finalizedData.nodes);
this.body.emitter.emit("startSimulation");
this.body.emitter.emit('startSimulation');
});
}
else {
@ -357,7 +361,7 @@ class ManipulationSystem {
else {
this.body.data.edges.remove(selectedEdges);
this.body.data.nodes.remove(selectedNodes);
this.body.emitter.emit("startSimulation");
this.body.emitter.emit('startSimulation');
}
}
@ -402,10 +406,10 @@ class ManipulationSystem {
this.manipulationDiv = document.createElement('div');
this.manipulationDiv.className = 'vis-manipulation';
if (this.editMode === true) {
this.manipulationDiv.style.display = "block";
this.manipulationDiv.style.display = 'block';
}
else {
this.manipulationDiv.style.display = "none";
this.manipulationDiv.style.display = 'none';
}
this.canvas.frame.appendChild(this.manipulationDiv);
}
@ -415,10 +419,10 @@ class ManipulationSystem {
this.editModeDiv = document.createElement('div');
this.editModeDiv.className = 'vis-edit-mode';
if (this.editMode === true) {
this.editModeDiv.style.display = "none";
this.editModeDiv.style.display = 'none';
}
else {
this.editModeDiv.style.display = "block";
this.editModeDiv.style.display = 'block';
}
this.canvas.frame.appendChild(this.editModeDiv);
}
@ -501,7 +505,7 @@ class ManipulationSystem {
this._unbindTemporaryEvents();
// restore the physics if required
this.body.emitter.emit("restorePhysics");
this.body.emitter.emit('restorePhysics');
}
@ -571,9 +575,9 @@ class ManipulationSystem {
}
_createEditNodeButton(locale) {
let button = this._createButton('editNode', 'vis-button vis-edit', locale['editNode']);
let button = this._createButton('editNodeMode', 'vis-button vis-edit', locale['editNodeMode']);
this.manipulationDiv.appendChild(button);
this._bindHammerToDiv(button, this.editNode.bind(this));
this._bindHammerToDiv(button, this.editNodeMode.bind(this));
}
_createEditEdgeButton(locale) {
@ -595,13 +599,13 @@ class ManipulationSystem {
}
_createButton(id, className, label, labelClassName = 'vis-label') {
this.manipulationDOM[id+"Div"] = document.createElement('div');
this.manipulationDOM[id+"Div"].className = className;
this.manipulationDOM[id+"Label"] = document.createElement('div');
this.manipulationDOM[id+"Label"].className = labelClassName;
this.manipulationDOM[id+"Label"].innerHTML = label;
this.manipulationDOM[id+"Div"].appendChild(this.manipulationDOM[id+'Label']);
return this.manipulationDOM[id+"Div"];
this.manipulationDOM[id+'Div'] = document.createElement('div');
this.manipulationDOM[id+'Div'].className = className;
this.manipulationDOM[id+'Label'] = document.createElement('div');
this.manipulationDOM[id+'Label'].className = labelClassName;
this.manipulationDOM[id+'Label'].innerHTML = label;
this.manipulationDOM[id+'Div'].appendChild(this.manipulationDOM[id+'Label']);
return this.manipulationDOM[id+'Div'];
}
_createDescription(label) {
@ -635,7 +639,7 @@ class ManipulationSystem {
this.body.eventListeners[UIfunctionName] = newFunction;
}
else {
throw new Error('This UI function does not exist. Typo? You tried: "' + UIfunctionName + '" possible are: ' + JSON.stringify(Object.keys(this.body.eventListeners)));
throw new Error('This UI function does not exist. Typo? You tried: ' + UIfunctionName + ' possible are: ' + JSON.stringify(Object.keys(this.body.eventListeners)));
}
}
@ -710,6 +714,7 @@ class ManipulationSystem {
* @private
*/
_controlNodeTouch(event) {
this.selectionHandler.unselectAll();
this.lastTouch = this.body.functions.getPointer(event.center);
this.lastTouch.translation = util.extend({},this.body.view.translation); // copy the object
}
@ -740,7 +745,7 @@ class ManipulationSystem {
edge.edgeType.to = to;
}
this.body.emitter.emit("_redraw");
this.body.emitter.emit('_redraw');
}
/**
@ -749,7 +754,7 @@ class ManipulationSystem {
* @private
*/
_controlNodeDrag(event) {
this.body.emitter.emit("disablePhysics");
this.body.emitter.emit('disablePhysics');
let pointer = this.body.functions.getPointer(event.center);
let pos = this.canvas.DOMtoCanvas(pointer);
@ -763,7 +768,7 @@ class ManipulationSystem {
let diffY = pointer.y - this.lastTouch.y;
this.body.view.translation = {x:this.lastTouch.translation.x + diffX, y:this.lastTouch.translation.y + diffY};
}
this.body.emitter.emit("_redraw");
this.body.emitter.emit('_redraw');
}
@ -789,7 +794,7 @@ class ManipulationSystem {
// perform the connection
if (node !== undefined && this.selectedControlNode !== undefined) {
if (node.isCluster === true) {
alert(this.options.locales[this.options.locale]["createEdgeError"])
alert(this.options.locales[this.options.locale]['createEdgeError'])
}
else {
let from = this.body.nodes[this.temporaryIds.nodes[0]];
@ -803,9 +808,9 @@ class ManipulationSystem {
}
else {
edge.updateEdgeType();
this.body.emitter.emit("restorePhysics");
this.body.emitter.emit('restorePhysics');
}
this.body.emitter.emit("_redraw");
this.body.emitter.emit('_redraw');
}
// ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
@ -822,7 +827,10 @@ class ManipulationSystem {
_handleConnect(event) {
// check to avoid double fireing of this function.
if (new Date().valueOf() - this.touchTime > 100) {
let pointer = this.body.functions.getPointer(event.center);
this.lastTouch = this.body.functions.getPointer(event.center);
this.lastTouch.translation = util.extend({},this.body.view.translation); // copy the object
let pointer = this.lastTouch;
let node = this.selectionHandler.getNodeAt(pointer);
if (node !== undefined) {
@ -832,20 +840,19 @@ class ManipulationSystem {
else {
// create a node the temporary line can look at
let targetNode = this._getNewTargetNode(node.x,node.y);
let targetNodeId = targetNode.id;
this.body.nodes[targetNode.id] = targetNode;
this.body.nodeIndices.push(targetNode.id);
// create a temporary edge
let connectionEdge = this.body.functions.createEdge({
id: "connectionEdge" + util.randomUUID(),
id: 'connectionEdge' + util.randomUUID(),
from: node.id,
to: targetNode.id,
physics:false,
physics: false,
smooth: {
enabled: true,
dynamic: false,
type: "continuous",
type: 'continuous',
roundness: 0.5
}
});
@ -854,30 +861,36 @@ class ManipulationSystem {
this.temporaryIds.nodes.push(targetNode.id);
this.temporaryIds.edges.push(connectionEdge.id);
this.temporaryUIFunctions["onDrag"] = this.body.eventListeners.onDrag;
this.body.eventListeners.onDrag = (event) => {
let pointer = this.body.functions.getPointer(event.center);
let targetNode = this.body.nodes[targetNodeId];
targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
this.body.emitter.emit("_redraw");
}
}
}
this.touchTime = new Date().valueOf();
}
}
// do the original touch events
this.temporaryUIFunctions["onTouch"](event);
_dragControlNode(event) {
let pointer = this.body.functions.getPointer(event.center);
if (this.temporaryIds.nodes[0] !== undefined) {
let targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
this.body.emitter.emit('_redraw');
}
else {
let diffX = pointer.x - this.lastTouch.x;
let diffY = pointer.y - this.lastTouch.y;
this.body.view.translation = {x:this.lastTouch.translation.x + diffX, y:this.lastTouch.translation.y + diffY};
}
}
/**
* Connect the new edge to the target if one exists, otherwise remove temp line
* @param event
* @private
*/
_finishConnect(event) {
console.log("finishd")
let pointer = this.body.functions.getPointer(event.center);
let pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
@ -887,17 +900,12 @@ class ManipulationSystem {
connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
}
//restore the drag function
if (this.temporaryUIFunctions["onDrag"] !== undefined) {
this.body.eventListeners.onDrag = this.temporaryUIFunctions["onDrag"];
delete this.temporaryUIFunctions["onDrag"];
}
// get the overlapping node but NOT the temporary node;
let overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
let node = undefined;
for (let i = overlappingNodeIds.length-1; i >= 0; i--) {
if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) !== -1) {
// if the node id is NOT a temporary node, accept the node.
if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) === -1) {
node = this.body.nodes[overlappingNodeIds[i]];
break;
}
@ -909,7 +917,7 @@ class ManipulationSystem {
// perform the connection
if (node !== undefined) {
if (node.isCluster === true) {
alert(this.options.locales[this.options.locale]["createEdgeError"]);
alert(this.options.locales[this.options.locale]['createEdgeError']);
}
else {
if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
@ -917,7 +925,7 @@ class ManipulationSystem {
}
}
}
this.body.emitter.emit("_redraw");
this.body.emitter.emit('_redraw');
}
// --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
@ -933,7 +941,7 @@ class ManipulationSystem {
id: util.randomUUID(),
x: clickData.pointer.canvas.x,
y: clickData.pointer.canvas.y,
label: "new"
label: 'new'
};
if (typeof this.options.handlerFunctions.addNode === 'function') {
@ -961,6 +969,7 @@ class ManipulationSystem {
* @private
*/
_performCreateEdge(sourceNodeId, targetNodeId) {
console.log('sou',sourceNodeId, targetNodeId)
let defaultData = {from: sourceNodeId, to: targetNodeId};
if (this.options.handlerFunctions.addEdge) {
if (this.options.handlerFunctions.addEdge.length === 2) {

+ 0
- 1
lib/network/modules/SelectionHandler.js View File

@ -150,7 +150,6 @@ class SelectionHandler {
// we first check if this is an navigation controls element
let positionObject = this._pointerToPositionObject(pointer);
let overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
// if there are overlapping nodes, select the last one, this is the
// one which is drawn on top of the others
if (overlappingNodes.length > 0) {

+ 8
- 0
lib/network/modules/components/edges/BezierEdgeDynamic.js View File

@ -12,6 +12,14 @@ class BezierEdgeDynamic extends BezierEdgeBase {
this.to = this.body.nodes[this.options.to];
this.id = this.options.id;
this.setupSupportNode();
// fix weird behaviour
if (this.from.id === this.to.id) {
this.via.setOptions({physics:false})
}
else {
this.via.setOptions({physics:true})
}
}
cleanup() {

+ 1
- 2
lib/network/modules/components/physics/SpringSolver.js View File

@ -22,7 +22,7 @@ class SpringSolver {
// forces caused by the edges, modelled as springs
for (let i = 0; i < edgeIndices.length; i++) {
edge = edges[edgeIndices[i]];
if (edge.connected === true) {
if (edge.connected === true && edge.toId !== edge.fromId) {
// only calculate forces if nodes are in the same sector
if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
if (edge.edgeType.via !== undefined) {
@ -31,7 +31,6 @@ class SpringSolver {
var node2 = edge.edgeType.via;
var node3 = edge.from;
this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
}

Loading…
Cancel
Save