have HEAD working

This commit is contained in:
Peter Cottle 2012-09-29 11:52:18 -07:00
parent 3b58cf2912
commit f78e77e5c6
4 changed files with 116 additions and 29 deletions

View file

@ -18,9 +18,12 @@ var GRAPHICS = {
curveControlPointOffset: 50, curveControlPointOffset: 50,
defaultEasing: 'easeInOut', defaultEasing: 'easeInOut',
defaultAnimationTime: 300, defaultAnimationTime: 300,
rectFill: '#FF3A3A', rectFill: '#FF3A3A',
headRectFill: '#2831FF',
rectStroke: '#FFF', rectStroke: '#FFF',
rectStrokeWidth: '3', rectStrokeWidth: '3',
multiBranchY: 20, multiBranchY: 20,
upstreamHeadOpacity: 0.5, upstreamHeadOpacity: 0.5,
upstreamNoneOpacity: 0.2, upstreamNoneOpacity: 0.2,

View file

@ -40,6 +40,9 @@ GitEngine.prototype.init = function() {
// commit once to get things going // commit once to get things going
this.commit(); this.commit();
// now we are ready
events.trigger('gitEngineReady', this);
}; };
GitEngine.prototype.getDetachedHead = function() { GitEngine.prototype.getDetachedHead = function() {

View file

@ -4,6 +4,12 @@ var VisBranch = Backbone.Model.extend({
text: null, text: null,
rect: null, rect: null,
arrow: null, arrow: null,
isHead: false,
flip: 1,
fill: GRAPHICS.rectFill,
stroke: GRAPHICS.rectStroke,
offsetX: GRAPHICS.nodeRadius * 4.75, offsetX: GRAPHICS.nodeRadius * 4.75,
offsetY: 0, offsetY: 0,
arrowHeight: 14, arrowHeight: 14,
@ -11,8 +17,10 @@ var VisBranch = Backbone.Model.extend({
arrowEdgeHeight: 6, arrowEdgeHeight: 6,
arrowLength: 14, arrowLength: 14,
arrowOffsetFromCircleX: 10, arrowOffsetFromCircleX: 10,
vPad: 5, vPad: 5,
hPad: 5, hPad: 5,
animationSpeed: GRAPHICS.defaultAnimationTime, animationSpeed: GRAPHICS.defaultAnimationTime,
animationEasing: GRAPHICS.defaultEasing animationEasing: GRAPHICS.defaultEasing
}, },
@ -25,15 +33,27 @@ var VisBranch = Backbone.Model.extend({
initialize: function() { initialize: function() {
this.validateAtInit(); this.validateAtInit();
if (this.get('branch').get('id') == 'HEAD') {
// switch to a head ref
this.set('isHead', true);
this.set('flip', -1);
this.set('fill', GRAPHICS.headRectFill);
}
}, },
getCommitPosition: function() { getCommitPosition: function() {
var commit = this.get('branch').get('target'); var commit = gitEngine.getCommitFromRef(this.get('branch'));
var visNode = commit.get('visNode'); var visNode = commit.get('visNode');
return visNode.getScreenCoords(); return visNode.getScreenCoords();
}, },
getBranchStackIndex: function() { getBranchStackIndex: function() {
if (this.get('isHead')) {
// head is never stacked with other branches
return 0;
}
var myArray = this.getBranchStackArray(); var myArray = this.getBranchStackArray();
var index = -1; var index = -1;
_.each(myArray, function(branch, i) { _.each(myArray, function(branch, i) {
@ -45,11 +65,23 @@ var VisBranch = Backbone.Model.extend({
}, },
getBranchStackLength: function() { getBranchStackLength: function() {
if (this.get('isHead')) {
// head is always by itself
return 1;
}
return this.getBranchStackArray().length; return this.getBranchStackArray().length;
}, },
getBranchStackArray: function() { getBranchStackArray: function() {
return gitVisuals.branchStackMap[this.get('branch').get('target').get('id')]; var arr = gitVisuals.branchStackMap[this.get('branch').get('target').get('id')];
if (arr === undefined) {
// this only occurs when we are generating graphics inside of
// a new Branch instantiation, so we need to force the update
gitVisuals.calcBranchStacks();
return this.getBranchStackArray();
}
return arr;
}, },
getTextPosition: function() { getTextPosition: function() {
@ -59,13 +91,14 @@ var VisBranch = Backbone.Model.extend({
// so everything is independent // so everything is independent
var myPos = this.getBranchStackIndex(); var myPos = this.getBranchStackIndex();
return { return {
x: pos.x + this.get('offsetX'), x: pos.x + this.get('flip') * this.get('offsetX'),
y: pos.y + myPos * GRAPHICS.multiBranchY + this.get('offsetY') y: pos.y + myPos * GRAPHICS.multiBranchY + this.get('offsetY')
}; };
}, },
getRectPosition: function() { getRectPosition: function() {
var pos = this.getTextPosition(); var pos = this.getTextPosition();
var f = this.get('flip');
// first get text width and height // first get text width and height
var textSize = this.getTextSize(); var textSize = this.getTextSize();
return { return {
@ -85,26 +118,27 @@ var VisBranch = Backbone.Model.extend({
var toStringCoords = function(pos) { var toStringCoords = function(pos) {
return String(Math.round(pos.x)) + ',' + String(Math.round(pos.y)); return String(Math.round(pos.x)) + ',' + String(Math.round(pos.y));
}; };
var f = this.get('flip');
var arrowTip = offset2d(this.getCommitPosition(), var arrowTip = offset2d(this.getCommitPosition(),
this.get('arrowOffsetFromCircleX'), f * this.get('arrowOffsetFromCircleX'),
0 0
); );
var arrowEdgeUp = offset2d(arrowTip, this.get('arrowLength'), -this.get('arrowHeight')); var arrowEdgeUp = offset2d(arrowTip, f * this.get('arrowLength'), -this.get('arrowHeight'));
var arrowEdgeLow = offset2d(arrowTip, this.get('arrowLength'), this.get('arrowHeight')); var arrowEdgeLow = offset2d(arrowTip, f * this.get('arrowLength'), this.get('arrowHeight'));
var arrowInnerUp = offset2d(arrowEdgeUp, var arrowInnerUp = offset2d(arrowEdgeUp,
this.get('arrowInnerSkew'), f * this.get('arrowInnerSkew'),
this.get('arrowEdgeHeight') this.get('arrowEdgeHeight')
); );
var arrowInnerLow = offset2d(arrowEdgeLow, var arrowInnerLow = offset2d(arrowEdgeLow,
this.get('arrowInnerSkew'), f * this.get('arrowInnerSkew'),
-this.get('arrowEdgeHeight') -this.get('arrowEdgeHeight')
); );
var tailLength = 30; var tailLength = 30;
var arrowStartUp = offset2d(arrowInnerUp, tailLength, 0); var arrowStartUp = offset2d(arrowInnerUp, f * tailLength, 0);
var arrowStartLow = offset2d(arrowInnerLow, tailLength, 0); var arrowStartLow = offset2d(arrowInnerLow, f * tailLength, 0);
var pathStr = ''; var pathStr = '';
pathStr += 'M' + toStringCoords(arrowStartUp) + ' '; pathStr += 'M' + toStringCoords(arrowStartUp) + ' ';
@ -130,6 +164,13 @@ var VisBranch = Backbone.Model.extend({
}; };
var textNode = this.get('text').node; var textNode = this.get('text').node;
if (this.get('isHead')) {
// HEAD is a special case
return {
w: textNode.clientWidth,
h: textNode.clientHeight
};
}
var maxWidth = 0; var maxWidth = 0;
_.each(this.getBranchStackArray(), function(branch) { _.each(this.getBranchStackArray(), function(branch) {
@ -192,7 +233,8 @@ var VisBranch = Backbone.Model.extend({
var text = paper.text(textPos.x, textPos.y, String(name)); var text = paper.text(textPos.x, textPos.y, String(name));
text.attr({ text.attr({
'font-size': 14, 'font-size': 14,
'font-family': 'Monaco, Courier, font-monospace' 'font-family': 'Monaco, Courier, font-monospace',
opacity: this.getTextOpacity()
}); });
this.set('text', text); this.set('text', text);
@ -200,18 +242,20 @@ var VisBranch = Backbone.Model.extend({
var sizeOfRect = this.getRectSize(); var sizeOfRect = this.getRectSize();
var rect = paper.rect(rectPos.x, rectPos.y, sizeOfRect.w, sizeOfRect.h, 8); var rect = paper.rect(rectPos.x, rectPos.y, sizeOfRect.w, sizeOfRect.h, 8);
rect.attr({ rect.attr({
fill: GRAPHICS.rectFill, fill: this.get('fill'),
stroke: GRAPHICS.rectStroke, stroke: this.get('stroke'),
'stroke-width': GRAPHICS.rectStrokeWidth 'stroke-width': GRAPHICS.rectStrokeWidth,
opacity: this.getNonTextOpacity()
}); });
this.set('rect', rect); this.set('rect', rect);
var arrowPath = this.getArrowPath(); var arrowPath = this.getArrowPath();
var arrow = paper.path(arrowPath); var arrow = paper.path(arrowPath);
arrow.attr({ arrow.attr({
fill: GRAPHICS.rectFill, fill: this.get('fill'),
stroke: GRAPHICS.rectStroke, stroke: this.get('stroke'),
'stroke-width': GRAPHICS.rectStrokeWidth 'stroke-width': GRAPHICS.rectStrokeWidth,
opacity: this.getNonTextOpacity()
}); });
this.set('arrow', arrow); this.set('arrow', arrow);
@ -225,16 +269,32 @@ var VisBranch = Backbone.Model.extend({
}); });
}, },
getNonTextOpacity: function() {
if (this.get('isHead')) {
return gitEngine.getDetachedHead() ? 1 : 0;
}
return this.getBranchStackIndex() == 0 ? 1 : 0.0;
},
getTextOpacity: function() {
if (this.get('isHead')) {
return gitEngine.getDetachedHead() ? 1 : 0;
}
return 1;
},
animateUpdatedPos: function(speed, easing) { animateUpdatedPos: function(speed, easing) {
var s = speed !== undefined ? speed : this.get('animationSpeed'); var s = speed !== undefined ? speed : this.get('animationSpeed');
var e = easing || this.get('animationEasing'); var e = easing || this.get('animationEasing');
var masterOpacity = this.getBranchStackIndex() == 0 ? 1 : 0.0; var nonTextOpacity = this.getNonTextOpacity();
var textOpacity = this.getTextOpacity();
this.updateName(); this.updateName();
var textPos = this.getTextPosition(); var textPos = this.getTextPosition();
this.get('text').stop().animate({ this.get('text').stop().animate({
x: textPos.x, x: textPos.x,
y: textPos.y y: textPos.y,
opacity: textOpacity
}, s, e); }, s, e);
var rectPos = this.getRectPosition(); var rectPos = this.getRectPosition();
@ -244,13 +304,13 @@ var VisBranch = Backbone.Model.extend({
y: rectPos.y, y: rectPos.y,
width: rectSize.w, width: rectSize.w,
height: rectSize.h, height: rectSize.h,
opacity: masterOpacity, opacity: nonTextOpacity,
}, s, e); }, s, e);
var arrowPath = this.getArrowPath(); var arrowPath = this.getArrowPath();
this.get('arrow').stop().animate({ this.get('arrow').stop().animate({
path: arrowPath, path: arrowPath,
opacity: masterOpacity opacity: nonTextOpacity
}, s, e); }, s, e);
} }
}); });
@ -259,6 +319,7 @@ var VisBranch = Backbone.Model.extend({
var VisNode = Backbone.Model.extend({ var VisNode = Backbone.Model.extend({
defaults: { defaults: {
depth: undefined, depth: undefined,
maxWidth: null,
id: null, id: null,
pos: null, pos: null,
radius: null, radius: null,
@ -295,6 +356,19 @@ var VisNode = Backbone.Model.extend({
pos.y = this.get('depth') * depthIncrement; pos.y = this.get('depth') * depthIncrement;
}, },
getMaxWidthScaled: function() {
// returns our max width scaled based on if we are visible
// from a branch or not
var stat = gitVisuals.getCommitUpstreamStatus(this.get('commit'));
var map = {
branch: 1,
head: 0.3,
none: 0.1
};
if (map[stat] === undefined) { throw new Error('bad stat'); }
return map[stat] * this.get('maxWidth');
},
toFront: function() { toFront: function() {
this.get('circle').toFront(); this.get('circle').toFront();
}, },

View file

@ -5,8 +5,8 @@ function GitVisuals(options) {
this.edgeCollection = new VisEdgeCollection(); this.edgeCollection = new VisEdgeCollection();
this.visBranchCollection = new VisBranchCollection(); this.visBranchCollection = new VisBranchCollection();
this.commitMap = {}; this.commitMap = {};
this.rootCommit = null; this.rootCommit = null;
this.branchStackMap = null; this.branchStackMap = null;
this.upstreamBranchSet = null; this.upstreamBranchSet = null;
@ -30,8 +30,16 @@ function GitVisuals(options) {
events.on('refreshTree', _.bind( events.on('refreshTree', _.bind(
this.refreshTree, this this.refreshTree, this
)); ));
events.on('gitEngineReady', this.whenGitEngineReady, this);
} }
GitVisuals.prototype.whenGitEngineReady = function(gitEngine) {
// seed this with the HEAD pseudo-branch
this.visBranchCollection.add(new VisBranch({
branch: gitEngine.HEAD
}));
};
GitVisuals.prototype.getScreenBounds = function() { GitVisuals.prototype.getScreenBounds = function() {
// for now we return the node radius subtracted from the walls // for now we return the node radius subtracted from the walls
return { return {
@ -57,7 +65,7 @@ GitVisuals.prototype.toScreenCoords = function(pos) {
}; };
/*************************************** /***************************************
== Tree Calculation Parts == == BEGIN Tree Calculation Parts ==
_ __ __ _ _ __ __ _
\\/ / \ \//_ \\/ / \ \//_
\ \ / __| __ \ \ / __| __
@ -101,11 +109,11 @@ GitVisuals.prototype.calcTreeCoords = function() {
throw new Error('grr, no root commit!'); throw new Error('grr, no root commit!');
} }
this.calcUpstreamSets();
this.calcBranchStacks();
this.calcDepth(); this.calcDepth();
this.calcWidth(); this.calcWidth();
this.calcBranchStacks();
this.calcUpstreamSets();
}; };
GitVisuals.prototype.calcGraphicsCoords = function() { GitVisuals.prototype.calcGraphicsCoords = function() {
@ -116,7 +124,6 @@ GitVisuals.prototype.calcGraphicsCoords = function() {
GitVisuals.prototype.calcUpstreamSets = function() { GitVisuals.prototype.calcUpstreamSets = function() {
this.upstreamBranchSet = gitEngine.getUpstreamBranchSet(); this.upstreamBranchSet = gitEngine.getUpstreamBranchSet();
this.upstreamHeadSet = gitEngine.getUpstreamHeadSet(); this.upstreamHeadSet = gitEngine.getUpstreamHeadSet();
}; };
@ -193,7 +200,7 @@ GitVisuals.prototype.assignBoundsRecursive = function(commit, min, max) {
var totalFlex = 0; var totalFlex = 0;
var children = commit.get('children'); var children = commit.get('children');
_.each(children, function(child) { _.each(children, function(child) {
totalFlex += child.get('visNode').get('maxWidth'); totalFlex += child.get('visNode').getMaxWidthScaled();
}, this); }, this);
var prevBound = min; var prevBound = min;
@ -201,7 +208,7 @@ GitVisuals.prototype.assignBoundsRecursive = function(commit, min, max) {
// now go through and do everything // now go through and do everything
// TODO: order so the max width children are in the middle!! // TODO: order so the max width children are in the middle!!
_.each(children, function(child) { _.each(children, function(child) {
var flex = child.get('visNode').get('maxWidth'); var flex = child.get('visNode').getMaxWidthScaled();
var portion = (flex / totalFlex) * myLength; var portion = (flex / totalFlex) * myLength;
var childMin = prevBound; var childMin = prevBound;
var childMax = childMin + portion; var childMax = childMin + portion;