Browse Source

removed this.selection in favor or this.selectionObj. This allows keeping track of selection of nodes and edges.

css_transitions
Alex de Mulder 10 years ago
parent
commit
c81ab9157a
5 changed files with 430 additions and 346 deletions
  1. +214
    -172
      dist/vis.js
  2. +7
    -0
      src/graph/ClusterMixin.js
  3. +12
    -2
      src/graph/Edge.js
  4. +21
    -21
      src/graph/Graph.js
  5. +176
    -151
      src/graph/SelectionMixin.js

+ 214
- 172
dist/vis.js View File

@ -5,7 +5,7 @@
* A dynamic, browser-based visualization library. * A dynamic, browser-based visualization library.
* *
* @version 0.4.0-SNAPSHOT * @version 0.4.0-SNAPSHOT
* @date 2014-01-29
* @date 2014-01-30
* *
* @license * @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com * Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -9780,6 +9780,7 @@ function Edge (properties, graph, constants) {
this.width = constants.edges.width; this.width = constants.edges.width;
this.value = undefined; this.value = undefined;
this.length = constants.edges.length; this.length = constants.edges.length;
this.selected = false;
this.from = null; // a node this.from = null; // a node
this.to = null; // a node this.to = null; // a node
@ -10016,7 +10017,7 @@ Edge.prototype._drawLine = function(ctx) {
* @private * @private
*/ */
Edge.prototype._getLineWidth = function() { Edge.prototype._getLineWidth = function() {
if (this.from.selected || this.to.selected) {
if (this.selected == true) {
return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv;
} }
else { else {
@ -10366,6 +10367,15 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
Edge.prototype.setScale = function(scale) { Edge.prototype.setScale = function(scale) {
this.graphScaleInv = 1.0/scale; this.graphScaleInv = 1.0/scale;
}; };
Edge.prototype.select = function() {
this.selected = true;
}
Edge.prototype.unselect = function() {
this.selected = false;
}
/** /**
* Popup is a class to create a popup window with some text * Popup is a class to create a popup window with some text
* @param {Element} container The container object. * @param {Element} container The container object.
@ -11479,6 +11489,10 @@ var ClusterMixin = {
// if child node has been added on smaller scale than current, kick out // if child node has been added on smaller scale than current, kick out
if (childNode.formationScale < this.scale || force == true) { if (childNode.formationScale < this.scale || force == true) {
// remove the selection, first remove the selection from the connected edges
this._unselectConnectedEdges(parentNode);
parentNode.unselect();
// put the child node back in the global nodes object // put the child node back in the global nodes object
this.nodes[containedNodeId] = childNode; this.nodes[containedNodeId] = childNode;
@ -11527,6 +11541,9 @@ var ClusterMixin = {
// recalculate the size of the node on the next time the node is rendered // recalculate the size of the node on the next time the node is rendered
parentNode.clearSizeCache(); parentNode.clearSizeCache();
// this unselects the rest of the edges
this._unselectConnectedEdges(parentNode);
} }
// check if a further expansion step is possible if recursivity is enabled // check if a further expansion step is possible if recursivity is enabled
@ -12272,7 +12289,7 @@ var SelectionMixin = {
_getNodeAt : function (pointer) { _getNodeAt : function (pointer) {
// we first check if this is an navigationUI element // we first check if this is an navigationUI element
var positionObject = this._pointerToPositionObject(pointer); var positionObject = this._pointerToPositionObject(pointer);
overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
var overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
// if there are overlapping nodes, select the last one, this is the // if there are overlapping nodes, select the last one, this is the
// one which is drawn on top of the others // one which is drawn on top of the others
@ -12285,6 +12302,36 @@ var SelectionMixin = {
}, },
/**
* retrieve all edges overlapping with given object, selector is around center
* @param {Object} object An object with parameters left, top, right, bottom
* @return {Number[]} An array with id's of the overlapping nodes
* @private
*/
_getEdgesOverlappingWith : function (object, overlappingEdges) {
var edges = this.edges;
for (var edgeId in edges) {
if (edges.hasOwnProperty(edgeId)) {
if (edges[edgeId].isOverlappingWith(object)) {
overlappingEdges.push(edgeId);
}
}
}
},
/**
* retrieve all nodes overlapping with given object
* @param {Object} object An object with parameters left, top, right, bottom
* @return {Number[]} An array with id's of the overlapping nodes
* @private
*/
_getAllEdgesOverlappingWith : function (object) {
var overlappingEdges = [];
this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges);
return overlappingEdges;
},
/** /**
* Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call
* _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences.
@ -12294,18 +12341,25 @@ var SelectionMixin = {
* @private * @private
*/ */
_getEdgeAt : function(pointer) { _getEdgeAt : function(pointer) {
return null;
var positionObject = this._pointerToPositionObject(pointer);
var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject);
if (overlappingEdges.length > 0) {
return this.edges[overlappingEdges[overlappingEdges.length - 1]];
}
else {
return null;
}
}, },
/** /**
* Add object to the selection array. The this.selection id array may not be needed.
* Add object to the selection array.
* *
* @param obj * @param obj
* @private * @private
*/ */
_addToSelection : function(obj) { _addToSelection : function(obj) {
this.selection.push(obj.id);
this.selectionObj[obj.id] = obj; this.selectionObj[obj.id] = obj;
}, },
@ -12317,12 +12371,6 @@ var SelectionMixin = {
* @private * @private
*/ */
_removeFromSelection : function(obj) { _removeFromSelection : function(obj) {
for (var i = 0; i < this.selection.length; i++) {
if (obj.id == this.selection[i]) {
this.selection.splice(i,1);
break;
}
}
delete this.selectionObj[obj.id]; delete this.selectionObj[obj.id];
}, },
@ -12338,10 +12386,9 @@ var SelectionMixin = {
doNotTrigger = false; doNotTrigger = false;
} }
this.selection = [];
for (var objId in this.selectionObj) {
if (this.selectionObj.hasOwnProperty(objId)) {
this.selectionObj[objId].unselect();
for (var objectId in this.selectionObj) {
if (this.selectionObj.hasOwnProperty(objectId)) {
this.selectionObj[objectId].unselect();
} }
} }
this.selectionObj = {}; this.selectionObj = {};
@ -12359,25 +12406,55 @@ var SelectionMixin = {
* @private * @private
*/ */
_selectionIsEmpty : function() { _selectionIsEmpty : function() {
if (this.selection.length == 0) {
return true;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
return false;
}
} }
else {
return false;
return true;
},
/**
* select the edges connected to the node that is being selected
*
* @param {Node} node
* @private
*/
_selectConnectedEdges : function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
edge.select();
this._addToSelection(edge);
} }
}, },
/**
* unselect the edges connected to the node that is being selected
*
* @param {Node} node
* @private
*/
_unselectConnectedEdges : function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
edge.unselect();
this._removeFromSelection(edge);
}
},
/** /**
* This is called when someone clicks on a node. either select or deselect it. * This is called when someone clicks on a node. either select or deselect it.
* If there is an existing selection and we don't want to append to it, clear the existing selection * If there is an existing selection and we don't want to append to it, clear the existing selection
* *
* @param {Node} node
* @param {Node || Edge} object
* @param {Boolean} append * @param {Boolean} append
* @param {Boolean} [doNotTrigger] | ignore trigger * @param {Boolean} [doNotTrigger] | ignore trigger
* @private * @private
*/ */
_selectNode : function(node, append, doNotTrigger) {
_selectObject : function(object, append, doNotTrigger) {
if (doNotTrigger === undefined) { if (doNotTrigger === undefined) {
doNotTrigger = false; doNotTrigger = false;
} }
@ -12386,14 +12463,16 @@ var SelectionMixin = {
this._unselectAll(true); this._unselectAll(true);
} }
if (node.selected == false) {
node.select();
this._addToSelection(node);
if (object.selected == false) {
object.select();
this._addToSelection(object);
if (object instanceof Node) {
this._selectConnectedEdges(object);
}
} }
else { else {
node.unselect();
this._removeFromSelection(node);
object.unselect();
this._removeFromSelection(object);
} }
if (doNotTrigger == false) { if (doNotTrigger == false) {
this._trigger('select'); this._trigger('select');
@ -12428,10 +12507,16 @@ var SelectionMixin = {
_handleTap : function(pointer) { _handleTap : function(pointer) {
var node = this._getNodeAt(pointer); var node = this._getNodeAt(pointer);
if (node != null) { if (node != null) {
this._selectNode(node,false);
this._selectObject(node,false);
} }
else { else {
this._unselectAll();
var edge = this._getEdgeAt(pointer);
if (edge != null) {
this._selectObject(edge,false);
}
else {
this._unselectAll();
}
} }
this._redraw(); this._redraw();
}, },
@ -12463,7 +12548,13 @@ var SelectionMixin = {
_handleOnHold : function(pointer) { _handleOnHold : function(pointer) {
var node = this._getNodeAt(pointer); var node = this._getNodeAt(pointer);
if (node != null) { if (node != null) {
this._selectNode(node,true);
this._selectObject(node,true);
}
else {
var edge = this._getEdgeAt(pointer);
if (edge != null) {
this._selectObject(edge,true);
}
} }
this._redraw(); this._redraw();
}, },
@ -12485,12 +12576,72 @@ var SelectionMixin = {
/** /**
* *
* retrieve the currently selected nodes
* retrieve the currently selected objects
* @return {Number[] | String[]} selection An array with the ids of the * @return {Number[] | String[]} selection An array with the ids of the
* selected nodes. * selected nodes.
*/ */
getSelection : function() { getSelection : function() {
return this.selection.concat([]);
var nodeIdString = this.getSelectedNodes();
/*
var edgeIdString = this.getSelectedEdges();
var idString = "";
if (nodeIdString != "") {
idString = idString.concat("Nodes: ",nodeIdString);
if (edgeIdString != "") {
idString = idString.concat("; ");
}
}
if (edgeIdString != "") {
idString = idString.concat("Edges: ",edgeIdString);
}
*/
return nodeIdString
},
/**
*
* retrieve the currently selected nodes
* @return {String} selection An array with the ids of the
* selected nodes.
*/
getSelectedNodes : function() {
var idString = "", i = 0;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
if (this.selectionObj[objectId] instanceof Node) {
if (i != 0) {
idString = idString.concat(", ");
}
idString = idString.concat(String(objectId));
i++;
}
}
}
return idString
},
/**
*
* retrieve the currently selected edges
* @return {String} selection An array with the ids of the
* selected nodes.
*/
getSelectedEdges : function() {
var idString = "", i = 0;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
if (this.selectionObj[objectId] instanceof Edge) {
if (i != 0) {
idString = idString.concat(", ");
}
idString = idString.concat(String(objectId));
i++;
}
}
}
return idString
}, },
/** /**
@ -12504,8 +12655,6 @@ var SelectionMixin = {
}, },
/** /**
* // TODO: rework this function, it is from the old system
*
* select zero or more nodes * select zero or more nodes
* @param {Number[] | String[]} selection An array with the ids of the * @param {Number[] | String[]} selection An array with the ids of the
* selected nodes. * selected nodes.
@ -12526,7 +12675,7 @@ var SelectionMixin = {
if (!node) { if (!node) {
throw new RangeError('Node with id "' + id + '" not found'); throw new RangeError('Node with id "' + id + '" not found');
} }
this._selectNode(node,true,true);
this._selectObject(node,true,true);
} }
this.redraw(); this.redraw();
@ -12534,135 +12683,28 @@ var SelectionMixin = {
/** /**
* TODO: rework this function, it is from the old system
*
* Validate the selection: remove ids of nodes which no longer exist * Validate the selection: remove ids of nodes which no longer exist
* @private * @private
*/ */
_updateSelection : function () { _updateSelection : function () {
var i = 0;
while (i < this.selection.length) {
var nodeId = this.selection[i];
if (!this.nodes.hasOwnProperty(nodeId)) {
this.selection.splice(i, 1);
delete this.selectionObj[nodeId];
}
else {
i++;
}
}
}
/**
* Unselect selected nodes. If no selection array is provided, all nodes
* are unselected
* @param {Object[]} selection Array with selection objects, each selection
* object has a parameter row. Optional
* @param {Boolean} triggerSelect If true (default), the select event
* is triggered when nodes are unselected
* @return {Boolean} changed True if the selection is changed
* @private
*/
/* _unselectNodes : function(selection, triggerSelect) {
var changed = false;
var i, iMax, id;
if (selection) {
// remove provided selections
for (i = 0, iMax = selection.length; i < iMax; i++) {
id = selection[i];
if (this.nodes.hasOwnProperty(id)) {
this.nodes[id].unselect();
}
var j = 0;
while (j < this.selection.length) {
if (this.selection[j] == id) {
this.selection.splice(j, 1);
changed = true;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
if (this.selectionObj[objectId] instanceof Node) {
if (!this.nodes.hasOwnProperty(objectId)) {
delete this.selectionObj[objectId];
} }
else {
j++;
}
}
}
}
else if (this.selection && this.selection.length) {
// remove all selections
for (i = 0, iMax = this.selection.length; i < iMax; i++) {
id = this.selection[i];
if (this.nodes.hasOwnProperty(id)) {
this.nodes[id].unselect();
} }
changed = true;
}
this.selection = [];
}
if (changed && (triggerSelect == true || triggerSelect == undefined)) {
// fire the select event
this._trigger('select');
}
return changed;
},
*/
/**
* select all nodes on given location x, y
* @param {Array} selection an array with node ids
* @param {boolean} append If true, the new selection will be appended to the
* current selection (except for duplicate entries)
* @return {Boolean} changed True if the selection is changed
* @private
*/
/* _selectNodes : function(selection, append) {
var changed = false;
var i, iMax;
// TODO: the selectNodes method is a little messy, rework this
// check if the current selection equals the desired selection
var selectionAlreadyThere = true;
if (selection.length != this.selection.length) {
selectionAlreadyThere = false;
}
else {
for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) {
if (selection[i] != this.selection[i]) {
selectionAlreadyThere = false;
break;
else { // assuming only edges and nodes are selected
if (!this.edges.hasOwnProperty(objectId)) {
delete this.selectionObj[objectId];
}
} }
} }
} }
if (selectionAlreadyThere) {
return changed;
}
}
if (append == undefined || append == false) {
// first deselect any selected node
var triggerSelect = false;
changed = this._unselectNodes(undefined, triggerSelect);
}
for (i = 0, iMax = selection.length; i < iMax; i++) {
// add each of the new selections, but only when they are not duplicate
var id = selection[i];
var isDuplicate = (this.selection.indexOf(id) != -1);
if (!isDuplicate) {
this.nodes[id].select();
this.selection.push(id);
changed = true;
}
}
if (changed) {
// fire the select event
this._trigger('select');
}
return changed;
},
*/
}; };
@ -13569,27 +13611,28 @@ Graph.prototype._onDragStart = function () {
} }
// create an array with the selected nodes and their original location and status // create an array with the selected nodes and their original location and status
var me = this;
this.selection.forEach(function (id) {
var node = me.nodes[id];
if (node) {
var s = {
id: id,
node: node,
// store original x, y, xFixed and yFixed, make the node temporarily Fixed
x: node.x,
y: node.y,
xFixed: node.xFixed,
yFixed: node.yFixed
};
for (var objectId in this.selectionObj) {
if (this.selectionObj.hasOwnProperty(objectId)) {
var object = this.selectionObj[objectId];
if (object instanceof Node) {
var s = {
id: object.id,
node: object,
// store original x, y, xFixed and yFixed, make the node temporarily Fixed
x: object.x,
y: object.y,
xFixed: object.xFixed,
yFixed: object.yFixed
};
node.xFixed = true;
node.yFixed = true;
object.xFixed = true;
object.yFixed = true;
drag.selection.push(s);
drag.selection.push(s);
}
} }
});
}
} }
}; };
@ -14932,7 +14975,6 @@ Graph.prototype._loadSectorSystem = function() {
* @private * @private
*/ */
Graph.prototype._loadSelectionSystem = function() { Graph.prototype._loadSelectionSystem = function() {
this.selection = [];
this.selectionObj = {}; this.selectionObj = {};
for (var mixinFunction in SelectionMixin) { for (var mixinFunction in SelectionMixin) {

+ 7
- 0
src/graph/ClusterMixin.js View File

@ -335,6 +335,10 @@ var ClusterMixin = {
// if child node has been added on smaller scale than current, kick out // if child node has been added on smaller scale than current, kick out
if (childNode.formationScale < this.scale || force == true) { if (childNode.formationScale < this.scale || force == true) {
// remove the selection, first remove the selection from the connected edges
this._unselectConnectedEdges(parentNode);
parentNode.unselect();
// put the child node back in the global nodes object // put the child node back in the global nodes object
this.nodes[containedNodeId] = childNode; this.nodes[containedNodeId] = childNode;
@ -383,6 +387,9 @@ var ClusterMixin = {
// recalculate the size of the node on the next time the node is rendered // recalculate the size of the node on the next time the node is rendered
parentNode.clearSizeCache(); parentNode.clearSizeCache();
// this unselects the rest of the edges
this._unselectConnectedEdges(parentNode);
} }
// check if a further expansion step is possible if recursivity is enabled // check if a further expansion step is possible if recursivity is enabled

+ 12
- 2
src/graph/Edge.js View File

@ -32,6 +32,7 @@ function Edge (properties, graph, constants) {
this.width = constants.edges.width; this.width = constants.edges.width;
this.value = undefined; this.value = undefined;
this.length = constants.edges.length; this.length = constants.edges.length;
this.selected = false;
this.from = null; // a node this.from = null; // a node
this.to = null; // a node this.to = null; // a node
@ -268,7 +269,7 @@ Edge.prototype._drawLine = function(ctx) {
* @private * @private
*/ */
Edge.prototype._getLineWidth = function() { Edge.prototype._getLineWidth = function() {
if (this.from.selected || this.to.selected) {
if (this.selected == true) {
return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv; return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv;
} }
else { else {
@ -617,4 +618,13 @@ Edge._dist = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
*/ */
Edge.prototype.setScale = function(scale) { Edge.prototype.setScale = function(scale) {
this.graphScaleInv = 1.0/scale; this.graphScaleInv = 1.0/scale;
};
};
Edge.prototype.select = function() {
this.selected = true;
}
Edge.prototype.unselect = function() {
this.selected = false;
}

+ 21
- 21
src/graph/Graph.js View File

@ -640,27 +640,28 @@ Graph.prototype._onDragStart = function () {
} }
// create an array with the selected nodes and their original location and status // create an array with the selected nodes and their original location and status
var me = this;
this.selection.forEach(function (id) {
var node = me.nodes[id];
if (node) {
var s = {
id: id,
node: node,
// store original x, y, xFixed and yFixed, make the node temporarily Fixed
x: node.x,
y: node.y,
xFixed: node.xFixed,
yFixed: node.yFixed
};
node.xFixed = true;
node.yFixed = true;
drag.selection.push(s);
for (var objectId in this.selectionObj) {
if (this.selectionObj.hasOwnProperty(objectId)) {
var object = this.selectionObj[objectId];
if (object instanceof Node) {
var s = {
id: object.id,
node: object,
// store original x, y, xFixed and yFixed, make the node temporarily Fixed
x: object.x,
y: object.y,
xFixed: object.xFixed,
yFixed: object.yFixed
};
object.xFixed = true;
object.yFixed = true;
drag.selection.push(s);
}
} }
});
}
} }
}; };
@ -2003,7 +2004,6 @@ Graph.prototype._loadSectorSystem = function() {
* @private * @private
*/ */
Graph.prototype._loadSelectionSystem = function() { Graph.prototype._loadSelectionSystem = function() {
this.selection = [];
this.selectionObj = {}; this.selectionObj = {};
for (var mixinFunction in SelectionMixin) { for (var mixinFunction in SelectionMixin) {

+ 176
- 151
src/graph/SelectionMixin.js View File

@ -108,7 +108,7 @@ var SelectionMixin = {
_getNodeAt : function (pointer) { _getNodeAt : function (pointer) {
// we first check if this is an navigationUI element // we first check if this is an navigationUI element
var positionObject = this._pointerToPositionObject(pointer); var positionObject = this._pointerToPositionObject(pointer);
overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
var overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
// if there are overlapping nodes, select the last one, this is the // if there are overlapping nodes, select the last one, this is the
// one which is drawn on top of the others // one which is drawn on top of the others
@ -121,6 +121,36 @@ var SelectionMixin = {
}, },
/**
* retrieve all edges overlapping with given object, selector is around center
* @param {Object} object An object with parameters left, top, right, bottom
* @return {Number[]} An array with id's of the overlapping nodes
* @private
*/
_getEdgesOverlappingWith : function (object, overlappingEdges) {
var edges = this.edges;
for (var edgeId in edges) {
if (edges.hasOwnProperty(edgeId)) {
if (edges[edgeId].isOverlappingWith(object)) {
overlappingEdges.push(edgeId);
}
}
}
},
/**
* retrieve all nodes overlapping with given object
* @param {Object} object An object with parameters left, top, right, bottom
* @return {Number[]} An array with id's of the overlapping nodes
* @private
*/
_getAllEdgesOverlappingWith : function (object) {
var overlappingEdges = [];
this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges);
return overlappingEdges;
},
/** /**
* Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call
* _getNodeAt and _getEdgesAt, then priortize the selection to user preferences. * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences.
@ -130,18 +160,25 @@ var SelectionMixin = {
* @private * @private
*/ */
_getEdgeAt : function(pointer) { _getEdgeAt : function(pointer) {
return null;
var positionObject = this._pointerToPositionObject(pointer);
var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject);
if (overlappingEdges.length > 0) {
return this.edges[overlappingEdges[overlappingEdges.length - 1]];
}
else {
return null;
}
}, },
/** /**
* Add object to the selection array. The this.selection id array may not be needed.
* Add object to the selection array.
* *
* @param obj * @param obj
* @private * @private
*/ */
_addToSelection : function(obj) { _addToSelection : function(obj) {
this.selection.push(obj.id);
this.selectionObj[obj.id] = obj; this.selectionObj[obj.id] = obj;
}, },
@ -153,12 +190,6 @@ var SelectionMixin = {
* @private * @private
*/ */
_removeFromSelection : function(obj) { _removeFromSelection : function(obj) {
for (var i = 0; i < this.selection.length; i++) {
if (obj.id == this.selection[i]) {
this.selection.splice(i,1);
break;
}
}
delete this.selectionObj[obj.id]; delete this.selectionObj[obj.id];
}, },
@ -174,10 +205,9 @@ var SelectionMixin = {
doNotTrigger = false; doNotTrigger = false;
} }
this.selection = [];
for (var objId in this.selectionObj) {
if (this.selectionObj.hasOwnProperty(objId)) {
this.selectionObj[objId].unselect();
for (var objectId in this.selectionObj) {
if (this.selectionObj.hasOwnProperty(objectId)) {
this.selectionObj[objectId].unselect();
} }
} }
this.selectionObj = {}; this.selectionObj = {};
@ -195,25 +225,55 @@ var SelectionMixin = {
* @private * @private
*/ */
_selectionIsEmpty : function() { _selectionIsEmpty : function() {
if (this.selection.length == 0) {
return true;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
return false;
}
} }
else {
return false;
return true;
},
/**
* select the edges connected to the node that is being selected
*
* @param {Node} node
* @private
*/
_selectConnectedEdges : function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
edge.select();
this._addToSelection(edge);
} }
}, },
/**
* unselect the edges connected to the node that is being selected
*
* @param {Node} node
* @private
*/
_unselectConnectedEdges : function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
edge.unselect();
this._removeFromSelection(edge);
}
},
/** /**
* This is called when someone clicks on a node. either select or deselect it. * This is called when someone clicks on a node. either select or deselect it.
* If there is an existing selection and we don't want to append to it, clear the existing selection * If there is an existing selection and we don't want to append to it, clear the existing selection
* *
* @param {Node} node
* @param {Node || Edge} object
* @param {Boolean} append * @param {Boolean} append
* @param {Boolean} [doNotTrigger] | ignore trigger * @param {Boolean} [doNotTrigger] | ignore trigger
* @private * @private
*/ */
_selectNode : function(node, append, doNotTrigger) {
_selectObject : function(object, append, doNotTrigger) {
if (doNotTrigger === undefined) { if (doNotTrigger === undefined) {
doNotTrigger = false; doNotTrigger = false;
} }
@ -222,14 +282,16 @@ var SelectionMixin = {
this._unselectAll(true); this._unselectAll(true);
} }
if (node.selected == false) {
node.select();
this._addToSelection(node);
if (object.selected == false) {
object.select();
this._addToSelection(object);
if (object instanceof Node) {
this._selectConnectedEdges(object);
}
} }
else { else {
node.unselect();
this._removeFromSelection(node);
object.unselect();
this._removeFromSelection(object);
} }
if (doNotTrigger == false) { if (doNotTrigger == false) {
this._trigger('select'); this._trigger('select');
@ -264,10 +326,16 @@ var SelectionMixin = {
_handleTap : function(pointer) { _handleTap : function(pointer) {
var node = this._getNodeAt(pointer); var node = this._getNodeAt(pointer);
if (node != null) { if (node != null) {
this._selectNode(node,false);
this._selectObject(node,false);
} }
else { else {
this._unselectAll();
var edge = this._getEdgeAt(pointer);
if (edge != null) {
this._selectObject(edge,false);
}
else {
this._unselectAll();
}
} }
this._redraw(); this._redraw();
}, },
@ -299,7 +367,13 @@ var SelectionMixin = {
_handleOnHold : function(pointer) { _handleOnHold : function(pointer) {
var node = this._getNodeAt(pointer); var node = this._getNodeAt(pointer);
if (node != null) { if (node != null) {
this._selectNode(node,true);
this._selectObject(node,true);
}
else {
var edge = this._getEdgeAt(pointer);
if (edge != null) {
this._selectObject(edge,true);
}
} }
this._redraw(); this._redraw();
}, },
@ -321,12 +395,72 @@ var SelectionMixin = {
/** /**
* *
* retrieve the currently selected nodes
* retrieve the currently selected objects
* @return {Number[] | String[]} selection An array with the ids of the * @return {Number[] | String[]} selection An array with the ids of the
* selected nodes. * selected nodes.
*/ */
getSelection : function() { getSelection : function() {
return this.selection.concat([]);
var nodeIdString = this.getSelectedNodes();
/*
var edgeIdString = this.getSelectedEdges();
var idString = "";
if (nodeIdString != "") {
idString = idString.concat("Nodes: ",nodeIdString);
if (edgeIdString != "") {
idString = idString.concat("; ");
}
}
if (edgeIdString != "") {
idString = idString.concat("Edges: ",edgeIdString);
}
*/
return nodeIdString
},
/**
*
* retrieve the currently selected nodes
* @return {String} selection An array with the ids of the
* selected nodes.
*/
getSelectedNodes : function() {
var idString = "", i = 0;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
if (this.selectionObj[objectId] instanceof Node) {
if (i != 0) {
idString = idString.concat(", ");
}
idString = idString.concat(String(objectId));
i++;
}
}
}
return idString
},
/**
*
* retrieve the currently selected edges
* @return {String} selection An array with the ids of the
* selected nodes.
*/
getSelectedEdges : function() {
var idString = "", i = 0;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
if (this.selectionObj[objectId] instanceof Edge) {
if (i != 0) {
idString = idString.concat(", ");
}
idString = idString.concat(String(objectId));
i++;
}
}
}
return idString
}, },
/** /**
@ -340,8 +474,6 @@ var SelectionMixin = {
}, },
/** /**
* // TODO: rework this function, it is from the old system
*
* select zero or more nodes * select zero or more nodes
* @param {Number[] | String[]} selection An array with the ids of the * @param {Number[] | String[]} selection An array with the ids of the
* selected nodes. * selected nodes.
@ -362,7 +494,7 @@ var SelectionMixin = {
if (!node) { if (!node) {
throw new RangeError('Node with id "' + id + '" not found'); throw new RangeError('Node with id "' + id + '" not found');
} }
this._selectNode(node,true,true);
this._selectObject(node,true,true);
} }
this.redraw(); this.redraw();
@ -370,135 +502,28 @@ var SelectionMixin = {
/** /**
* TODO: rework this function, it is from the old system
*
* Validate the selection: remove ids of nodes which no longer exist * Validate the selection: remove ids of nodes which no longer exist
* @private * @private
*/ */
_updateSelection : function () { _updateSelection : function () {
var i = 0;
while (i < this.selection.length) {
var nodeId = this.selection[i];
if (!this.nodes.hasOwnProperty(nodeId)) {
this.selection.splice(i, 1);
delete this.selectionObj[nodeId];
}
else {
i++;
}
}
}
/**
* Unselect selected nodes. If no selection array is provided, all nodes
* are unselected
* @param {Object[]} selection Array with selection objects, each selection
* object has a parameter row. Optional
* @param {Boolean} triggerSelect If true (default), the select event
* is triggered when nodes are unselected
* @return {Boolean} changed True if the selection is changed
* @private
*/
/* _unselectNodes : function(selection, triggerSelect) {
var changed = false;
var i, iMax, id;
if (selection) {
// remove provided selections
for (i = 0, iMax = selection.length; i < iMax; i++) {
id = selection[i];
if (this.nodes.hasOwnProperty(id)) {
this.nodes[id].unselect();
}
var j = 0;
while (j < this.selection.length) {
if (this.selection[j] == id) {
this.selection.splice(j, 1);
changed = true;
}
else {
j++;
for(var objectId in this.selectionObj) {
if(this.selectionObj.hasOwnProperty(objectId)) {
if (this.selectionObj[objectId] instanceof Node) {
if (!this.nodes.hasOwnProperty(objectId)) {
delete this.selectionObj[objectId];
} }
} }
}
}
else if (this.selection && this.selection.length) {
// remove all selections
for (i = 0, iMax = this.selection.length; i < iMax; i++) {
id = this.selection[i];
if (this.nodes.hasOwnProperty(id)) {
this.nodes[id].unselect();
}
changed = true;
}
this.selection = [];
}
if (changed && (triggerSelect == true || triggerSelect == undefined)) {
// fire the select event
this._trigger('select');
}
return changed;
},
*/
/**
* select all nodes on given location x, y
* @param {Array} selection an array with node ids
* @param {boolean} append If true, the new selection will be appended to the
* current selection (except for duplicate entries)
* @return {Boolean} changed True if the selection is changed
* @private
*/
/* _selectNodes : function(selection, append) {
var changed = false;
var i, iMax;
// TODO: the selectNodes method is a little messy, rework this
// check if the current selection equals the desired selection
var selectionAlreadyThere = true;
if (selection.length != this.selection.length) {
selectionAlreadyThere = false;
}
else {
for (i = 0, iMax = Math.min(selection.length, this.selection.length); i < iMax; i++) {
if (selection[i] != this.selection[i]) {
selectionAlreadyThere = false;
break;
else { // assuming only edges and nodes are selected
if (!this.edges.hasOwnProperty(objectId)) {
delete this.selectionObj[objectId];
}
} }
} }
} }
if (selectionAlreadyThere) {
return changed;
}
if (append == undefined || append == false) {
// first deselect any selected node
var triggerSelect = false;
changed = this._unselectNodes(undefined, triggerSelect);
}
}
for (i = 0, iMax = selection.length; i < iMax; i++) {
// add each of the new selections, but only when they are not duplicate
var id = selection[i];
var isDuplicate = (this.selection.indexOf(id) != -1);
if (!isDuplicate) {
this.nodes[id].select();
this.selection.push(id);
changed = true;
}
}
if (changed) {
// fire the select event
this._trigger('select');
}
return changed;
},
*/
}; };

Loading…
Cancel
Save