2016-03-29 15:16:08 +05:30
|
|
|
var db = require('./gitGraphAst');
|
2016-03-31 10:40:35 +05:30
|
|
|
var _ = require('lodash');
|
2016-03-29 15:16:08 +05:30
|
|
|
var gitGraphParser = require('./parser/gitGraph');
|
2016-03-29 08:33:38 +05:30
|
|
|
var d3 = require('../../d3');
|
|
|
|
var Logger = require('../../logger');
|
|
|
|
|
|
|
|
var log = new Logger.Log();
|
2016-03-31 10:40:35 +05:30
|
|
|
var allCommitsDict = {};
|
2016-04-01 14:17:21 +05:30
|
|
|
var branchNum;
|
|
|
|
var config = {
|
|
|
|
nodeWidth: 75,
|
|
|
|
lineStrokeWidth: 4,
|
|
|
|
branchLineHeight: 50,
|
2016-04-25 12:38:48 +05:30
|
|
|
lineColor: 'grey',
|
2016-04-02 11:51:04 +05:30
|
|
|
leftMargin: 50,
|
|
|
|
nodeLabel: {
|
|
|
|
width: 50,
|
|
|
|
height: 100,
|
|
|
|
x: -25,
|
|
|
|
y: 25
|
|
|
|
}
|
2016-04-01 14:17:21 +05:30
|
|
|
}
|
2016-04-01 20:01:46 +05:30
|
|
|
var apiConfig = {};
|
|
|
|
exports.setConf = function(c) {
|
|
|
|
apiConfig = c;
|
2016-03-29 15:16:08 +05:30
|
|
|
}
|
2016-03-29 08:33:38 +05:30
|
|
|
|
2016-04-01 14:17:21 +05:30
|
|
|
|
2016-03-31 10:40:35 +05:30
|
|
|
function svgCreateDefs(svg) {
|
2016-04-02 11:51:04 +05:30
|
|
|
svg
|
2016-04-25 12:38:48 +05:30
|
|
|
.append('defs')
|
|
|
|
.append('g')
|
|
|
|
.attr('id', 'def-commit')
|
|
|
|
.append('circle')
|
|
|
|
.attr('r', 15)
|
|
|
|
.attr('cx', 0)
|
|
|
|
.attr('cy', 0);
|
|
|
|
svg.select('#def-commit')
|
2016-04-01 12:05:59 +05:30
|
|
|
.append('foreignObject')
|
2016-04-02 11:51:04 +05:30
|
|
|
.attr('width', config.nodeLabel.width)
|
|
|
|
.attr('height', config.nodeLabel.height)
|
|
|
|
.attr('x', config.nodeLabel.x)
|
|
|
|
.attr('y', config.nodeLabel.y)
|
2016-04-25 12:38:48 +05:30
|
|
|
.attr('class', 'node-label')
|
2016-04-01 12:05:59 +05:30
|
|
|
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
|
|
|
|
.append('xhtml:p')
|
2016-04-25 12:38:48 +05:30
|
|
|
.html('a big chunk of text that should wrap');
|
2016-03-31 10:40:35 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-01 12:05:59 +05:30
|
|
|
function svgDrawLine(svg, points, interpolate) {
|
2016-04-25 12:38:48 +05:30
|
|
|
interpolate = interpolate || 'basis';
|
2016-03-31 10:40:35 +05:30
|
|
|
var lineGen = d3.svg.line()
|
2016-04-01 12:05:59 +05:30
|
|
|
.x(function(d) {
|
|
|
|
return Math.round(d.x)
|
|
|
|
})
|
|
|
|
.y(function(d) {
|
|
|
|
return Math.round(d.y)
|
|
|
|
})
|
|
|
|
.interpolate(interpolate);
|
2016-03-31 10:40:35 +05:30
|
|
|
|
|
|
|
svg
|
2016-04-25 12:38:48 +05:30
|
|
|
.append('svg:path')
|
|
|
|
.attr('d', lineGen(points))
|
|
|
|
.style('stroke', config.lineColor)
|
|
|
|
.style('stroke-width', config.lineStrokeWidth)
|
|
|
|
.style('fill', 'none');
|
2016-03-31 10:40:35 +05:30
|
|
|
}
|
2016-04-01 12:05:59 +05:30
|
|
|
// Pass in the element and its pre-transform coords
|
|
|
|
function getElementCoords(element, coords) {
|
|
|
|
coords = coords || element.node().getBBox();
|
|
|
|
var ctm = element.node().getCTM(),
|
|
|
|
xn = ctm.e + coords.x * ctm.a,
|
|
|
|
yn = ctm.f + coords.y * ctm.d;
|
|
|
|
//log.debug(ctm, coords);
|
|
|
|
return {
|
|
|
|
left: xn,
|
|
|
|
top: yn,
|
|
|
|
width: coords.width,
|
|
|
|
height: coords.height
|
|
|
|
};
|
2016-04-25 12:38:48 +05:30
|
|
|
}
|
2016-03-31 10:40:35 +05:30
|
|
|
|
|
|
|
function svgDrawLineForCommits(svg, fromId, toId) {
|
2016-04-25 12:38:48 +05:30
|
|
|
log.debug('svgDrawLineForCommits: ', fromId, toId);
|
|
|
|
var fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle'));
|
|
|
|
var toBbox = getElementCoords(svg.select('#node-' + toId + ' circle'));
|
|
|
|
//log.debug('svgDrawLineForCommits: ', fromBbox, toBbox);
|
2016-04-01 14:17:21 +05:30
|
|
|
if (fromBbox.left - toBbox.left > config.nodeWidth) {
|
|
|
|
var lineStart = { x: fromBbox.left - config.nodeWidth, y: toBbox.top + toBbox.height/2};
|
2016-04-01 12:05:59 +05:30
|
|
|
var lineEnd ={ x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height/2 };
|
2016-04-25 12:38:48 +05:30
|
|
|
svgDrawLine(svg, [lineStart , lineEnd], 'linear')
|
2016-04-01 12:05:59 +05:30
|
|
|
svgDrawLine(svg, [
|
|
|
|
{x: fromBbox.left, y: fromBbox.top + fromBbox.height/2},
|
2016-04-01 14:17:21 +05:30
|
|
|
{x: fromBbox.left - config.nodeWidth/2, y: fromBbox.top + fromBbox.height/2},
|
|
|
|
{x: fromBbox.left - config.nodeWidth/2, y: lineStart.y},
|
2016-04-01 12:05:59 +05:30
|
|
|
lineStart]);
|
|
|
|
} else {
|
|
|
|
svgDrawLine(svg, [{
|
2016-04-25 12:38:48 +05:30
|
|
|
'x': fromBbox.left,
|
|
|
|
'y': fromBbox.top + fromBbox.height / 2
|
2016-04-01 12:05:59 +05:30
|
|
|
}, {
|
2016-04-25 12:38:48 +05:30
|
|
|
'x': fromBbox.left - config.nodeWidth/2,
|
|
|
|
'y': fromBbox.top + fromBbox.height / 2
|
2016-04-01 12:05:59 +05:30
|
|
|
}, {
|
2016-04-25 12:38:48 +05:30
|
|
|
'x': fromBbox.left - config.nodeWidth/2,
|
|
|
|
'y': toBbox.top + toBbox.height / 2
|
2016-04-01 12:05:59 +05:30
|
|
|
}, {
|
2016-04-25 12:38:48 +05:30
|
|
|
'x': toBbox.left + toBbox.width,
|
|
|
|
'y': toBbox.top + toBbox.height / 2
|
2016-04-01 12:05:59 +05:30
|
|
|
}]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function cloneNode(svg, selector) {
|
|
|
|
return svg.select(selector).node().cloneNode(true);
|
2016-03-31 10:40:35 +05:30
|
|
|
}
|
2016-04-01 12:05:59 +05:30
|
|
|
|
2016-04-01 14:17:21 +05:30
|
|
|
function renderCommitHistory(svg, commitid, branches, direction) {
|
2016-03-31 10:40:35 +05:30
|
|
|
var commit;
|
|
|
|
if (_.isString(commitid)) {
|
|
|
|
do {
|
|
|
|
commit = allCommitsDict[commitid];
|
2016-04-25 12:38:48 +05:30
|
|
|
log.debug('in renderCommitHistory', commit.id, commit.seq);
|
|
|
|
if (svg.select('#node-' + commitid).size() > 0) {
|
2016-04-01 14:17:21 +05:30
|
|
|
return;
|
|
|
|
}
|
2016-03-31 10:40:35 +05:30
|
|
|
svg
|
2016-04-01 12:05:59 +05:30
|
|
|
.append(function() {
|
2016-04-25 12:38:48 +05:30
|
|
|
return cloneNode(svg, '#def-commit');
|
2016-04-01 12:05:59 +05:30
|
|
|
})
|
2016-04-25 12:38:48 +05:30
|
|
|
.attr('class', 'commit')
|
|
|
|
.attr('id', function() {
|
|
|
|
return 'node-' + commit.id;
|
2016-04-01 12:05:59 +05:30
|
|
|
})
|
2016-04-25 12:38:48 +05:30
|
|
|
.attr('transform', function() {
|
|
|
|
return 'translate(' + (commit.seq * config.nodeWidth + config.leftMargin) + ', '
|
|
|
|
+ (branchNum * config.branchLineHeight) + ')';
|
2016-03-31 10:40:35 +05:30
|
|
|
})
|
2016-04-25 12:38:48 +05:30
|
|
|
.attr('fill', 'yellow')
|
|
|
|
.attr('stroke', 'grey')
|
|
|
|
.attr('stroke-width', '2');
|
2016-03-31 10:40:35 +05:30
|
|
|
|
2016-04-25 12:38:48 +05:30
|
|
|
svg.select('#node-' + commit.id + ' p')
|
2016-04-02 11:51:04 +05:30
|
|
|
.text(commit.id);
|
2016-04-25 12:38:48 +05:30
|
|
|
var branch = _.find(branches, ['commit', commit]);
|
2016-04-02 11:51:04 +05:30
|
|
|
if (branch) {
|
2016-04-25 12:38:48 +05:30
|
|
|
log.debug('found branch ', branch.name);
|
2016-04-02 18:59:12 +05:30
|
|
|
// don't try to select foreignObject - doesn't work.
|
|
|
|
// instead select by class name and it works.
|
2016-04-25 12:38:48 +05:30
|
|
|
svg.select('#node-' + commit.id + ' .node-label')
|
|
|
|
.append('xhtml:p')
|
|
|
|
.attr('class', 'branch-label')
|
2016-04-02 11:51:04 +05:30
|
|
|
.text(branch.name);
|
|
|
|
}
|
2016-03-31 10:40:35 +05:30
|
|
|
commitid = commit.parent
|
|
|
|
} while (commitid && allCommitsDict[commitid]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_.isArray(commitid)) {
|
2016-04-25 12:38:48 +05:30
|
|
|
log.debug('found merge commmit', commitid);
|
2016-04-01 14:17:21 +05:30
|
|
|
renderCommitHistory(svg, commitid[0], branches, direction);
|
|
|
|
branchNum++;
|
|
|
|
renderCommitHistory(svg, commitid[1], branches, direction);
|
2016-03-31 10:40:35 +05:30
|
|
|
}
|
|
|
|
}
|
2016-03-31 14:44:36 +05:30
|
|
|
|
|
|
|
function renderLines(svg, commit) {
|
|
|
|
while (commit.seq > 0) {
|
|
|
|
if (_.isString(commit.parent)) {
|
|
|
|
svgDrawLineForCommits(svg, commit.id, commit.parent);
|
|
|
|
commit = allCommitsDict[commit.parent];
|
|
|
|
} else if (_.isArray(commit.parent)) {
|
|
|
|
svgDrawLineForCommits(svg, commit.id, commit.parent[0])
|
|
|
|
svgDrawLineForCommits(svg, commit.id, commit.parent[1])
|
|
|
|
renderLines(svg, allCommitsDict[commit.parent[1]]);
|
|
|
|
commit = allCommitsDict[commit.parent[0]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-01 12:05:59 +05:30
|
|
|
exports.draw = function(txt, id, ver) {
|
2016-03-30 14:36:39 +05:30
|
|
|
try {
|
2016-03-29 15:16:08 +05:30
|
|
|
var parser;
|
|
|
|
parser = gitGraphParser.parser;
|
|
|
|
parser.yy = db;
|
2016-03-29 08:33:38 +05:30
|
|
|
|
2016-03-29 15:16:08 +05:30
|
|
|
log.debug('in gitgraph renderer', txt, id, ver);
|
|
|
|
// Parse the graph definition
|
2016-04-25 12:38:48 +05:30
|
|
|
parser.parse(txt + '\n');
|
2016-04-01 20:01:46 +05:30
|
|
|
|
|
|
|
config = _.extend(config, apiConfig, db.getOptions());
|
2016-04-25 12:38:48 +05:30
|
|
|
log.debug('effective options', config);
|
2016-03-30 14:36:39 +05:30
|
|
|
var direction = db.getDirection();
|
2016-03-31 10:40:35 +05:30
|
|
|
allCommitsDict = db.getCommits();
|
|
|
|
var branches = db.getBranchesAsObjArray();
|
2016-03-30 14:36:39 +05:30
|
|
|
var svg = d3.select('#' + id);
|
2016-03-31 10:40:35 +05:30
|
|
|
svgCreateDefs(svg);
|
2016-04-01 14:17:21 +05:30
|
|
|
branchNum = 1;
|
2016-04-25 12:38:48 +05:30
|
|
|
_.each(branches, function(v) {
|
2016-04-01 14:17:21 +05:30
|
|
|
renderCommitHistory(svg, v.commit.id, branches, direction);
|
2016-03-31 15:47:38 +05:30
|
|
|
renderLines(svg, v.commit);
|
|
|
|
branchNum++;
|
|
|
|
})
|
2016-03-29 08:33:38 +05:30
|
|
|
|
2016-03-30 14:36:39 +05:30
|
|
|
svg.attr('height', 900);
|
2016-04-01 14:17:21 +05:30
|
|
|
svg.attr('width', 2500);
|
2016-03-30 14:36:39 +05:30
|
|
|
} catch (e) {
|
2016-04-25 12:38:48 +05:30
|
|
|
log.error('Error while rendering gitgraph');
|
2016-03-29 15:16:08 +05:30
|
|
|
log.error(e.message);
|
|
|
|
}
|
2016-03-29 08:33:38 +05:30
|
|
|
};
|