Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/renderer/src/components/graph/GraphCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,9 @@ export function GraphCanvas({
const clampView = useCallback(() => {
const view = viewRef.current
const { width, height } = sizeRef.current
const cs = contentSize(sceneRef.current.layout, sceneRef.current.wip?.column ?? null)
const cs = contentSize(sceneRef.current.layout, sceneRef.current.wip?.column ?? null, (row) =>
labelWidthFor(row.name)
)
const cw = cs.width * view.scale
const ch = cs.height * view.scale
const clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), hi)
Expand Down Expand Up @@ -358,7 +360,9 @@ export function GraphCanvas({
zoomAnim.stop()
panInertia.cancel()
const { width, height } = sizeRef.current
const cs = contentSize(sceneRef.current.layout, sceneRef.current.wip?.column ?? null)
const cs = contentSize(sceneRef.current.layout, sceneRef.current.wip?.column ?? null, (row) =>
labelWidthFor(row.name)
)
const view = viewRef.current
view.scale = Math.min(
MAX_SCALE,
Expand Down
16 changes: 16 additions & 0 deletions src/renderer/src/components/graph/geometry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,20 @@ describe('graph geometry', () => {
44
)
})

test('contentSize grows to cover a label pill overhanging its last column', () => {
const layout = sampleLayout()
const feature = layout.rows.find((r) => r.name === 'feature')
if (!feature) throw new Error('missing feature row')
// A name far wider than the row span: the pill's right edge (rest position
// plus the pill's own padding) plus the margin sets the content width.
const textWidth = 400
const { width } = contentSize(layout, null, () => textWidth)
expect(width).toBe(nodeX(feature.startColumn) - NODE_R + textWidth + 16 + 28)
})

test('contentSize ignores labels that fit inside their row span', () => {
const layout = sampleLayout()
expect(contentSize(layout, null, () => 10)).toEqual(contentSize(layout, null))
})
})
17 changes: 14 additions & 3 deletions src/renderer/src/components/graph/geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,27 @@ export const toWorldY = (view: View, screenY: number): number => (screenY - view
/** World-space size of the whole diagram. `wipColumn` is the WIP node's
* column when it shows, or null. Both it and an empty branch's reserved slot
* can sit past the last commit column, so width follows the rightmost of
* commits, row spans and the WIP node. */
* commits, row spans and the WIP node — and, when `labelWidth` is given, of
* label pills too: a long branch name on a short row overhangs its last
* column, and pan/fit clamp to this size, so an uncounted overhang would be
* forever cut at the viewport edge. */
export function contentSize(
layout: GraphLayout,
wipColumn: number | null
wipColumn: number | null,
labelWidth?: (row: GraphRow) => number
): { width: number; height: number } {
let last = layout.columnCount - 1
for (const row of layout.rows) last = Math.max(last, row.endColumn)
if (wipColumn !== null) last = Math.max(last, wipColumn)
let width = MARGIN_X * 2 + Math.max(1, last + 1) * COL_W
if (labelWidth) {
for (const row of layout.rows) {
const rect = labelRect(row, labelWidth(row))
width = Math.max(width, rect.x + rect.w + MARGIN_X)
}
}
return {
width: MARGIN_X * 2 + Math.max(1, last + 1) * COL_W,
width,
height: MARGIN_Y + Math.max(1, layout.rowCount) * ROW_H + ROW_H / 2
}
}
Expand Down
Loading