feat: move git graph legend to top-right corner to avoid overlap with graph
Deploy PR-Helper / deploy (push) Successful in 26s
Deploy PR-Helper / deploy (push) Successful in 26s
This commit is contained in:
@@ -129,6 +129,10 @@ const GitGraph = {
|
|||||||
// Draw branch labels on the right side
|
// Draw branch labels on the right side
|
||||||
this._drawBranchLabels(g, nodeMap, this._laneBranchMap, laneWidth, maxLane);
|
this._drawBranchLabels(g, nodeMap, this._laneBranchMap, laneWidth, maxLane);
|
||||||
|
|
||||||
|
// Draw legend in top-right corner
|
||||||
|
const svgWidth = Math.max(width, graphWidth);
|
||||||
|
this._drawLegend(svg, this._laneBranchMap, svgWidth);
|
||||||
|
|
||||||
// Store for updates
|
// Store for updates
|
||||||
this._nodeMap = nodeMap;
|
this._nodeMap = nodeMap;
|
||||||
|
|
||||||
@@ -429,6 +433,81 @@ const GitGraph = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Draw legend in top-right corner of SVG
|
||||||
|
_drawLegend(svg, laneBranchMap, svgWidth) {
|
||||||
|
const legendPadding = 12;
|
||||||
|
const itemHeight = 20;
|
||||||
|
const circleRadius = 5;
|
||||||
|
const fontSize = 11;
|
||||||
|
|
||||||
|
// Collect unique branches
|
||||||
|
const branches = [];
|
||||||
|
const seen = new Set();
|
||||||
|
Object.values(laneBranchMap).forEach(info => {
|
||||||
|
if (!seen.has(info.name)) {
|
||||||
|
seen.add(info.name);
|
||||||
|
branches.push(info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (branches.length === 0) return;
|
||||||
|
|
||||||
|
// Create legend group
|
||||||
|
const legend = svg.append('g')
|
||||||
|
.attr('class', 'graph-legend');
|
||||||
|
|
||||||
|
// Calculate legend dimensions
|
||||||
|
const tempText = svg.append('text')
|
||||||
|
.attr('font-size', `${fontSize}px`)
|
||||||
|
.attr('font-family', 'system-ui, -apple-system, sans-serif');
|
||||||
|
|
||||||
|
let maxTextWidth = 0;
|
||||||
|
branches.forEach(b => {
|
||||||
|
tempText.text(b.name);
|
||||||
|
maxTextWidth = Math.max(maxTextWidth, tempText.node().getBBox().width);
|
||||||
|
});
|
||||||
|
tempText.remove();
|
||||||
|
|
||||||
|
const legendWidth = circleRadius * 2 + 8 + maxTextWidth + legendPadding * 2;
|
||||||
|
const legendHeight = branches.length * itemHeight + legendPadding * 2;
|
||||||
|
|
||||||
|
// Position in top-right
|
||||||
|
const legendX = svgWidth - legendWidth - 10;
|
||||||
|
const legendY = 10;
|
||||||
|
|
||||||
|
legend.attr('transform', `translate(${legendX},${legendY})`);
|
||||||
|
|
||||||
|
// Background
|
||||||
|
legend.append('rect')
|
||||||
|
.attr('width', legendWidth)
|
||||||
|
.attr('height', legendHeight)
|
||||||
|
.attr('rx', 6)
|
||||||
|
.attr('ry', 6)
|
||||||
|
.attr('fill', 'white')
|
||||||
|
.attr('stroke', '#e5e7eb')
|
||||||
|
.attr('stroke-width', 1)
|
||||||
|
.attr('opacity', 0.95);
|
||||||
|
|
||||||
|
// Legend items
|
||||||
|
branches.forEach((branch, i) => {
|
||||||
|
const itemY = legendPadding + i * itemHeight + itemHeight / 2;
|
||||||
|
|
||||||
|
legend.append('circle')
|
||||||
|
.attr('cx', legendPadding + circleRadius)
|
||||||
|
.attr('cy', itemY)
|
||||||
|
.attr('r', circleRadius)
|
||||||
|
.attr('fill', branch.color);
|
||||||
|
|
||||||
|
legend.append('text')
|
||||||
|
.attr('x', legendPadding + circleRadius * 2 + 8)
|
||||||
|
.attr('y', itemY + 4)
|
||||||
|
.text(branch.name)
|
||||||
|
.attr('font-size', `${fontSize}px`)
|
||||||
|
.attr('fill', '#374151')
|
||||||
|
.attr('font-family', 'system-ui, -apple-system, sans-serif');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
_updateSelectionVisuals() {
|
_updateSelectionVisuals() {
|
||||||
if (!this._nodes || !this._lanes) return;
|
if (!this._nodes || !this._lanes) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user