diff --git a/src/animationFactory.js b/src/animationFactory.js index e34ee949..dcbba96f 100644 --- a/src/animationFactory.js +++ b/src/animationFactory.js @@ -42,6 +42,57 @@ AnimationFactory.prototype.genCommitBirthAnimation = function(animationQueue, co })); }; +AnimationFactory.prototype.overrideOpacityDepth2 = function(attr, opacity) { + opacity = (opacity === undefined) ? 1 : opacity; + + var newAttr = {}; + + _.each(attr, function(partObj, partName) { + newAttr[partName] = {}; + _.each(partObj, function(val, key) { + if (key == 'opacity') { + newAttr[partName][key] = opacity; + } else { + newAttr[partName][key] = val; + } + }); + }); + return newAttr; +}; + +AnimationFactory.prototype.overrideOpacityDepth3 = function(snapShot, opacity) { + var newSnap = {}; + + _.each(snapShot, function(visObj, visID) { + newSnap[visID] = this.overrideOpacityDepth2(visObj, opacity); + }, this); + console.log(newSnap); + return newSnap; +}; + +AnimationFactory.prototype.genCommitBirthClosureFromSnapshot = function(step) { + + var time = GRAPHICS.defaultAnimationTime * 1.0; + var bounceTime = time * 2.0; + + var visNode = step.newCommit.get('visNode'); + var afterAttrWithOpacity = this.overrideOpacityDepth2(step.afterSnapshot[visNode.getID()]); + var afterSnapWithOpacity = this.overrideOpacityDepth3(step.afterSnapshot); + + var animation = function() { + // TODO -- unhighlight old commit visnode here + + visNode.setBirthFromSnapshot(step.beforeSnapshot); + visNode.parentInFront(); + gitVisuals.visBranchesFront(); + + visNode.animateToAttr(afterAttrWithOpacity, bounceTime, 'bounce'); + visNode.animateOutgoingEdgesToAttr(afterSnapWithOpacity, bounceTime); + }; + + return animation; +}; + AnimationFactory.prototype.refreshTree = function(animationQueue) { animationQueue.add(new Animation({ closure: function() { @@ -52,6 +103,34 @@ AnimationFactory.prototype.refreshTree = function(animationQueue) { }; AnimationFactory.prototype.rebaseAnimation = function(animationQueue, rebaseResponse, gitEngine) { + // HIGHLIGHTING PART!!!! + var rebaseSteps = rebaseResponse.rebaseSteps; + _.each(rebaseSteps, function(rebaseStep) { + var snapshotPart = this.genFromToSnapshotAnimation(rebaseStep.beforeSnapshot, rebaseStep.afterSnapshot); + var birthPart = this.genCommitBirthClosureFromSnapshot(rebaseStep); + + var animation = function() { + snapshotPart(); + birthPart(); + }; + + animationQueue.add(new Animation({ + closure: animation + })); + + /* + rebaseStep.oldCommit + rebaseStep.newCommit + rebaseStep.beforeSnapshot + rebaseStep.afterSnapshot*/ + }, this); +}; + +AnimationFactory.prototype.genFromToSnapshotAnimation = function(beforeSnapshot, afterSnapshot) { + return function() { + console.log('from', beforeSnapshot, 'to', afterSnapshot); + gitVisuals.animateAllFromAttrToAttr(beforeSnapshot, afterSnapshot); + }; }; diff --git a/src/git.js b/src/git.js index 5455240a..9dc0a557 100644 --- a/src/git.js +++ b/src/git.js @@ -553,6 +553,7 @@ GitEngine.prototype.rebaseStarter = function() { }; GitEngine.prototype.rebaseAnimation = function(response) { + /* // TODO: move to animation factory var start = function() { // maybe search stuff?? @@ -599,6 +600,7 @@ GitEngine.prototype.rebaseAnimation = function(response) { }, this); animationFactory.refreshTree(this.animationQueue); + */ }; GitEngine.prototype.rebase = function(targetSource, currentLocation) { diff --git a/src/tree.js b/src/tree.js index a320625c..31e8f6ea 100644 --- a/src/tree.js +++ b/src/tree.js @@ -353,16 +353,27 @@ var VisBranch = Backbone.Model.extend({ animateUpdatedPos: function(speed, easing) { var attr = this.getAttributes(); - this.animateFromAttr(attr, speed, easing); + this.animateToAttr(attr, speed, easing); }, - animateFromAttr: function(attr, speed, easing) { + animateFromAttrToAttr: function(fromAttr, toAttr, speed, easing) { + // an animation of 0 is essentially setting the attribute directly + this.animateToAttr(fromAttr, 0); + this.animateToAttr(toAttr, speed, easing); + }, + + animateToAttr: function(attr, speed, easing) { + var func = 'animate'; + if (speed == 0) { + func = 'attr'; + } + var s = speed !== undefined ? speed : this.get('animationSpeed'); var e = easing || this.get('animationEasing'); - 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); + 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); } }); @@ -389,6 +400,10 @@ var VisNode = Backbone.Model.extend({ stroke: GRAPHICS.defaultNodeStroke }, + getID: function() { + return this.get('id'); + }, + validateAtInit: function() { if (!this.get('id')) { throw new Error('need id for mapping'); @@ -480,15 +495,26 @@ var VisNode = Backbone.Model.extend({ animateUpdatedPosition: function(speed, easing) { var attr = this.getAttributes(); - this.animateFromAttr(attr, speed, easing); + this.animateToAttr(attr, speed, easing); }, - animateFromAttr: function(attr, speed, easing) { + animateFromAttrToAttr: function(fromAttr, toAttr, speed, easing) { + // an animation of 0 is essentially setting the attribute directly + this.animateToAttr(fromAttr, 0); + this.animateToAttr(toAttr, speed, easing); + }, + + animateToAttr: function(attr, speed, easing) { + var func = 'animate'; + if (speed == 0) { + func = 'attr'; + } + var s = speed !== undefined ? speed : this.get('animationSpeed'); var e = easing || this.get('animationEasing'); - this.get('circle').stop().animate(attr.circle, s, e); - this.get('text').stop().animate(attr.text, s, e); + this.get('circle').stop()[func](attr.circle, s, e); + this.get('text').stop()[func](attr.text, s, e); }, getScreenCoords: function() { @@ -521,9 +547,43 @@ var VisNode = Backbone.Model.extend({ }); }, + setBirthFromSnapshot: function(beforeSnapshot) { + // first get parent attribute + var parentID = this.get('commit').get('parents')[0].get('visNode').getID(); + var parentAttr = beforeSnapshot[parentID]; + + // then set myself faded on top of parent + this.get('circle').attr({ + opacity: 0, + r: 0, + cx: parentAttr.circle.cx, + cy: parentAttr.circle.cy + }); + + this.get('text').attr({ + opacity: 0, + x: parentAttr.text.x, + y: parentAttr.text.y + }); + + // then do edges + var parentCoords = { + x: parentAttr.circle.cx, + y: parentAttr.circle.cy + }; + this.setOutgoingEdgesBirthPosition(parentCoords); + }, + setBirth: function() { this.setBirthPosition(); - this.setOutgoingEdgesBirthPosition(); + this.setOutgoingEdgesBirthPosition(this.getParentScreenCoords()); + }, + + animateOutgoingEdgesToAttr: function(snapShot, speed, easing) { + _.each(this.get('outgoingEdges'), function(edge) { + var attr = snapShot[edge.getID()]; + edge.animateToAttr(attr); + }, this); }, animateOutgoingEdges: function(speed, easing) { @@ -535,12 +595,12 @@ var VisNode = Backbone.Model.extend({ animateOutgoingEdgesFromSnapshot: function(snapshot, speed, easing) { _.each(this.get('outgoingEdges'), function(edge) { var attr = snapshot[edge.getID()]; - edge.animateFromAttr(attr, speed, easing); + edge.animateToAttr(attr, speed, easing); }, this); }, - setOutgoingEdgesBirthPosition: function() { - var parentCoords = this.getParentScreenCoords(); + setOutgoingEdgesBirthPosition: function(parentCoords) { + _.each(this.get('outgoingEdges'), function(edge) { var headPos = edge.get('head').getScreenCoords(); var path = edge.genSmoothBezierPathStringFromCoords(parentCoords, headPos); @@ -747,12 +807,23 @@ var VisEdge = Backbone.Model.extend({ animateUpdatedPath: function(speed, easing) { var attr = this.getAttributes(); - this.animateFromAttr(attr, speed, easing); + this.animateToAttr(attr, speed, easing); }, - animateFromAttr: function(attr, speed, easing) { + animateFromAttrToAttr: function(fromAttr, toAttr, speed, easing) { + // an animation of 0 is essentially setting the attribute directly + this.animateToAttr(fromAttr, 0); + this.animateToAttr(toAttr, speed, easing); + }, + + animateToAttr: function(attr, speed, easing) { + var func = 'animate'; + if (speed == 0) { + func = 'attr'; + } + this.get('path').toBack(); - this.get('path').stop().animate( + this.get('path').stop()[func]( attr.path, speed !== undefined ? speed : this.get('animationSpeed'), easing || this.get('animationEasing') diff --git a/src/visuals.js b/src/visuals.js index 794e8d6a..0a7c934c 100644 --- a/src/visuals.js +++ b/src/visuals.js @@ -64,6 +64,27 @@ GitVisuals.prototype.toScreenCoords = function(pos) { }; }; +GitVisuals.prototype.animateAllFromAttrToAttr = function(fromSnapshot, toSnapshot) { + var animate = function(obj) { + var id = obj.getID(); + if (!fromSnapshot[id] || !toSnapshot[id]) { + console.warn('this obj doesnt exist yet', id); + return; + } + obj.animateFromAttrToAttr(fromSnapshot[id], toSnapshot[id]); + }; + + this.visBranchCollection.each(function(visBranch) { + animate(visBranch); + }); + this.edgeCollection.each(function(visEdge) { + animate(visEdge); + }); + _.each(this.visNodeMap, function(visNode) { + animate(visNode); + }); +}; + /*************************************** == BEGIN Tree Calculation Parts == _ __ __ _ @@ -101,6 +122,10 @@ GitVisuals.prototype.genSnapshot = function() { }; GitVisuals.prototype.refreshTree = function(speed) { + if (!this.paperReady) { + return; + } + // this method can only be called after graphics are rendered this.fullCalc(); @@ -362,12 +387,9 @@ GitVisuals.prototype.canvasResize = function(width, height) { this.paperWidth = width; this.paperHeight = height; - // there will be one resize before paper is ready -- if so, dont call it - if (!this.paperReady) { - return; - } - + // refresh when we are ready this.refreshTree(); + // TODO when animation is happening, do this: events.trigger('processCommandFromEvent', 'refresh'); }; GitVisuals.prototype.addNode = function(id, commit) {