diff --git a/src/git.js b/src/git.js index be78dddc..ec26adc0 100644 --- a/src/git.js +++ b/src/git.js @@ -48,16 +48,22 @@ GitEngine.prototype.init = function() { GitEngine.prototype.exportTree = function() { // need to export all commits, their connectivity / messages, branches, and state of head. // this would be simple if didn't have circular structures.... :P + var totalExport = { + branches: {}, + commits: {}, + HEAD: null + }; - var branches = this.branchCollection.toJSON(); - _.each(branches, function(branch) { + _.each(this.branchCollection.toJSON(), function(branch) { branch.target = branch.target.get('id'); branch.visBranch = undefined; + + totalExport.branches[branch.id] = branch; }); - var commits = this.commitCollection.toJSON(); - _.each(commits, function(commit) { + _.each(this.commitCollection.toJSON(), function(commit) { commit.visNode = undefined; + commit.children = []; // convert parents var parents = []; @@ -66,26 +72,115 @@ GitEngine.prototype.exportTree = function() { }); commit.parents = parents; - var children = []; - _.each(commit.children, function(child) { - children.push(child.get('id')); - }); - commit.children = children; + totalExport.commits[commit.id] = commit; }, this); var HEAD = this.HEAD.toJSON(); HEAD.target = HEAD.target.get('id'); + totalExport.HEAD = HEAD; - return { - branches: branches, - commits: commits, - HEAD: HEAD - }; + return totalExport; }; GitEngine.prototype.loadTree = function(tree) { + // first clear everything + this.removeAll(); + // now we do the loading part + var createdSoFar = {}; + _.each(tree.commits, function(commitJSON) { + var commit = this.getOrMakeRecursive(tree, createdSoFar, commitJSON.id); + this.commitCollection.add(commit); + }, this); + _.each(tree.branches, function(branchJSON) { + var branch = this.getOrMakeRecursive(tree, createdSoFar, branchJSON.id); + this.branchCollection.add(branch); + }, this); + + var HEAD = this.getOrMakeRecursive(tree, createdSoFar, tree.HEAD.id); + this.HEAD = HEAD; + + gitVisuals.refreshTreeHarsh(); +}; + +GitEngine.prototype.getOrMakeRecursive = function(tree, createdSoFar, objID) { + if (createdSoFar[objID]) { + // base case + return createdSoFar[objID]; + } + + var getType = function(tree, id) { + if (tree.commits[id]) { + return 'commit'; + } else if (tree.branches[id]) { + return 'branch'; + } else if (id == 'HEAD') { + return 'HEAD'; + } + throw new Error("bad type for " + id); + }; + + // figure out what type + var type = getType(tree, objID); + + if (type == 'HEAD') { + var headJSON = tree.HEAD; + var HEAD = new Ref(_.extend( + tree.HEAD, + { + target: this.getOrMakeRecursive(tree, createdSoFar, headJSON.target) + } + )); + createdSoFar[objID] = HEAD; + return HEAD; + } + + if (type == 'branch') { + var branchJSON = tree.branches[objID]; + + var branch = new Branch(_.extend( + tree.branches[objID], + { + target: this.getOrMakeRecursive(tree, createdSoFar, branchJSON.target) + } + )); + createdSoFar[objID] = branch; + return branch; + } + + if (type == 'commit') { + // for commits, we need to grab all the parents + var commitJSON = tree.commits[objID]; + + var parentObjs = []; + _.each(commitJSON.parents, function(parentID) { + parentObjs.push(this.getOrMakeRecursive(tree, createdSoFar, parentID)); + }, this); + + var commit = new Commit(_.extend( + commitJSON, + { + parents: parentObjs + } + )); + createdSoFar[objID] = commit; + return commit; + } + + throw new Error('ruh rho!! unsupported tyep for ' + objID); +}; + +GitEngine.prototype.removeAll = function() { + this.branchCollection.each(function(branch) { + branch.get('visBranch').remove(); + }, this); + this.commitCollection.each(function(commit) { + commit.get('visNode').removeAll(); + }, this); + + this.branchCollection.reset(); + this.commitCollection.reset(); }; GitEngine.prototype.getDetachedHead = function() { diff --git a/src/tree.js b/src/tree.js index 300572dd..ef65edac 100644 --- a/src/tree.js +++ b/src/tree.js @@ -1,4 +1,14 @@ -var VisBranch = Backbone.Model.extend({ +var VisBase = Backbone.Model.extend({ + removeKeys: function(keys) { + _.each(keys, function(key) { + if (this.get(key)) { + this.get(key).remove(); + } + }, this); + } +}); + +var VisBranch = VisBase.extend({ defaults: { pos: null, text: null, @@ -172,7 +182,7 @@ var VisBranch = Backbone.Model.extend({ getTextSize: function() { var getTextWidth = function(visBranch) { var textNode = visBranch.get('text').node; - return textNode.clientWidth; + return (textNode === null) ? 1 : textNode.clientWidth; }; var textNode = this.get('text').node; @@ -254,13 +264,7 @@ var VisBranch = Backbone.Model.extend({ }, remove: function() { - var keys = ['text', 'arrow', 'rect']; - _.each(keys, function(key) { - if (this.get(key)) { - this.get(key).remove(); - } - }, this); - + this.removeKeys(['text', 'arrow', 'rect']); // also need to remove from gitVisuals gitVisuals.removeVisBranch(this); }, @@ -363,22 +367,24 @@ var VisBranch = Backbone.Model.extend({ }, animateToAttr: function(attr, speed, easing) { - var func = 'animate'; if (speed == 0) { - func = 'attr'; + this.get('text').attr(attr.text); + this.get('rect').attr(attr.rect); + this.get('arrow').attr(attr.arrow); + return; } var s = speed !== undefined ? speed : this.get('animationSpeed'); var e = easing || this.get('animationEasing'); - this.get('text').stop()[func](attr.text, s, e); - this.get('rect').stop()[func](attr.rect, s, e); - this.get('arrow').stop()[func](attr.arrow, s, e); + this.get('text').stop().animate(attr.text, s, e); + this.get('rect').stop().animate(attr.rect, s, e); + this.get('arrow').stop().animate(attr.arrow, s, e); } }); -var VisNode = Backbone.Model.extend({ +var VisNode = VisBase.extend({ defaults: { depth: undefined, maxWidth: null, @@ -526,7 +532,6 @@ var VisNode = Backbone.Model.extend({ }, animateToSnapshot: function(snapShot, speed, easing) { - console.log('animating to snapshot', snapShot, this.getID()); if (!snapShot[this.getID()]) { return; } @@ -534,16 +539,17 @@ var VisNode = Backbone.Model.extend({ }, animateToAttr: function(attr, speed, easing) { - var func = 'animate'; if (speed == 0) { - func = 'attr'; + this.get('circle').attr(attr.circle); + this.get('text').attr(attr.text); + return; } var s = speed !== undefined ? speed : this.get('animationSpeed'); var e = easing || this.get('animationEasing'); - this.get('circle').stop()[func](attr.circle, s, e); - this.get('text').stop()[func](attr.text, s, e); + this.get('circle').stop().animate(attr.circle, s, e); + this.get('text').stop().animate(attr.text, s, e); }, getScreenCoords: function() { @@ -578,6 +584,7 @@ var VisNode = Backbone.Model.extend({ setBirthFromSnapshot: function(beforeSnapshot) { // first get parent attribute + // woof bad data access. TODO var parentID = this.get('commit').get('parents')[0].get('visNode').getID(); var parentAttr = beforeSnapshot[parentID]; @@ -697,6 +704,21 @@ var VisNode = Backbone.Model.extend({ }, this); }, + remove: function() { + this.removeKeys(['circle'], ['text']); + // needs a manual removal of text for whatever reason + this.get('text').remove(); + + gitVisuals.removeVisNode(this); + }, + + removeAll: function() { + this.remove(); + _.each(this.get('outgoingEdges'), function(edge) { + edge.remove(); + }, this); + }, + genGraphics: function(paper) { var pos = this.getScreenCoords(); var textPos = this.getTextScreenCoords(); @@ -722,7 +744,7 @@ var VisNode = Backbone.Model.extend({ } }); -var VisEdge = Backbone.Model.extend({ +var VisEdge = VisBase.extend({ defaults: { tail: null, head: null, @@ -749,6 +771,11 @@ var VisEdge = Backbone.Model.extend({ this.get('tail').get('outgoingEdges').push(this); }, + remove: function() { + this.removeKeys(['path']); + gitVisuals.removeVisEdge(this); + }, + genSmoothBezierPathString: function(tail, head) { var tailPos = tail.getScreenCoords(); var headPos = head.getScreenCoords(); @@ -870,13 +897,13 @@ var VisEdge = Backbone.Model.extend({ }, animateToAttr: function(attr, speed, easing) { - var func = 'animate'; if (speed == 0) { - func = 'attr'; + this.get('path').attr(attr.path); + return; } this.get('path').toBack(); - this.get('path').stop()[func]( + this.get('path').stop().animate( attr.path, speed !== undefined ? speed : this.get('animationSpeed'), easing || this.get('animationEasing') diff --git a/src/visuals.js b/src/visuals.js index 7bfdef4f..a1ca4a87 100644 --- a/src/visuals.js +++ b/src/visuals.js @@ -3,7 +3,7 @@ function GitVisuals(options) { this.branchCollection = options.branchCollection; this.visNodeMap = {}; - this.edgeCollection = new VisEdgeCollection(); + this.visEdgeCollection = new VisEdgeCollection(); this.visBranchCollection = new VisBranchCollection(); this.commitMap = {}; @@ -81,7 +81,7 @@ GitVisuals.prototype.animateAllFromAttrToAttr = function(fromSnapshot, toSnapsho this.visBranchCollection.each(function(visBranch) { animate(visBranch); }); - this.edgeCollection.each(function(visEdge) { + this.visEdgeCollection.each(function(visEdge) { animate(visEdge); }); _.each(this.visNodeMap, function(visNode) { @@ -118,7 +118,7 @@ GitVisuals.prototype.genSnapshot = function() { snapshot[visBranch.getID()] = visBranch.getAttributes(); }, this); - this.edgeCollection.each(function(visEdge) { + this.visEdgeCollection.each(function(visEdge) { snapshot[visEdge.getID()] = visEdge.getAttributes(); }, this); @@ -354,6 +354,14 @@ GitVisuals.prototype.removeVisBranch = function(visBranch) { this.visBranchCollection.remove(visBranch); }; +GitVisuals.prototype.removeVisNode = function(visNode) { + this.visNodeMap[visNode.getID()] = undefined; +}; + +GitVisuals.prototype.removeVisEdge = function(visEdge) { + this.visEdgeCollection.remove(visEdge); +}; + GitVisuals.prototype.animateRefs = function(speed) { this.visBranchCollection.each(function(visBranch) { visBranch.animateUpdatedPos(speed); @@ -361,7 +369,7 @@ GitVisuals.prototype.animateRefs = function(speed) { }; GitVisuals.prototype.animateEdges = function(speed) { - this.edgeCollection.each(function(edge) { + this.visEdgeCollection.each(function(edge) { edge.animateUpdatedPath(speed); }, this); }; @@ -431,7 +439,7 @@ GitVisuals.prototype.addEdge = function(idTail, idHead) { tail: visNodeTail, head: visNodeHead }); - this.edgeCollection.add(edge); + this.visEdgeCollection.add(edge); if (this.paperReady) { edge.genGraphics(paper); @@ -472,7 +480,7 @@ GitVisuals.prototype.drawTreeFirstTime = function() { visNode.genGraphics(paper); }, this); - this.edgeCollection.each(function(edge) { + this.visEdgeCollection.each(function(edge) { edge.genGraphics(paper); }, this);