@jupyterlab/git
Version:
A JupyterLab extension for version control using git
139 lines (138 loc) • 4.87 kB
JavaScript
import * as React from 'react';
import { generateGraphData } from '../generateGraphData';
import { SVGPathData } from '../svgPathData';
const COLOURS = [
'#e11d21',
'#fbca04',
'#009800',
'#006b75',
'#207de5',
'#0052cc',
'#5319e7',
'#f7c6c7',
'#fad8c7',
'#fef2c0',
'#bfe5bf',
'#c7def8',
'#bfdadc',
'#bfd4f2',
'#d4c5f9',
'#cccccc',
'#84b6eb',
'#e6e6e6',
'#cc317c'
];
const DEFAULT_BRANCH_GAP = 10;
const DEFAULT_RADIUS = 3;
const DEFAULT_LINE_WIDTH = 2;
const getColour = function (branch) {
const n = COLOURS.length;
return COLOURS[branch % n];
};
const branchCount = (commitNodes) => {
let maxBranch = -1;
commitNodes.forEach(node => {
maxBranch = node.routes.reduce((max, route) => {
return Math.max(max, route.from, route.to);
}, maxBranch);
});
return maxBranch + 1;
};
export class GitCommitGraph extends React.Component {
constructor(props) {
super(props);
this._graphData = [];
this._x_step = DEFAULT_BRANCH_GAP;
this._dotRadius = this.props.dotRadius || DEFAULT_RADIUS;
this._lineWidth = this.props.lineWidth || DEFAULT_LINE_WIDTH;
}
getGraphData() {
this._graphData = generateGraphData(this.props.commits, this.props.getNodeHeight);
return this._graphData;
}
getBranchCount() {
return branchCount(this.getGraphData());
}
getWidth() {
return (this.getBranchCount() + 0.5) * this._x_step;
}
getHeight() {
// if this.props.commits.length = 0, just pass 0
const numCommits = this.props.commits.length;
const lastNodeHeight = numCommits === 0
? 0
: this.props.getNodeHeight(this.props.commits[numCommits - 1].sha);
const numGraphNodes = this._graphData.length;
const lastYOffset = numGraphNodes === 0
? 0
: this._graphData[this._graphData.length - 1].yOffset;
return lastYOffset + lastNodeHeight;
}
renderRouteNode(svgPathDataAttribute, branch) {
const colour = getColour(branch);
const style = {
stroke: colour,
strokeWidth: this._lineWidth,
fill: 'none'
};
const classes = `commits-graph-branch-${branch}`;
return (React.createElement("path", { d: svgPathDataAttribute, style: style, className: classes }));
}
renderRoute(yOffset, route, height) {
const { from, to, branch } = route;
const x_step = this._x_step;
const svgPath = new SVGPathData();
const from_x = (from + 1) * x_step;
const from_y = yOffset;
const to_x = (to + 1) * x_step;
const to_y = yOffset + height;
svgPath.moveTo(from_x, from_y);
if (from_x === to_x) {
svgPath.lineTo(to_x, to_y);
}
else {
svgPath.bezierCurveTo(from_x - x_step / 4, from_y + height / 2, to_x + x_step / 4, to_y - height / 2, to_x, to_y);
}
return this.renderRouteNode(svgPath.toString(), branch);
}
renderCommitNode(x, y, sha, dot_branch) {
const radius = this._dotRadius;
const colour = getColour(dot_branch);
const strokeWidth = 1;
const style = {
stroke: colour,
strokeWidth: strokeWidth,
fill: colour
};
const classes = `commits-graph-branch-${dot_branch}`;
return (React.createElement("circle", { cx: x, cy: y, r: radius, style: style, "data-sha": sha, className: classes },
React.createElement("title", null, sha.slice(0, 7))));
}
renderCommit(commit) {
const { sha, dot, routes, yOffset } = commit;
const { lateralOffset, branch } = dot;
// draw dot
const x = (lateralOffset + 1) * this._x_step;
const y = yOffset;
const commitNode = this.renderCommitNode(x, y, sha, branch);
const routeNodes = routes.map(route => this.renderRoute(commit.yOffset, route, this.props.getNodeHeight(commit.sha)));
return [commitNode, routeNodes];
}
render() {
// reset lookup table of commit node locations
const allCommitNodes = [];
const allRouteNodes = [];
const commitNodes = this.getGraphData();
commitNodes.forEach(node => {
const commit = node;
const [commitNode, routeNodes] = this.renderCommit(commit);
allCommitNodes.push(commitNode);
allRouteNodes.push(...routeNodes);
});
const children = [...allRouteNodes, ...allCommitNodes];
const height = this.getHeight();
const width = this.getWidth();
const style = { height, width, flexShrink: 0 };
return (React.createElement("svg", { height: height, width: width, style: style }, ...children));
}
}