diff --git a/build/bundle.js b/build/bundle.js index 3ce02d34..75dd689f 100644 --- a/build/bundle.js +++ b/build/bundle.js @@ -389,262 +389,6 @@ process.binding = function (name) { }; })(); -}); - -require.define("/animationFactory.js",function(require,module,exports,__dirname,__filename,process,global){/****************** - * This class is responsible for a lot of the heavy lifting around creating an animation at a certain state in time. - * The tricky thing is that when a new commit has to be "born," say in the middle of a rebase - * or something, it must animate out from the parent position to it's birth position. - - * These two positions though may not be where the commit finally ends up. So we actually need to take a snapshot of the tree, - * store all those positions, take a snapshot of the tree after a layout refresh afterwards, and then animate between those two spots. - * and then essentially animate the entire tree too. - */ - -// essentially a static class -var AnimationFactory = function() { - -} - -AnimationFactory.prototype.genCommitBirthAnimation = function(animationQueue, commit, gitVisuals) { - if (!animationQueue) { - throw new Error("Need animation queue to add closure to!"); - } - - var time = GRAPHICS.defaultAnimationTime * 1.0; - var bounceTime = time * 2; - - // essentially refresh the entire tree, but do a special thing for the commit - var visNode = commit.get('visNode'); - - var animation = function() { - // this takes care of refs and all that jazz, and updates all the positions - gitVisuals.refreshTree(time); - - visNode.setBirth(); - visNode.parentInFront(); - gitVisuals.visBranchesFront(); - - visNode.animateUpdatedPosition(bounceTime, 'bounce'); - visNode.animateOutgoingEdges(time); - }; - - animationQueue.add(new Animation({ - closure: animation, - duration: Math.max(time, bounceTime) - })); -}; - -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); - return newSnap; -}; - -AnimationFactory.prototype.genCommitBirthClosureFromSnapshot = function(step, gitVisuals) { - var time = GRAPHICS.defaultAnimationTime * 1.0; - var bounceTime = time * 1.5; - - var visNode = step.newCommit.get('visNode'); - var afterAttrWithOpacity = this.overrideOpacityDepth2(step.afterSnapshot[visNode.getID()]); - var afterSnapWithOpacity = this.overrideOpacityDepth3(step.afterSnapshot); - - var animation = function() { - visNode.setBirthFromSnapshot(step.beforeSnapshot); - visNode.parentInFront(); - gitVisuals.visBranchesFront(); - - visNode.animateToAttr(afterAttrWithOpacity, bounceTime, 'bounce'); - visNode.animateOutgoingEdgesToAttr(afterSnapWithOpacity, bounceTime); - }; - - return animation; -}; - -AnimationFactory.prototype.refreshTree = function(animationQueue, gitVisuals) { - animationQueue.add(new Animation({ - closure: function() { - gitVisuals.refreshTree(); - } - })); -}; - -AnimationFactory.prototype.rebaseAnimation = function(animationQueue, rebaseResponse, - gitEngine, gitVisuals) { - - this.rebaseHighlightPart(animationQueue, rebaseResponse, gitEngine); - this.rebaseBirthPart(animationQueue, rebaseResponse, gitEngine, gitVisuals); -}; - -AnimationFactory.prototype.rebaseHighlightPart = function(animationQueue, rebaseResponse, gitEngine) { - var fullTime = GRAPHICS.defaultAnimationTime * 0.66; - var slowTime = fullTime * 2.0; - - // we want to highlight all the old commits - var oldCommits = rebaseResponse.toRebaseArray; - // we are either highlighting to a visBranch or a visNode - var visBranch = rebaseResponse.destinationBranch.get('visBranch'); - if (!visBranch) { - // in the case where we rebase onto a commit - visBranch = rebaseResponse.destinationBranch.get('visNode'); - } - - _.each(oldCommits, function(oldCommit) { - var visNode = oldCommit.get('visNode'); - animationQueue.add(new Animation({ - closure: function() { - visNode.highlightTo(visBranch, slowTime, 'easeInOut'); - }, - duration: fullTime * 1.5 - })); - - }, this); - - this.delay(animationQueue, fullTime * 2); -}; - -AnimationFactory.prototype.rebaseBirthPart = function(animationQueue, rebaseResponse, - gitEngine, gitVisuals) { - var rebaseSteps = rebaseResponse.rebaseSteps; - - var newVisNodes = []; - _.each(rebaseSteps, function(step) { - var visNode = step.newCommit.get('visNode'); - - newVisNodes.push(visNode); - visNode.setOpacity(0); - visNode.setOutgoingEdgesOpacity(0); - }, this); - - var previousVisNodes = []; - _.each(rebaseSteps, function(rebaseStep, index) { - var toOmit = newVisNodes.slice(index + 1); - - var snapshotPart = this.genFromToSnapshotAnimation( - rebaseStep.beforeSnapshot, - rebaseStep.afterSnapshot, - toOmit, - previousVisNodes, - gitVisuals - ); - var birthPart = this.genCommitBirthClosureFromSnapshot(rebaseStep, gitVisuals); - - var animation = function() { - snapshotPart(); - birthPart(); - }; - - animationQueue.add(new Animation({ - closure: animation, - duration: GRAPHICS.defaultAnimationTime * 1.5 - })); - - previousVisNodes.push(rebaseStep.newCommit.get('visNode')); - }, this); - - // need to delay to let bouncing finish - this.delay(animationQueue); - - this.refreshTree(animationQueue, gitVisuals); -}; - -AnimationFactory.prototype.delay = function(animationQueue, time) { - time = time || GRAPHICS.defaultAnimationTime; - animationQueue.add(new Animation({ - closure: function() { }, - duration: time - })); -}; - -AnimationFactory.prototype.genSetAllCommitOpacities = function(visNodes, opacity) { - // need to slice for closure - var nodesToAnimate = visNodes.slice(0); - - return function() { - _.each(nodesToAnimate, function(visNode) { - visNode.setOpacity(opacity); - visNode.setOutgoingEdgesOpacity(opacity); - }); - }; -}; - -AnimationFactory.prototype.stripObjectsFromSnapshot = function(snapShot, toOmit) { - var ids = []; - _.each(toOmit, function(obj) { - ids.push(obj.getID()); - }); - - var newSnapshot = {}; - _.each(snapShot, function(val, key) { - if (_.include(ids, key)) { - // omit - return; - } - newSnapshot[key] = val; - }, this); - return newSnapshot; -}; - -AnimationFactory.prototype.genFromToSnapshotAnimation = function( - beforeSnapshot, - afterSnapshot, - commitsToOmit, - commitsToFixOpacity, - gitVisuals) { - - // we want to omit the commit outgoing edges - var toOmit = []; - _.each(commitsToOmit, function(visNode) { - toOmit.push(visNode); - toOmit = toOmit.concat(visNode.get('outgoingEdges')); - }); - - var fixOpacity = function(obj) { - if (!obj) { return; } - _.each(obj, function(attr, partName) { - obj[partName].opacity = 1; - }); - }; - - // HORRIBLE loop to fix opacities all throughout the snapshot - _.each([beforeSnapshot, afterSnapshot], function(snapShot) { - _.each(commitsToFixOpacity, function(visNode) { - fixOpacity(snapShot[visNode.getID()]); - _.each(visNode.get('outgoingEdges'), function(visEdge) { - fixOpacity(snapShot[visEdge.getID()]); - }); - }); - }); - - return function() { - gitVisuals.animateAllFromAttrToAttr(beforeSnapshot, afterSnapshot, toOmit); - }; -}; - -exports.AnimationFactory = AnimationFactory; - - }); require.define("/main.js",function(require,module,exports,__dirname,__filename,process,global){var AnimationFactory = require('./animationFactory').AnimationFactory; @@ -817,6 +561,7 @@ exports.CommandBuffer = CommandBuffer; require.define("/git.js",function(require,module,exports,__dirname,__filename,process,global){var AnimationFactoryModule = require('./animationFactory'); var animationFactory = new AnimationFactoryModule.AnimationFactory(); var Main = require('./main'); +var AnimationQueue = require('./async').AnimationQueue; // backbone or something uses _.uniqueId, so we make our own here var uniqueId = (function() { @@ -2450,6 +2195,92 @@ exports.Branch = Branch; exports.Ref = Ref; +}); + +require.define("/async.js",function(require,module,exports,__dirname,__filename,process,global){var Animation = Backbone.Model.extend({ + defaults: { + duration: 300, + closure: null + }, + + validateAtInit: function() { + if (!this.get('closure')) { + throw new Error('give me a closure!'); + } + }, + + initialize: function(options) { + this.validateAtInit(); + }, + + run: function() { + this.get('closure')(); + } +}); + +var AnimationQueue = Backbone.Model.extend({ + defaults: { + animations: null, + index: 0, + callback: null, + defer: false + }, + + initialize: function(options) { + this.set('animations', []); + if (!options.callback) { + console.warn('no callback'); + } + }, + + add: function(animation) { + if (!animation instanceof Animation) { + throw new Error("Need animation not something else"); + } + + this.get('animations').push(animation); + }, + + start: function() { + this.set('index', 0); + + // set the global lock that we are animating + GLOBAL.isAnimating = true; + this.next(); + }, + + finish: function() { + // release lock here + GLOBAL.isAnimating = false; + this.get('callback')(); + }, + + next: function() { + // ok so call the first animation, and then set a timeout to call the next + // TODO: animations with callbacks!! + var animations = this.get('animations'); + var index = this.get('index'); + if (index >= animations.length) { + this.finish(); + return; + } + + var next = animations[index]; + var duration = next.get('duration'); + + next.run(); + + this.set('index', index + 1); + setTimeout(_.bind(function() { + this.next(); + }, this), duration); + }, +}); + +exports.Animation = Animation; +exports.AnimationQueue = AnimationQueue; + + }); require.define("/commandModel.js",function(require,module,exports,__dirname,__filename,process,global){var Command = Backbone.Model.extend({ @@ -4859,11 +4690,270 @@ exports.VisBranch = VisBranch; +}); + +require.define("/animationFactory.js",function(require,module,exports,__dirname,__filename,process,global){/****************** + * This class is responsible for a lot of the heavy lifting around creating an animation at a certain state in time. + * The tricky thing is that when a new commit has to be "born," say in the middle of a rebase + * or something, it must animate out from the parent position to it's birth position. + + * These two positions though may not be where the commit finally ends up. So we actually need to take a snapshot of the tree, + * store all those positions, take a snapshot of the tree after a layout refresh afterwards, and then animate between those two spots. + * and then essentially animate the entire tree too. + */ + +var Animation = require('./async').Animation; + +// essentially a static class +var AnimationFactory = function() { + +} + +AnimationFactory.prototype.genCommitBirthAnimation = function(animationQueue, commit, gitVisuals) { + if (!animationQueue) { + throw new Error("Need animation queue to add closure to!"); + } + + var time = GRAPHICS.defaultAnimationTime * 1.0; + var bounceTime = time * 2; + + // essentially refresh the entire tree, but do a special thing for the commit + var visNode = commit.get('visNode'); + + var animation = function() { + // this takes care of refs and all that jazz, and updates all the positions + gitVisuals.refreshTree(time); + + visNode.setBirth(); + visNode.parentInFront(); + gitVisuals.visBranchesFront(); + + visNode.animateUpdatedPosition(bounceTime, 'bounce'); + visNode.animateOutgoingEdges(time); + }; + + animationQueue.add(new Animation({ + closure: animation, + duration: Math.max(time, bounceTime) + })); +}; + +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); + return newSnap; +}; + +AnimationFactory.prototype.genCommitBirthClosureFromSnapshot = function(step, gitVisuals) { + var time = GRAPHICS.defaultAnimationTime * 1.0; + var bounceTime = time * 1.5; + + var visNode = step.newCommit.get('visNode'); + var afterAttrWithOpacity = this.overrideOpacityDepth2(step.afterSnapshot[visNode.getID()]); + var afterSnapWithOpacity = this.overrideOpacityDepth3(step.afterSnapshot); + + var animation = function() { + visNode.setBirthFromSnapshot(step.beforeSnapshot); + visNode.parentInFront(); + gitVisuals.visBranchesFront(); + + visNode.animateToAttr(afterAttrWithOpacity, bounceTime, 'bounce'); + visNode.animateOutgoingEdgesToAttr(afterSnapWithOpacity, bounceTime); + }; + + return animation; +}; + +AnimationFactory.prototype.refreshTree = function(animationQueue, gitVisuals) { + animationQueue.add(new Animation({ + closure: function() { + gitVisuals.refreshTree(); + } + })); +}; + +AnimationFactory.prototype.rebaseAnimation = function(animationQueue, rebaseResponse, + gitEngine, gitVisuals) { + + this.rebaseHighlightPart(animationQueue, rebaseResponse, gitEngine); + this.rebaseBirthPart(animationQueue, rebaseResponse, gitEngine, gitVisuals); +}; + +AnimationFactory.prototype.rebaseHighlightPart = function(animationQueue, rebaseResponse, gitEngine) { + var fullTime = GRAPHICS.defaultAnimationTime * 0.66; + var slowTime = fullTime * 2.0; + + // we want to highlight all the old commits + var oldCommits = rebaseResponse.toRebaseArray; + // we are either highlighting to a visBranch or a visNode + var visBranch = rebaseResponse.destinationBranch.get('visBranch'); + if (!visBranch) { + // in the case where we rebase onto a commit + visBranch = rebaseResponse.destinationBranch.get('visNode'); + } + + _.each(oldCommits, function(oldCommit) { + var visNode = oldCommit.get('visNode'); + animationQueue.add(new Animation({ + closure: function() { + visNode.highlightTo(visBranch, slowTime, 'easeInOut'); + }, + duration: fullTime * 1.5 + })); + + }, this); + + this.delay(animationQueue, fullTime * 2); +}; + +AnimationFactory.prototype.rebaseBirthPart = function(animationQueue, rebaseResponse, + gitEngine, gitVisuals) { + var rebaseSteps = rebaseResponse.rebaseSteps; + + var newVisNodes = []; + _.each(rebaseSteps, function(step) { + var visNode = step.newCommit.get('visNode'); + + newVisNodes.push(visNode); + visNode.setOpacity(0); + visNode.setOutgoingEdgesOpacity(0); + }, this); + + var previousVisNodes = []; + _.each(rebaseSteps, function(rebaseStep, index) { + var toOmit = newVisNodes.slice(index + 1); + + var snapshotPart = this.genFromToSnapshotAnimation( + rebaseStep.beforeSnapshot, + rebaseStep.afterSnapshot, + toOmit, + previousVisNodes, + gitVisuals + ); + var birthPart = this.genCommitBirthClosureFromSnapshot(rebaseStep, gitVisuals); + + var animation = function() { + snapshotPart(); + birthPart(); + }; + + animationQueue.add(new Animation({ + closure: animation, + duration: GRAPHICS.defaultAnimationTime * 1.5 + })); + + previousVisNodes.push(rebaseStep.newCommit.get('visNode')); + }, this); + + // need to delay to let bouncing finish + this.delay(animationQueue); + + this.refreshTree(animationQueue, gitVisuals); +}; + +AnimationFactory.prototype.delay = function(animationQueue, time) { + time = time || GRAPHICS.defaultAnimationTime; + animationQueue.add(new Animation({ + closure: function() { }, + duration: time + })); +}; + +AnimationFactory.prototype.genSetAllCommitOpacities = function(visNodes, opacity) { + // need to slice for closure + var nodesToAnimate = visNodes.slice(0); + + return function() { + _.each(nodesToAnimate, function(visNode) { + visNode.setOpacity(opacity); + visNode.setOutgoingEdgesOpacity(opacity); + }); + }; +}; + +AnimationFactory.prototype.stripObjectsFromSnapshot = function(snapShot, toOmit) { + var ids = []; + _.each(toOmit, function(obj) { + ids.push(obj.getID()); + }); + + var newSnapshot = {}; + _.each(snapShot, function(val, key) { + if (_.include(ids, key)) { + // omit + return; + } + newSnapshot[key] = val; + }, this); + return newSnapshot; +}; + +AnimationFactory.prototype.genFromToSnapshotAnimation = function( + beforeSnapshot, + afterSnapshot, + commitsToOmit, + commitsToFixOpacity, + gitVisuals) { + + // we want to omit the commit outgoing edges + var toOmit = []; + _.each(commitsToOmit, function(visNode) { + toOmit.push(visNode); + toOmit = toOmit.concat(visNode.get('outgoingEdges')); + }); + + var fixOpacity = function(obj) { + if (!obj) { return; } + _.each(obj, function(attr, partName) { + obj[partName].opacity = 1; + }); + }; + + // HORRIBLE loop to fix opacities all throughout the snapshot + _.each([beforeSnapshot, afterSnapshot], function(snapShot) { + _.each(commitsToFixOpacity, function(visNode) { + fixOpacity(snapShot[visNode.getID()]); + _.each(visNode.get('outgoingEdges'), function(visEdge) { + fixOpacity(snapShot[visEdge.getID()]); + }); + }); + }); + + return function() { + gitVisuals.animateAllFromAttrToAttr(beforeSnapshot, afterSnapshot, toOmit); + }; +}; + +exports.AnimationFactory = AnimationFactory; + + }); require.define("/git.js",function(require,module,exports,__dirname,__filename,process,global){var AnimationFactoryModule = require('./animationFactory'); var animationFactory = new AnimationFactoryModule.AnimationFactory(); var Main = require('./main'); +var AnimationQueue = require('./async').AnimationQueue; // backbone or something uses _.uniqueId, so we make our own here var uniqueId = (function() { @@ -9365,4 +9455,91 @@ var levelEngine = new LevelEngine(); }); require("/levels.js"); + +require.define("/async.js",function(require,module,exports,__dirname,__filename,process,global){var Animation = Backbone.Model.extend({ + defaults: { + duration: 300, + closure: null + }, + + validateAtInit: function() { + if (!this.get('closure')) { + throw new Error('give me a closure!'); + } + }, + + initialize: function(options) { + this.validateAtInit(); + }, + + run: function() { + this.get('closure')(); + } +}); + +var AnimationQueue = Backbone.Model.extend({ + defaults: { + animations: null, + index: 0, + callback: null, + defer: false + }, + + initialize: function(options) { + this.set('animations', []); + if (!options.callback) { + console.warn('no callback'); + } + }, + + add: function(animation) { + if (!animation instanceof Animation) { + throw new Error("Need animation not something else"); + } + + this.get('animations').push(animation); + }, + + start: function() { + this.set('index', 0); + + // set the global lock that we are animating + GLOBAL.isAnimating = true; + this.next(); + }, + + finish: function() { + // release lock here + GLOBAL.isAnimating = false; + this.get('callback')(); + }, + + next: function() { + // ok so call the first animation, and then set a timeout to call the next + // TODO: animations with callbacks!! + var animations = this.get('animations'); + var index = this.get('index'); + if (index >= animations.length) { + this.finish(); + return; + } + + var next = animations[index]; + var duration = next.get('duration'); + + next.run(); + + this.set('index', index + 1); + setTimeout(_.bind(function() { + this.next(); + }, this), duration); + }, +}); + +exports.Animation = Animation; +exports.AnimationQueue = AnimationQueue; + + +}); +require("/async.js"); })(); diff --git a/src/animationFactory.js b/src/animationFactory.js index e9d9bcdb..1bc55e62 100644 --- a/src/animationFactory.js +++ b/src/animationFactory.js @@ -8,6 +8,8 @@ * and then essentially animate the entire tree too. */ +var Animation = require('./async').Animation; + // essentially a static class var AnimationFactory = function() { diff --git a/src/async.js b/src/async.js index 6fc42f9a..a9641e5d 100644 --- a/src/async.js +++ b/src/async.js @@ -78,3 +78,6 @@ var AnimationQueue = Backbone.Model.extend({ }, }); +exports.Animation = Animation; +exports.AnimationQueue = AnimationQueue; + diff --git a/src/git.js b/src/git.js index c599bab8..35851323 100644 --- a/src/git.js +++ b/src/git.js @@ -1,6 +1,7 @@ var AnimationFactoryModule = require('./animationFactory'); var animationFactory = new AnimationFactoryModule.AnimationFactory(); var Main = require('./main'); +var AnimationQueue = require('./async').AnimationQueue; // backbone or something uses _.uniqueId, so we make our own here var uniqueId = (function() { diff --git a/src/index.html b/src/index.html index d6f5d6f5..7cd553ee 100644 --- a/src/index.html +++ b/src/index.html @@ -128,7 +128,7 @@ - +