|
|
var Backbone = require('backbone'); |
|
|
var GRAPHICS = require('../util/constants').GRAPHICS; |
|
|
|
|
|
var VisBase = require('../visuals/visBase').VisBase; |
|
|
var GlobalStateStore = require('../stores/GlobalStateStore'); |
|
|
|
|
|
var VisEdge = VisBase.extend({ |
|
|
defaults: { |
|
|
tail: null, |
|
|
head: null, |
|
|
animationSpeed: GRAPHICS.defaultAnimationTime, |
|
|
animationEasing: GRAPHICS.defaultEasing |
|
|
}, |
|
|
|
|
|
validateAtInit: function() { |
|
|
var required = ['tail', 'head']; |
|
|
required.forEach(function(key) { |
|
|
if (!this.get(key)) { |
|
|
throw new Error(key + ' is required!'); |
|
|
} |
|
|
}, this); |
|
|
}, |
|
|
|
|
|
getID: function() { |
|
|
return this.get('tail').get('id') + '.' + this.get('head').get('id'); |
|
|
}, |
|
|
|
|
|
initialize: function() { |
|
|
this.validateAtInit(); |
|
|
|
|
|
|
|
|
this.gitVisuals = this.get('gitVisuals'); |
|
|
this.gitEngine = this.get('gitEngine'); |
|
|
|
|
|
this.get('tail').get('outgoingEdges').push(this); |
|
|
}, |
|
|
|
|
|
remove: function() { |
|
|
this.removeKeys(['path']); |
|
|
this.gitVisuals.removeVisEdge(this); |
|
|
}, |
|
|
|
|
|
genSmoothBezierPathString: function(tail, head) { |
|
|
var tailPos = tail.getScreenCoords(); |
|
|
var headPos = head.getScreenCoords(); |
|
|
return this.genSmoothBezierPathStringFromCoords(tailPos, headPos); |
|
|
}, |
|
|
|
|
|
genSmoothBezierPathStringFromCoords: function(tailPos, headPos) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var flipFactor = (GlobalStateStore.getFlipTreeY()) ? -1 : 1; |
|
|
var coords = function(pos) { |
|
|
return String(Math.round(pos.x)) + ',' + String(Math.round(pos.y)); |
|
|
}; |
|
|
var offset = function(pos, dir, delta) { |
|
|
delta = delta || GRAPHICS.curveControlPointOffset; |
|
|
return { |
|
|
x: pos.x, |
|
|
y: pos.y + flipFactor * delta * dir |
|
|
}; |
|
|
}; |
|
|
var offset2d = function(pos, x, y) { |
|
|
return { |
|
|
x: pos.x + x, |
|
|
y: pos.y + flipFactor * y |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
tailPos = offset(tailPos, -1, this.get('tail').getRadius()); |
|
|
headPos = offset(headPos, 1, this.get('head').getRadius() * 1.15); |
|
|
|
|
|
var str = ''; |
|
|
|
|
|
str += 'M' + coords(tailPos) + ' '; |
|
|
|
|
|
str += 'C'; |
|
|
|
|
|
str += coords(offset(tailPos, -1)) + ' '; |
|
|
str += coords(offset(headPos, 1)) + ' '; |
|
|
|
|
|
str += coords(headPos); |
|
|
|
|
|
|
|
|
var delta = GRAPHICS.arrowHeadSize || 10; |
|
|
str += ' L' + coords(offset2d(headPos, -delta, delta)); |
|
|
str += ' L' + coords(offset2d(headPos, delta, delta)); |
|
|
str += ' L' + coords(headPos); |
|
|
|
|
|
|
|
|
str += 'C'; |
|
|
str += coords(offset(headPos, 1)) + ' '; |
|
|
str += coords(offset(tailPos, -1)) + ' '; |
|
|
str += coords(tailPos); |
|
|
|
|
|
return str; |
|
|
}, |
|
|
|
|
|
getBezierCurve: function() { |
|
|
return this.genSmoothBezierPathString(this.get('tail'), this.get('head')); |
|
|
}, |
|
|
|
|
|
getStrokeColor: function() { |
|
|
return GRAPHICS.visBranchStrokeColorNone; |
|
|
}, |
|
|
|
|
|
setOpacity: function(opacity) { |
|
|
opacity = (opacity === undefined) ? 1 : opacity; |
|
|
|
|
|
this.get('path').attr({opacity: opacity}); |
|
|
}, |
|
|
|
|
|
genGraphics: function(paper) { |
|
|
var pathString = this.getBezierCurve(); |
|
|
|
|
|
var path = paper.path(pathString).attr({ |
|
|
'stroke-width': GRAPHICS.visBranchStrokeWidth, |
|
|
'stroke': this.getStrokeColor(), |
|
|
'stroke-linecap': 'round', |
|
|
'stroke-linejoin': 'round', |
|
|
'fill': this.getStrokeColor() |
|
|
}); |
|
|
path.toBack(); |
|
|
this.set('path', path); |
|
|
}, |
|
|
|
|
|
getOpacity: function() { |
|
|
var stat = this.gitVisuals.getCommitUpstreamStatus(this.get('tail')); |
|
|
var map = { |
|
|
'branch': 1, |
|
|
'tag': 1, |
|
|
'head': GRAPHICS.edgeUpstreamHeadOpacity, |
|
|
'none': GRAPHICS.edgeUpstreamNoneOpacity |
|
|
}; |
|
|
|
|
|
if (map[stat] === undefined) { throw new Error('bad stat'); } |
|
|
return map[stat]; |
|
|
}, |
|
|
|
|
|
getAttributes: function() { |
|
|
var newPath = this.getBezierCurve(); |
|
|
var opacity = this.getOpacity(); |
|
|
return { |
|
|
path: { |
|
|
path: newPath, |
|
|
opacity: opacity |
|
|
} |
|
|
}; |
|
|
}, |
|
|
|
|
|
animateUpdatedPath: function(speed, easing) { |
|
|
var attr = this.getAttributes(); |
|
|
this.animateToAttr(attr, speed, easing); |
|
|
}, |
|
|
|
|
|
animateFromAttrToAttr: function(fromAttr, toAttr, speed, easing) { |
|
|
|
|
|
this.animateToAttr(fromAttr, 0); |
|
|
this.animateToAttr(toAttr, speed, easing); |
|
|
}, |
|
|
|
|
|
animateToAttr: function(attr, speed, easing) { |
|
|
if (speed === 0) { |
|
|
this.get('path').attr(attr.path); |
|
|
return; |
|
|
} |
|
|
|
|
|
this.get('path').toBack(); |
|
|
this.get('path').stop(); |
|
|
this.get('path').animate( |
|
|
attr.path, |
|
|
speed !== undefined ? speed : this.get('animationSpeed'), |
|
|
easing || this.get('animationEasing') |
|
|
); |
|
|
} |
|
|
}); |
|
|
|
|
|
var VisEdgeCollection = Backbone.Collection.extend({ |
|
|
model: VisEdge |
|
|
}); |
|
|
|
|
|
exports.VisEdgeCollection = VisEdgeCollection; |
|
|
exports.VisEdge = VisEdge; |
|
|
|