markdown-it-git-graph
Version:
一个markdown-it插件,用于生成git提交图
123 lines (122 loc) • 4.52 kB
JavaScript
function newPoint(hash, x, y, color) {
return {
x,
y,
color,
draw(id, theme) {
return `<circle id="p-${id}-${hash}" cx="${this.x}" cy="${this.y}" r="${theme.pointRadius}" fill="${this.color}" />`;
},
};
}
function newLine(from, to, color) {
return {
from,
to,
color,
draw() {
return `<line x1="${this.from.x}" y1="${this.from.y}" x2="${this.to.x}" y2="${this.to.y}" stroke="${this.color}" stroke-width="2" />`;
},
};
}
function newMergeLine(from, to, color) {
return {
from,
to,
color,
draw(_, theme) {
const flag = Math.abs(this.to.y - this.from.y) > theme.lineHeight;
const x1 = this.from.x;
const y1 = this.to.y > this.from.y ? this.to.y - theme.lineHeight : this.to.y + theme.lineHeight;
const x2 = this.to.x;
const y2 = this.to.y;
return `<path d="M ${this.from.x} ${this.from.y}${flag ? ` ${x1} ${y1}` : ''} C ${0.8 * x1 + 0.2 * x2} ${0.2 * y1 + 0.8 * y2} ${0.2 * x1 + 0.8 * x2} ${0.8 * y1 + 0.2 * y2} ${x2} ${y2}" stroke="${this.color}" stroke-width="2" fill="none" />`;
},
};
}
function addToSvg(commits, svg, theme) {
svg.height = commits.length * theme.lineHeight;
const padding = {
x: theme.lineWidth / 2,
y: theme.lineHeight / 2,
};
const branchInfoCache = {};
const points = {};
for (let i = 0; i < commits.length; i++) {
const commit = commits[i];
if (points[commit.hash]) {
svg.errors.push({
draw: () => `commit ${commit.hash} is not uniqued`,
});
continue;
}
let branch = branchInfoCache[commit.branch.id];
if (!branch) {
branch = {
color: commit.branch.id < theme.colors.length ? theme.colors[commit.branch.id] : randomColor(),
x: commit.branch.id * theme.lineWidth + padding.x,
};
branchInfoCache[commit.branch.id] = branch;
}
const point = newPoint(commit.hash, branch.x, i * theme.lineHeight + padding.y, branch.color);
points[commit.hash] = point;
svg.points.push(point);
}
svg.width = (Object.keys(branchInfoCache).length) * theme.lineWidth;
for (let i = 0; i < commits.length; i++) {
const commit = commits[i];
const point = points[commit.hash];
if (commit.base === undefined && commit.merge === undefined) {
svg.lines.push(newLine({
x: point.x,
y: svg.height - padding.y,
}, point, point.color));
continue;
}
if (commit.base !== undefined) {
const basePoint = points[commit.base];
if (!basePoint) {
svg.errors.push({
draw: () => `commit ${commit.hash} base ${commit.base} not found`,
});
}
else {
svg.lines.push(newLine(basePoint, point, point.color));
}
}
if (commit.merge !== undefined) {
const mergePoint = points[commit.merge];
if (!mergePoint) {
svg.errors.push({
draw: () => `commit ${commit.hash} merge ${commit.merge} not found`,
});
}
else {
svg.mergeLines.push(newMergeLine(mergePoint, point, commit.base ? mergePoint.color : point.color));
}
}
}
}
function getSvg(idx, commits, options) {
const svg = {
id: idx.toString(),
width: 0,
height: 0,
points: [],
lines: [],
mergeLines: [],
errors: [],
draw(_, theme) {
if (svg.errors.length > 0) {
return `<svg width=300 height=100 xmlns='http://www.w3.org/2000/svg'>
${svg.errors.map(e => e.draw(this.id, theme)).join('\n')}</svg>`;
}
return `<svg width='${this.width}' height='${this.height}' xmlns='http://www.w3.org/2000/svg'>${this.mergeLines.map(e => e.draw(this.id, theme)).join('')}${this.lines.map(e => e.draw(this.id, theme)).join('')}${this.points.map(e => e.draw(this.id, theme)).join('')}</svg>`;
},
};
addToSvg(commits, svg, options.theme);
return svg;
}
function randomColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
export { getSvg, newLine, newMergeLine, newPoint, };