More operations supported.

This commit is contained in:
Paulo Veiga 2011-12-11 23:47:01 -03:00
parent 9c41f0719c
commit c2748f67cf
8 changed files with 245 additions and 83 deletions

View File

@ -28,3 +28,5 @@ mindplot.collaboration = {};
mindplot.collaboration.framework = {};
mindplot.collaboration.framework.brix = {};
mindplot.collaboration.framework.brix.model = {};
mindplot.nlayout = {};

View File

@ -3,21 +3,29 @@ mindplot.nlayout.ChildrenSorterStrategy = new Class({
},
predict:function(treeSet, parent, position) {
throw "Method must be implemented";
},
sorter: function(treeSet, parent, child, order) {
throw "Method must be implemented";
},
computeChildrenIdByHeights: function(treeSet, node) {
throw "Method must be implemented";
},
computeOffsets:function(treeSet, node) {
throw "Method must be implemented";
},
insert: function(treeSet, parent, child, order) {
throw "Method must be implemented";
},
detach:function(treeSet, node) {
throw "Method must be implemented";
},
predict:function(treeSet, parent, position) {
throw "Method must be implemented";
},
verify:function(treeSet, node) {
throw "Method must be implemented";
}
});

View File

@ -15,10 +15,11 @@ mindplot.nlayout.LayoutManager = new Class({
updateNodeSize: function(id, size) {
var node = this._treeSet.find(id);
node.setSize(size);
// @Todo: finish...
},
updateShirkState: function(id, isShrink) {
// @Todo: finish...
},
connectNode: function(parentId, childId, order) {
@ -29,12 +30,9 @@ mindplot.nlayout.LayoutManager = new Class({
this._layout.connectNode(parentId, childId, order);
},
disconnectNode: function(sourceId) {
},
deleteNode : function(id) {
disconnectNode: function(id) {
$assert($defined(id), "id can not be null");
this._layout.disconnectNode(id);
},
addNode:function(id, size, position) {
@ -43,6 +41,20 @@ mindplot.nlayout.LayoutManager = new Class({
this._treeSet.add(result);
},
removeNode: function(id) {
$assert($defined(id), "id can not be null");
var node = this._treeSet.find(id);
// Is It connected ?
if (this._treeSet.getParent(node)) {
this.disconnectNode(id);
}
// Remove the all the branch ...
this._treeSet.remove(id);
},
predict: function(parentId, childId, position) {
$assert($defined(parentId), "parentId can not be null");
$assert($defined(childId), "childId can not be null");
@ -50,7 +62,7 @@ mindplot.nlayout.LayoutManager = new Class({
var parent = this._treeSet.find(parentId);
var sorter = parent.getSorter();
var result = sorter.predict(parent, this._treeSet, position);
return sorter.predict(parent, this._treeSet, position);
},
dump: function() {
@ -64,13 +76,12 @@ mindplot.nlayout.LayoutManager = new Class({
// Collect changes ...
this._collectChanges();
if (fireEvents) {
this.flushEvents();
if (!$(fireEvents) || fireEvents) {
this._flushEvents();
}
},
flushEvents: function() {
_flushEvents: function() {
this._events.forEach(function(event) {
this.fireEvent('change', event);
}, this);

View File

@ -1,6 +1,6 @@
mindplot.nlayout.Node = new Class({
initialize:function(id, size, position, sorter) {
$assert(!isNaN(id), "id can not be null");
$assert(typeof id === 'number' && isFinite(id), "id can not be null");
$assert(size, "size can not be null");
$assert(position, "position can not be null");
$assert(sorter, "sorter can not be null");
@ -18,7 +18,7 @@ mindplot.nlayout.Node = new Class({
},
setOrder: function(order) {
$assert(!isNaN(order), "Order can not be null");
$assert(typeof order === 'number' && isFinite(order), "Order can not be null. Value:" + order);
this._setProperty('order', order, false);
},
@ -64,8 +64,8 @@ mindplot.nlayout.Node = new Class({
setPosition : function(position) {
$assert($defined(position), "Position can not be null");
$assert(!isNaN(position.x), "x can not be null");
$assert(!isNaN(position.y), "y can not be null");
$assert($defined(position.x), "x can not be null");
$assert($defined(position.y), "y can not be null");
this._setProperty('position', Object.clone(position));
},
@ -110,7 +110,7 @@ mindplot.nlayout.Node = new Class({
toString: function() {
return "[order:" + this.getOrder() + ", position: {" + this.getPosition().x + "," + this.getPosition().y + "}]";
return "[id:" + this.getId() + ", order:" + this.getOrder() + ", position: {" + this.getPosition().x + "," + this.getPosition().y + "}]";
}
});

View File

@ -1,8 +1,6 @@
mindplot.nlayout.OriginalLayout = new Class({
initialize: function(treeSet) {
this._treeSet = treeSet;
this._heightByNode = {};
},
createNode:function(id, size, position, type) {
@ -11,7 +9,7 @@ mindplot.nlayout.OriginalLayout = new Class({
$assert(position, "position can not be null");
$assert(type, "type can not be null");
var strategy = type === 'root' ? mindplot.nlayout.OriginalLayout.GRID_SORTER : mindplot.nlayout.OriginalLayout.SYMETRIC_SORTER;
var strategy = type === 'root' ? mindplot.nlayout.OriginalLayout.GRID_SORTER : mindplot.nlayout.OriginalLayout.SYMETRIC_SORTER;
return new mindplot.nlayout.Node(id, size, position, strategy);
},
@ -20,17 +18,33 @@ mindplot.nlayout.OriginalLayout = new Class({
var parent = this._treeSet.find(parentId);
var child = this._treeSet.find(childId);
// Connect the new node ...
this._treeSet.connect(parentId, childId);
// Insert the new node ...
var sorter = parent.getSorter();
sorter.insert(this._treeSet, parent, child, order);
// Connect the new node ...
this._treeSet.connect(parentId, childId);
// Fire a basic validation ...
sorter.verify(this._treeSet, parent);
},
disconnectNode: function(nodeId) {
var node = this._treeSet.find(nodeId);
$assert(this._treeSet.getParent(node),"Node already disconnected");
// Remove from children list.
var sorter = node.getSorter();
sorter.detach(this._treeSet, node);
// Disconnect the new node ...
this._treeSet.disconnect(nodeId);
// Fire a basic validation ...
sorter.verify(this._treeSet, node);
},
layout: function() {
var roots = this._treeSet.getTreeRoots();
roots.forEach(function(node) {
@ -42,12 +56,7 @@ mindplot.nlayout.OriginalLayout = new Class({
var heightById = sorter.computeChildrenIdByHeights(this._treeSet, node);
this._layoutChildren(node, heightById);
}.bind(this));
// Finally, return the list of nodes and properties that has been changed during the layout ...
}, this);
},
_layoutChildren: function(node, heightById) {
@ -57,11 +66,11 @@ mindplot.nlayout.OriginalLayout = new Class({
var childrenOrderMoved = children.some(function(child) {
return child.hasOrderChanged();
});
var heightChanged = this._heightByNode[nodeId] != heightById[nodeId];
throw "Esto no esta bien:"+ this._heightByNode;
// If ether any of the nodes has been changed of position or the height of the children is not
// the same, children nodes must be repositioned ....
var newBranchHeight = heightById[nodeId];
var heightChanged = node._branchHeight != newBranchHeight;
if (childrenOrderMoved || heightChanged) {
var sorter = node.getSorter();
@ -73,12 +82,14 @@ mindplot.nlayout.OriginalLayout = new Class({
var newPos = {x:parentPosition.x + offset.x,y:parentPosition.y + offset.y};
this._treeSet.updateBranchPosition(child, newPos);
}.bind(this));
node._branchHeight = newBranchHeight;
}
// Continue reordering the children nodes ...
children.forEach(function(child) {
this._layoutChildren(child, heightById);
}.bind(this));
}, this);
}
});

View File

@ -23,31 +23,32 @@ mindplot.nlayout.RootedTreeSet = new Class({
this._rootNodes.push(this._decodate(node));
},
remove: function(node) {
throw "Must be implemted";
remove: function(nodeId) {
$assert($defined(nodeId), 'nodeId can not be null');
var node = this.find(nodeId);
this._rootNodes.erase(node);
},
connect: function(parentId, childId) {
$assert($defined(parentId), 'parent can not be null');
$assert($defined(childId), 'child can not be null');
var parent = this.find(parentId, true);
var parent = this.find(parentId);
var child = this.find(childId, true);
$assert(!child._parent, 'node already connected. Id:' + child.getId() + ",previous:" + child._parent);
parent._children.push(child);
child._parent = parent;
this._rootNodes.erase(child);
},
disconnect: function(nodeId) {
$assert(node, 'node can not be null');
$assert(node._parent, 'child node not connected connected');
$assert($defined(nodeId), 'nodeId can not be null');
var node = this.find(nodeId);
$assert(node._parent, "Node is not connected");
node._parent._children.erase(node);
this._isolated.push(node);
this._rootNodes.push(node);
node._parent = null;
},
@ -63,7 +64,7 @@ mindplot.nlayout.RootedTreeSet = new Class({
break;
}
}
$assert(validate ? result : true, 'node could not be found id:' + id);
$assert($defined(validate) ? result : true, 'node could not be found id:' + id);
return result;
},
@ -91,6 +92,11 @@ mindplot.nlayout.RootedTreeSet = new Class({
return node._children;
},
getParent:function(node) {
$assert(node, 'node can not be null');
return node._parent;
},
dump: function() {
var branches = this._rootNodes;
var result = "";

View File

@ -65,28 +65,42 @@ mindplot.nlayout.SymetricSorder = new Class({
},
insert: function(treeSet, parent, child, order) {
var children = treeSet.getChildren(parent);
var children = this._getSortedChildren(treeSet, parent);
$assert(order <= children.length, "Order must be continues and can not have holes. Order:" + order);
// Sort array list ..
children.sort(function(a, b) {
return a.getOrder() - b.getOrder()
});
// Shift all the elements in one .
for (var i = order; i < children.length; i++) {
var node = children[i];
node.setOrder(node.getOrder() + 1);
node.setOrder(i + 1);
}
child.setOrder(order);
},
verify:function(treeSet, node) {
// Check that all is consistent ...
var children = treeSet.getChildren(node);
children.sort(function(a, b) {
detach:function(treeSet, node) {
var parent = treeSet.getParent(node);
var children = this._getSortedChildren(treeSet, parent);
var order = node.getOrder();
$assert(children[order] === node, "Node seems not to be in the right position");
// Shift all the nodes ...
for (var i = node.getOrder() + 1; i < children.length; i++) {
var child = children[i];
child.setOrder(child.getOrder() - 1);
}
node.setOrder(0);
},
_getSortedChildren:function(treeSet, node) {
var result = treeSet.getChildren(node);
result.sort(function(a, b) {
return a.getOrder() - b.getOrder()
});
return result;
},
verify:function(treeSet, node) {
// Check that all is consistent ...
var children = this._getSortedChildren(treeSet, node);
for (var i = 0; i < children.length; i++) {
$assert(children[i].getOrder() == i, "missing order elements");
@ -98,10 +112,7 @@ mindplot.nlayout.SymetricSorder = new Class({
$assert(node, "node can no be null.");
$assert("order can no be null.");
var children = treeSet.getChildren(node);
children.sort(function(a, b) {
return a.getOrder() - b.getOrder()
});
var children = this._getSortedChildren(treeSet, node);
// Compute heights ...
var heights = children.map(function(child) {

View File

@ -2,10 +2,11 @@ mindplot.nlayout.TestSuite = new Class({
Extends: mindplot.nlayout.ChildrenSorterStrategy,
initialize:function() {
// this.testAligned();
this.testAligned();
this.testEvents();
// @ Agregar tests que garantice que no se reposicional cosan inecesariamente 2 veces...
this.testEventsComplex();
this.testDisconnect();
this.testRemoveNode();
},
testAligned: function() {
@ -37,26 +38,15 @@ mindplot.nlayout.TestSuite = new Class({
manager.connectNode(0, 2, 0);
manager.connectNode(1, 3, 0);
// Reposition ...
manager.layout();
console.log("Updated tree:");
manager.dump();
// Listen for changes ...
console.log("Updated nodes ...");
// Basic layout repositioning ...
console.log("-- Updated tree ---");
var events = [];
manager.addEvent('change', function(event) {
console.log("Updated nodes: {id:" + event.getId() + ", order: " + event.getOrder() + ",position: {" + event.getPosition().x + "," + event.getPosition().y + "}");
events.push(event);
});
manager.flushEvents();
// Second flush must not fire events ...
console.log("---- Test Flush ---");
events.empty();
manager.flushEvents();
$assert(events.length == 0, "Event should not be fire twice.");
manager.layout(true);
manager.dump();
// Ok, if a new node is added, this an event should be fired ...
console.log("---- Layout without changes should not affect the tree ---");
@ -64,7 +54,130 @@ mindplot.nlayout.TestSuite = new Class({
manager.layout(true);
$assert(events.length == 0, "Unnecessary tree updated.");
},
testEventsComplex: function() {
var size = {width:10,height:10};
var position = {x:0,y:0};
var manager = new mindplot.nlayout.LayoutManager(0, size);
// Add 3 nodes...
manager.addNode(1, size, position);
manager.addNode(2, size, position);
manager.addNode(3, size, position);
manager.addNode(4, size, position);
// Now connect one with two....
manager.connectNode(0, 1, 0);
manager.connectNode(1, 2, 0);
manager.connectNode(1, 3, 1);
var events = [];
manager.addEvent('change', function(event) {
console.log("Updated nodes: {id:" + event.getId() + ", order: " + event.getOrder() + ",position: {" + event.getPosition().x + "," + event.getPosition().y + "}");
events.push(event);
});
// Reposition ...
manager.layout(true);
manager.dump();
// Add a new node and connect. Only children nodes should be affected.
console.log("---- Connect a new node ---");
events.empty();
manager.connectNode(1, 4, 2);
manager.layout(true);
manager.dump();
// @todo: This seems no to be ok...
$assert(events.length == 4, "Only 3 nodes should be repositioned.");
},
testDisconnect: function() {
var size = {width:10,height:10};
var position = {x:0,y:0};
var manager = new mindplot.nlayout.LayoutManager(0, size);
// Prepare a sample graph ...
manager.addNode(1, size, position);
manager.addNode(2, size, position);
manager.addNode(3, size, position);
manager.addNode(4, size, position);
manager.connectNode(0, 1, 0);
manager.connectNode(1, 2, 0);
manager.connectNode(1, 3, 1);
manager.connectNode(3, 4, 0);
var events = [];
manager.addEvent('change', function(event) {
var pos = event.getPosition();
var posStr = pos ? ",position: {" + pos.x + "," + event.getPosition().y : "";
console.log("Updated nodes: {id:" + event.getId() + ", order: " + event.getOrder() + posStr + "}");
events.push(event);
});
manager.layout(true);
manager.dump();
// Now, disconnect one node ...
console.log("--- Disconnect a single node ---");
events.empty();
manager.disconnectNode(2);
manager.layout(true);
manager.dump();
$assert(events.some(
function(event) {
return event.getId() == 2;
}), "Event for disconnected node seems not to be propagated");
// Great, let's disconnect a not with children.
console.log("--- Disconnect a node with children ---");
manager.disconnectNode(3);
manager.layout(true);
manager.dump();
$assert(events.some(
function(event) {
return event.getId() == 2;
}), "Event for disconnected node seems not to be propagated");
},
testRemoveNode: function() {
var size = {width:10,height:10};
var position = {x:0,y:0};
var manager = new mindplot.nlayout.LayoutManager(0, size);
// Prepare a sample graph ...
manager.addNode(1, size, position);
manager.addNode(2, size, position);
manager.addNode(3, size, position);
manager.addNode(4, size, position);
manager.connectNode(0, 1, 0);
manager.connectNode(1, 2, 0);
manager.connectNode(1, 3, 1);
manager.connectNode(3, 4, 0);
var events = [];
manager.addEvent('change', function(event) {
var pos = event.getPosition();
var posStr = pos ? ",position: {" + pos.x + "," + event.getPosition().y : "";
console.log("Updated nodes: {id:" + event.getId() + ", order: " + event.getOrder() + posStr + "}");
events.push(event);
});
manager.layout(true);
manager.dump();
// Test removal of a connected node ...
console.log("--- Remove node 3 ---");
manager.removeNode(3);
manager.layout(true);
manager.dump();
}
});