mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-27 08:28:50 +02:00
BOOM commit birthing animation done and animation factory fleshed out
This commit is contained in:
parent
bc4b9246eb
commit
23ee6944e2
6 changed files with 106 additions and 20 deletions
|
@ -1,13 +1,41 @@
|
||||||
/******************
|
/******************
|
||||||
* This class is responsible for a lot of the heavy lifting around creating an animation at a certain state in time.
|
* 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
|
* The tricky thing is that when a new commit has to be "born," say in the middle of a rebase
|
||||||
* out from the parent position to it's birth position.
|
* 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,
|
* 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.
|
* 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.
|
* and then essentially animate the entire tree too.
|
||||||
|
|
||||||
* not sure if this is necessary yet, so ill hold off for now. lets do some refs
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// essentially a static class
|
||||||
|
function AnimationFactory() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationFactory.prototype.genCommitBirthAnimation = function(animationQueue, commit) {
|
||||||
|
if (!animationQueue) {
|
||||||
|
throw new Error("Need animation queue to add closure to!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var time = GRAPHICS.defaultAnimationTime * 1.0;
|
||||||
|
|
||||||
|
// 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.setBirthPosition();
|
||||||
|
visNode.setOutgoingEdgesBirthPosition();
|
||||||
|
visNode.parentInFront();
|
||||||
|
|
||||||
|
visNode.animateUpdatedPosition(time);
|
||||||
|
visNode.animateOutgoingEdges(time);
|
||||||
|
};
|
||||||
|
|
||||||
|
animationQueue.add(new Animation({
|
||||||
|
closure: animation
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
10
src/git.js
10
src/git.js
|
@ -230,7 +230,9 @@ GitEngine.prototype.commitStarter = function() {
|
||||||
if (this.commandOptions['-am']) {
|
if (this.commandOptions['-am']) {
|
||||||
this.command.addWarning("Don't worry about adding files or commit messages in this demo");
|
this.command.addWarning("Don't worry about adding files or commit messages in this demo");
|
||||||
}
|
}
|
||||||
this.commit();
|
|
||||||
|
var newCommit = this.commit();
|
||||||
|
animationFactory.genCommitBirthAnimation(this.animationQueue, newCommit);
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.commit = function() {
|
GitEngine.prototype.commit = function() {
|
||||||
|
@ -248,6 +250,7 @@ GitEngine.prototype.commit = function() {
|
||||||
var targetBranch = this.HEAD.get('target');
|
var targetBranch = this.HEAD.get('target');
|
||||||
targetBranch.set('target', newCommit);
|
targetBranch.set('target', newCommit);
|
||||||
}
|
}
|
||||||
|
return newCommit;
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.resolveId = function(idOrTarget) {
|
GitEngine.prototype.resolveId = function(idOrTarget) {
|
||||||
|
@ -750,22 +753,23 @@ GitEngine.prototype.dispatch = function(command, callback) {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof GitError ||
|
if (err instanceof GitError ||
|
||||||
err instanceof CommandResult) {
|
err instanceof CommandResult) {
|
||||||
|
|
||||||
// short circuit animation by just setting error and returning
|
// short circuit animation by just setting error and returning
|
||||||
command.set('error', err);
|
command.set('error', err);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only add the refresh if we didn't do manual animations
|
||||||
|
if (!this.animationQueue.get('animations').length) {
|
||||||
this.animationQueue.add(new Animation({
|
this.animationQueue.add(new Animation({
|
||||||
closure: function() {
|
closure: function() {
|
||||||
gitVisuals.refreshTree();
|
gitVisuals.refreshTree();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// animation queue will call the callback when its done
|
// animation queue will call the callback when its done
|
||||||
this.animationQueue.start();
|
this.animationQueue.start();
|
||||||
|
|
|
@ -8,10 +8,13 @@ var gitVisuals = null;
|
||||||
|
|
||||||
var commandCollection = null;
|
var commandCollection = null;
|
||||||
var commandBuffer = null;
|
var commandBuffer = null;
|
||||||
|
var animationFactory = null;
|
||||||
|
|
||||||
var paper = null;
|
var paper = null;
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
animationFactory = new AnimationFactory();
|
||||||
|
|
||||||
// the two major collections that affect everything
|
// the two major collections that affect everything
|
||||||
var commitCollection = new CommitCollection();
|
var commitCollection = new CommitCollection();
|
||||||
commandCollection = new CommandCollection();
|
commandCollection = new CommandCollection();
|
||||||
|
|
59
src/tree.js
59
src/tree.js
|
@ -320,6 +320,7 @@ var VisNode = Backbone.Model.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
depth: undefined,
|
depth: undefined,
|
||||||
maxWidth: null,
|
maxWidth: null,
|
||||||
|
outgoingEdges: null,
|
||||||
id: null,
|
id: null,
|
||||||
pos: null,
|
pos: null,
|
||||||
radius: null,
|
radius: null,
|
||||||
|
@ -346,6 +347,8 @@ var VisNode = Backbone.Model.extend({
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.validateAtInit();
|
this.validateAtInit();
|
||||||
|
|
||||||
|
this.set('outgoingEdges', []);
|
||||||
},
|
},
|
||||||
|
|
||||||
setDepthBasedOn: function(depthIncrement) {
|
setDepthBasedOn: function(depthIncrement) {
|
||||||
|
@ -394,7 +397,8 @@ var VisNode = Backbone.Model.extend({
|
||||||
this.get('circle').stop().animate({
|
this.get('circle').stop().animate({
|
||||||
cx: pos.x,
|
cx: pos.x,
|
||||||
cy: pos.y,
|
cy: pos.y,
|
||||||
opacity: opacity
|
opacity: opacity,
|
||||||
|
r: this.getRadius()
|
||||||
},
|
},
|
||||||
speed !== undefined ? speed : this.get('animationSpeed'),
|
speed !== undefined ? speed : this.get('animationSpeed'),
|
||||||
easing || this.get('animationEasing')
|
easing || this.get('animationEasing')
|
||||||
|
@ -410,6 +414,45 @@ var VisNode = Backbone.Model.extend({
|
||||||
return this.get('radius') || GRAPHICS.nodeRadius;
|
return this.get('radius') || GRAPHICS.nodeRadius;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getParentScreenCoords: function() {
|
||||||
|
return this.get('commit').get('parents')[0].get('visNode').getScreenCoords();
|
||||||
|
},
|
||||||
|
|
||||||
|
setBirthPosition: function() {
|
||||||
|
// utility method for animating it out from underneath a parent
|
||||||
|
var parentCoords = this.getParentScreenCoords();
|
||||||
|
|
||||||
|
this.get('circle').attr({
|
||||||
|
cx: parentCoords.x,
|
||||||
|
cy: parentCoords.y,
|
||||||
|
opacity: 0,
|
||||||
|
r: 0,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
animateOutgoingEdges: function(speed, easing) {
|
||||||
|
_.each(this.get('outgoingEdges'), function(edge) {
|
||||||
|
edge.animateUpdatedPath(speed, easing);
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
setOutgoingEdgesBirthPosition: function() {
|
||||||
|
var parentCoords = this.getParentScreenCoords();
|
||||||
|
_.each(this.get('outgoingEdges'), function(edge) {
|
||||||
|
var headPos = edge.get('head').getScreenCoords();
|
||||||
|
var path = edge.genSmoothBezierPathStringFromCoords(parentCoords, headPos);
|
||||||
|
edge.get('path').stop().attr({
|
||||||
|
path: path,
|
||||||
|
opacity: 0
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
parentInFront: function() {
|
||||||
|
// woof!
|
||||||
|
this.get('commit').get('parents')[0].get('visNode').get('circle').toFront();
|
||||||
|
},
|
||||||
|
|
||||||
genGraphics: function(paper) {
|
genGraphics: function(paper) {
|
||||||
var pos = this.getScreenCoords();
|
var pos = this.getScreenCoords();
|
||||||
var circle = cuteSmallCircle(paper, pos.x, pos.y, {
|
var circle = cuteSmallCircle(paper, pos.x, pos.y, {
|
||||||
|
@ -438,11 +481,17 @@ var VisEdge = Backbone.Model.extend({
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.validateAtInit();
|
this.validateAtInit();
|
||||||
|
|
||||||
|
this.get('tail').get('outgoingEdges').push(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
genSmoothBezierPathString: function(tail, head) {
|
genSmoothBezierPathString: function(tail, head) {
|
||||||
var tailPos = tail.getScreenCoords();
|
var tailPos = tail.getScreenCoords();
|
||||||
var headPos = head.getScreenCoords();
|
var headPos = head.getScreenCoords();
|
||||||
|
return this.genSmoothBezierPathStringFromCoords(tailPos, headPos);
|
||||||
|
},
|
||||||
|
|
||||||
|
genSmoothBezierPathStringFromCoords: function(tailPos, headPos) {
|
||||||
// we need to generate the path and control points for the bezier. format
|
// we need to generate the path and control points for the bezier. format
|
||||||
// is M(move abs) C (curve to) (control point 1) (control point 2) (final point)
|
// is M(move abs) C (curve to) (control point 1) (control point 2) (final point)
|
||||||
// the control points have to be __below__ to get the curve starting off straight.
|
// the control points have to be __below__ to get the curve starting off straight.
|
||||||
|
@ -465,8 +514,8 @@ var VisEdge = Backbone.Model.extend({
|
||||||
};
|
};
|
||||||
|
|
||||||
// first offset tail and head by radii
|
// first offset tail and head by radii
|
||||||
tailPos = offset(tailPos, -1, tail.getRadius());
|
tailPos = offset(tailPos, -1, this.get('tail').getRadius());
|
||||||
headPos = offset(headPos, 1, head.getRadius());
|
headPos = offset(headPos, 1, this.get('head').getRadius());
|
||||||
|
|
||||||
var str = '';
|
var str = '';
|
||||||
// first move to bottom of tail
|
// first move to bottom of tail
|
||||||
|
@ -514,6 +563,10 @@ var VisEdge = Backbone.Model.extend({
|
||||||
|
|
||||||
animateUpdatedPath: function(speed, easing) {
|
animateUpdatedPath: function(speed, easing) {
|
||||||
var newPath = this.getBezierCurve();
|
var newPath = this.getBezierCurve();
|
||||||
|
this.animateUpdatedPathFromPath(newPath, speed, easing);
|
||||||
|
},
|
||||||
|
|
||||||
|
animateUpdatedPathFromPath: function(newPath, speed, easing) {
|
||||||
var opacity = this.getOpacity();
|
var opacity = this.getOpacity();
|
||||||
|
|
||||||
this.get('path').toBack();
|
this.get('path').toBack();
|
||||||
|
|
|
@ -81,12 +81,12 @@ GitVisuals.prototype.toScreenCoords = function(pos) {
|
||||||
|
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
GitVisuals.prototype.refreshTree = function() {
|
GitVisuals.prototype.refreshTree = function(speed) {
|
||||||
// this method can only be called after graphics are rendered
|
// this method can only be called after graphics are rendered
|
||||||
this.calcTreeCoords();
|
this.calcTreeCoords();
|
||||||
this.calcGraphicsCoords();
|
this.calcGraphicsCoords();
|
||||||
|
|
||||||
this.animateAll();
|
this.animateAll(speed);
|
||||||
};
|
};
|
||||||
|
|
||||||
GitVisuals.prototype.refreshTreeHarsh = function() {
|
GitVisuals.prototype.refreshTreeHarsh = function() {
|
||||||
|
|
2
todo.txt
2
todo.txt
|
@ -6,13 +6,11 @@ integrate animation into all git commands
|
||||||
|
|
||||||
animation factory? stuff like:
|
animation factory? stuff like:
|
||||||
|
|
||||||
-commitBirthAnimation(snapshotBefore, snapshotAfter, commit)
|
|
||||||
-highlightCommit(50, 'targetColor') // during search
|
-highlightCommit(50, 'targetColor') // during search
|
||||||
-clearHighlightsAllNodes
|
-clearHighlightsAllNodes
|
||||||
|
|
||||||
|
|
||||||
ALSO other big things:
|
ALSO other big things:
|
||||||
|
|
||||||
- Text on commit nodes
|
- Text on commit nodes
|
||||||
- Division in their rings based on how many / what branches they are part of
|
- Division in their rings based on how many / what branches they are part of
|
||||||
- Color on branch edges??
|
- Color on branch edges??
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue