diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.ts b/packages/mermaid/src/diagrams/git/gitGraphRenderer.ts index ec9a39f2a3..3493fa9953 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.ts +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.ts @@ -9,6 +9,9 @@ import type { GitGraphDiagramConfig } from '../../config.type.js'; let allCommitsDict = new Map(); +const LAYOUT_OFFSET = 10; +const COMMIT_STEP = 40; + const commitType: CommitType = { NORMAL: 0, REVERSE: 1, @@ -29,6 +32,10 @@ interface CommitPosition { y: number; } +interface CommitPositionOffset extends CommitPosition { + posWithOffset: number; +} + const branchPos = new Map(); const commitPos = new Map(); let lanes: number[] = []; @@ -93,9 +100,7 @@ const findClosestParent = (parents: string[], useBTLogic = false): string | unde const setParallelBTPos = ( sortedKeys: string[], commits: Map, - defaultPos: number, - commitStep: number, - layoutOffset: number + defaultPos: number ) => { let curPos = defaultPos; let maxPosition = defaultPos; @@ -108,12 +113,12 @@ const setParallelBTPos = ( } if (hasParents(commit)) { - curPos = calculateCommitPosition(commit, commitStep, maxPosition); + curPos = calculateCommitPosition(commit); maxPosition = Math.max(curPos, maxPosition); } else { roots.push(commit); } - setCommitPosition(commit, curPos, layoutOffset); + setCommitPosition(commit, curPos); }); curPos = maxPosition; @@ -125,7 +130,7 @@ const setParallelBTPos = ( const hasParents = (commit: Commit): boolean => commit.parents?.length > 0; const findClosestParentPos = (commit: Commit): number => { - const closestParent = findClosestParent(commit.parents.filter((p) => p !== null) as string[]); + const closestParent = findClosestParent(commit.parents.filter((p) => p !== null)); if (!closestParent) { throw new Error(`Closest parent not found for commit ${commit.id}`); } @@ -137,19 +142,19 @@ const findClosestParentPos = (commit: Commit): number => { return closestParentPos; }; -const calculateCommitPosition = (commit: Commit, commitStep: number): number => { +const calculateCommitPosition = (commit: Commit): number => { const closestParentPos = findClosestParentPos(commit); - return closestParentPos + commitStep; + return closestParentPos + COMMIT_STEP; }; -const setCommitPosition = (commit: Commit, curPos: number, layoutOffset: number) => { +const setCommitPosition = (commit: Commit, curPos: number) => { const branch = branchPos.get(commit.branch); if (!branch) { throw new Error(`Branch not found for commit ${commit.id}`); } const x = branch.pos; - const y = curPos + layoutOffset; + const y = curPos + LAYOUT_OFFSET; commitPos.set(commit.id, { x, y }); }; @@ -167,8 +172,7 @@ const setRootPosition = (commit: Commit, curPos: number, defaultPos: number) => const drawCommitBullet = ( gBullets: d3.Selection, commit: Commit, - x: number, - y: number, + commitPosition: CommitPositionOffset, typeClass: string, branchIndex: number, commitSymbolType: number @@ -176,8 +180,8 @@ const drawCommitBullet = ( if (commitSymbolType === commitType.HIGHLIGHT) { gBullets .append('rect') - .attr('x', x - 10) - .attr('y', y - 10) + .attr('x', commitPosition.x - 10) + .attr('y', commitPosition.y - 10) .attr('width', 20) .attr('height', 20) .attr( @@ -186,8 +190,8 @@ const drawCommitBullet = ( ); gBullets .append('rect') - .attr('x', x - 6) - .attr('y', y - 6) + .attr('x', commitPosition.x - 6) + .attr('y', commitPosition.y - 6) .attr('width', 12) .attr('height', 12) .attr( @@ -197,50 +201,50 @@ const drawCommitBullet = ( } else if (commitSymbolType === commitType.CHERRY_PICK) { gBullets .append('circle') - .attr('cx', x) - .attr('cy', y) + .attr('cx', commitPosition.x) + .attr('cy', commitPosition.y) .attr('r', 10) .attr('class', `commit ${commit.id} ${typeClass}`); gBullets .append('circle') - .attr('cx', x - 3) - .attr('cy', y + 2) + .attr('cx', commitPosition.x - 3) + .attr('cy', commitPosition.y + 2) .attr('r', 2.75) .attr('fill', '#fff') .attr('class', `commit ${commit.id} ${typeClass}`); gBullets .append('circle') - .attr('cx', x + 3) - .attr('cy', y + 2) + .attr('cx', commitPosition.x + 3) + .attr('cy', commitPosition.y + 2) .attr('r', 2.75) .attr('fill', '#fff') .attr('class', `commit ${commit.id} ${typeClass}`); gBullets .append('line') - .attr('x1', x + 3) - .attr('y1', y + 1) - .attr('x2', x) - .attr('y2', y - 5) + .attr('x1', commitPosition.x + 3) + .attr('y1', commitPosition.y + 1) + .attr('x2', commitPosition.x) + .attr('y2', commitPosition.y - 5) .attr('stroke', '#fff') .attr('class', `commit ${commit.id} ${typeClass}`); gBullets .append('line') - .attr('x1', x - 3) - .attr('y1', y + 1) - .attr('x2', x) - .attr('y2', y - 5) + .attr('x1', commitPosition.x - 3) + .attr('y1', commitPosition.y + 1) + .attr('x2', commitPosition.x) + .attr('y2', commitPosition.y - 5) .attr('stroke', '#fff') .attr('class', `commit ${commit.id} ${typeClass}`); } else { const circle = gBullets.append('circle'); - circle.attr('cx', x); - circle.attr('cy', y); + circle.attr('cx', commitPosition.x); + circle.attr('cy', commitPosition.y); circle.attr('r', commit.type === commitType.MERGE ? 9 : 10); circle.attr('class', `commit ${commit.id} commit${branchIndex % THEME_COLOR_LIMIT}`); if (commit.type === commitType.MERGE) { const circle2 = gBullets.append('circle'); - circle2.attr('cx', x); - circle2.attr('cy', y); + circle2.attr('cx', commitPosition.x); + circle2.attr('cy', commitPosition.y); circle2.attr('r', 6); circle2.attr( 'class', @@ -250,7 +254,10 @@ const drawCommitBullet = ( if (commitSymbolType === commitType.REVERSE) { const cross = gBullets.append('path'); cross - .attr('d', `M ${x - 5},${y - 5}L${x + 5},${y + 5}M${x - 5},${y + 5}L${x + 5},${y - 5}`) + .attr( + 'd', + `M ${commitPosition.x - 5},${commitPosition.y - 5}L${commitPosition.x + 5},${commitPosition.y + 5}M${commitPosition.x - 5},${commitPosition.y + 5}L${commitPosition.x + 5},${commitPosition.y - 5}` + ) .attr('class', `commit ${typeClass} ${commit.id} commit${branchIndex % THEME_COLOR_LIMIT}`); } } @@ -259,10 +266,8 @@ const drawCommitBullet = ( const drawCommitLabel = ( gLabels: d3.Selection, commit: Commit, - x: number, - y: number, + commitPosition: CommitPositionOffset, pos: number, - posWithOffset: number, gitGraphConfig: GitGraphDiagramConfig ) => { if ( @@ -274,34 +279,52 @@ const drawCommitLabel = ( const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg'); const text = wrapper .append('text') - .attr('x', x) - .attr('y', y + 25) + .attr('x', commitPosition.x) + .attr('y', commitPosition.y + 25) .attr('class', 'commit-label') .text(commit.id); const bbox = text.node()?.getBBox(); if (bbox) { labelBkg - .attr('x', posWithOffset - bbox.width / 2 - 2) - .attr('y', y + 13.5) + .attr('x', commitPosition.posWithOffset - bbox.width / 2 - 2) + .attr('y', commitPosition.y + 13.5) .attr('width', bbox.width + 4) .attr('height', bbox.height + 4); if (dir === 'TB' || dir === 'BT') { - labelBkg.attr('x', x - (bbox.width + 4)).attr('y', y - 12); - text.attr('x', x - (bbox.width + 2)).attr('y', y + bbox.height - 12); + labelBkg.attr('x', commitPosition.x - (bbox.width + 4)).attr('y', commitPosition.y - 12); + text + .attr('x', commitPosition.x - (bbox.width + 2)) + .attr('y', commitPosition.y + bbox.height - 12); } if (gitGraphConfig.rotateCommitLabel) { if (dir === 'TB' || dir === 'BT') { - text.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')'); - labelBkg.attr('transform', 'rotate(' + -45 + ', ' + x + ', ' + y + ')'); + text.attr( + 'transform', + 'rotate(' + -45 + ', ' + commitPosition.x + ', ' + commitPosition.y + ')' + ); + labelBkg.attr( + 'transform', + 'rotate(' + -45 + ', ' + commitPosition.x + ', ' + commitPosition.y + ')' + ); } else { const r_x = -7.5 - ((bbox.width + 10) / 25) * 9.5; const r_y = 10 + (bbox.width / 25) * 8.5; wrapper.attr( 'transform', - 'translate(' + r_x + ', ' + r_y + ') rotate(' + -45 + ', ' + pos + ', ' + y + ')' + 'translate(' + + r_x + + ', ' + + r_y + + ') rotate(' + + -45 + + ', ' + + pos + + ', ' + + commitPosition.y + + ')' ); } } @@ -312,11 +335,8 @@ const drawCommitLabel = ( const drawCommitTags = ( gLabels: d3.Selection, commit: Commit, - x: number, - y: number, - pos: number, - posWithOffset: number, - layoutOffset: number + commitPosition: CommitPositionOffset, + pos: number ) => { if (commit.tags.length > 0) { let yOffset = 0; @@ -329,7 +349,7 @@ const drawCommitTags = ( const hole = gLabels.append('circle'); const tag = gLabels .append('text') - .attr('y', y - 16 - yOffset) + .attr('y', commitPosition.y - 16 - yOffset) .attr('class', 'tag-label') .text(tagValue); const tagBbox = tag.node()?.getBBox(); @@ -339,7 +359,7 @@ const drawCommitTags = ( maxTagBboxWidth = Math.max(maxTagBboxWidth, tagBbox.width); maxTagBboxHeight = Math.max(maxTagBboxHeight, tagBbox.height); - tag.attr('x', posWithOffset - tagBbox.width / 2); + tag.attr('x', commitPosition.posWithOffset - tagBbox.width / 2); tagElements.push({ tag, @@ -353,16 +373,16 @@ const drawCommitTags = ( for (const { tag, hole, rect, yOffset } of tagElements) { const h2 = maxTagBboxHeight / 2; - const ly = y - 19.2 - yOffset; + const ly = commitPosition.y - 19.2 - yOffset; rect.attr('class', 'tag-label-bkg').attr( 'points', ` ${pos - maxTagBboxWidth / 2 - 2},${ly + 2} ${pos - maxTagBboxWidth / 2 - 2},${ly - 2} - ${posWithOffset - maxTagBboxWidth / 2 - 4},${ly - h2 - 2} - ${posWithOffset + maxTagBboxWidth / 2 + 4},${ly - h2 - 2} - ${posWithOffset + maxTagBboxWidth / 2 + 4},${ly + h2 + 2} - ${posWithOffset - maxTagBboxWidth / 2 - 4},${ly + h2 + 2}` + ${commitPosition.posWithOffset - maxTagBboxWidth / 2 - 4},${ly - h2 - 2} + ${commitPosition.posWithOffset + maxTagBboxWidth / 2 + 4},${ly - h2 - 2} + ${commitPosition.posWithOffset + maxTagBboxWidth / 2 + 4},${ly + h2 + 2} + ${commitPosition.posWithOffset - maxTagBboxWidth / 2 - 4},${ly + h2 + 2}` ); hole @@ -379,22 +399,22 @@ const drawCommitTags = ( .attr( 'points', ` - ${x},${yOrigin + 2} - ${x},${yOrigin - 2} - ${x + layoutOffset},${yOrigin - h2 - 2} - ${x + layoutOffset + maxTagBboxWidth + 4},${yOrigin - h2 - 2} - ${x + layoutOffset + maxTagBboxWidth + 4},${yOrigin + h2 + 2} - ${x + layoutOffset},${yOrigin + h2 + 2}` + ${commitPosition.x},${yOrigin + 2} + ${commitPosition.x},${yOrigin - 2} + ${commitPosition.x + LAYOUT_OFFSET},${yOrigin - h2 - 2} + ${commitPosition.x + LAYOUT_OFFSET + maxTagBboxWidth + 4},${yOrigin - h2 - 2} + ${commitPosition.x + LAYOUT_OFFSET + maxTagBboxWidth + 4},${yOrigin + h2 + 2} + ${commitPosition.x + LAYOUT_OFFSET},${yOrigin + h2 + 2}` ) - .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); + .attr('transform', 'translate(12,12) rotate(45, ' + commitPosition.x + ',' + pos + ')'); hole - .attr('cx', x + 2) + .attr('cx', commitPosition.x + 2) .attr('cy', yOrigin) - .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); + .attr('transform', 'translate(12,12) rotate(45, ' + commitPosition.x + ',' + pos + ')'); tag - .attr('x', x + 5) + .attr('x', commitPosition.x + 5) .attr('y', yOrigin + 3) - .attr('transform', 'translate(14,14) rotate(45, ' + x + ',' + pos + ')'); + .attr('transform', 'translate(14,14) rotate(45, ' + commitPosition.x + ',' + pos + ')'); } } } @@ -421,45 +441,50 @@ const getCommitClassType = (commit: Commit): string => { const calculatePosition = ( commit: Commit, dir: string, - isParallelCommits: boolean, pos: number, - commitStep: number, - layoutOffset: number, commitPos: Map ): number => { - const defaultCommitPosition = { x: 0, y: defaultPos }; // Default position if commit is not found - - if (isParallelCommits) { - if (commit.parents.length > 0) { - const closestParent = - dir === 'BT' ? findClosestParent(commit.parents) : findClosestParent(commit.parents); - - // Check if closestParent is defined - if (closestParent) { - const parentPosition = commitPos.get(closestParent) ?? defaultCommitPosition; - - if (dir === 'TB') { - return parentPosition.y + commitStep; - } else if (dir === 'BT') { - const currentPosition = commitPos.get(commit.id) ?? defaultCommitPosition; - return currentPosition.y - commitStep; - } else { - return parentPosition.x + commitStep; - } - } - } else { + const defaultCommitPosition = { x: 0, y: 0 }; // Default position if commit is not found + + if (commit.parents.length > 0) { + const closestParent = findClosestParent(commit.parents); + if (closestParent) { + const parentPosition = commitPos.get(closestParent) ?? defaultCommitPosition; + if (dir === 'TB') { - return defaultPos; + return parentPosition.y + COMMIT_STEP; } else if (dir === 'BT') { const currentPosition = commitPos.get(commit.id) ?? defaultCommitPosition; - return currentPosition.y - commitStep; + return currentPosition.y - COMMIT_STEP; } else { - return 0; + return parentPosition.x + COMMIT_STEP; } } + } else { + if (dir === 'TB') { + return defaultPos; + } else if (dir === 'BT') { + const currentPosition = commitPos.get(commit.id) ?? defaultCommitPosition; + return currentPosition.y - COMMIT_STEP; + } else { + return 0; + } } + return 0; +}; - return dir === 'TB' && isParallelCommits ? pos : pos + layoutOffset; +const getCommitPosition = ( + commit: Commit, + pos: number, + isParallelCommits: boolean +): CommitPositionOffset => { + const posWithOffset = dir === 'BT' && isParallelCommits ? pos : pos + LAYOUT_OFFSET; + const y = dir === 'TB' || dir === 'BT' ? posWithOffset : branchPos.get(commit.branch)?.pos; + const x = dir === 'TB' || dir === 'BT' ? branchPos.get(commit.branch)?.pos : posWithOffset; + if (x === undefined || y === undefined) { + throw new Error(`Position were undefined for commit ${commit.id}`); + } + return { x, y, posWithOffset }; }; const drawCommits = ( @@ -476,8 +501,6 @@ const drawCommits = ( let pos = dir === 'TB' || dir === 'BT' ? defaultPos : 0; const keys = [...commits.keys()]; const isParallelCommits = gitGraphConfig?.parallelCommits ?? false; - const layoutOffset = 10; - const commitStep = 40; const sortKeys = (a: string, b: string) => { const seqA = commits.get(a)?.seq; @@ -487,12 +510,10 @@ const drawCommits = ( let sortedKeys = keys.sort(sortKeys); - if (dir === 'BT' && !isParallelCommits) { - sortedKeys = sortedKeys.reverse(); - } - - if (dir === 'BT' && isParallelCommits) { - setParallelBTPos(sortedKeys, commits, pos, commitStep, layoutOffset); + if (dir === 'BT') { + if (isParallelCommits) { + setParallelBTPos(sortedKeys, commits, pos); + } sortedKeys = sortedKeys.reverse(); } @@ -500,40 +521,29 @@ const drawCommits = ( const commit = commits.get(key); if (!commit) { throw new Error(`Commit not found for key ${key}`); + } + if (isParallelCommits) { + pos = calculatePosition(commit, dir, pos, commitPos); + } + + const commitPosition = getCommitPosition(commit, pos, isParallelCommits); + // Don't draw the commits now but calculate the positioning which is used by the branch lines etc. + if (modifyGraph) { + const typeClass = getCommitClassType(commit); + const commitSymbolType = commit.customType ?? commit.type; + const branchIndex = branchPos.get(commit.branch)?.index ?? 0; + drawCommitBullet(gBullets, commit, commitPosition, typeClass, branchIndex, commitSymbolType); + drawCommitLabel(gLabels, commit, commitPosition, pos, gitGraphConfig); + drawCommitTags(gLabels, commit, commitPosition, pos); + } + if (dir === 'TB' || dir === 'BT') { + commitPos.set(commit.id, { x: commitPosition.x, y: commitPosition.posWithOffset }); } else { - pos = calculatePosition( - commit, - dir, - isParallelCommits, - pos, - commitStep, - layoutOffset, - commitPos - ); - const posWithOffset = dir === 'BT' && isParallelCommits ? pos : pos + layoutOffset; - const y = dir === 'TB' || dir === 'BT' ? posWithOffset : branchPos.get(commit.branch)?.pos; - const x = dir === 'TB' || dir === 'BT' ? branchPos.get(commit.branch)?.pos : posWithOffset; - if (x === undefined || y === undefined) { - throw new Error(`Position were undefined for commit ${commit.id}`); - } - // Don't draw the commits now but calculate the positioning which is used by the branch lines etc. - if (modifyGraph) { - const typeClass = getCommitClassType(commit); - const commitSymbolType = commit.customType ?? commit.type; - const branchIndex = branchPos.get(commit.branch)?.index ?? 0; - drawCommitBullet(gBullets, commit, x, y, typeClass, branchIndex, commitSymbolType); - drawCommitLabel(gLabels, commit, x, y, pos, posWithOffset, gitGraphConfig); - drawCommitTags(gLabels, commit, x, y, pos, posWithOffset, layoutOffset); - } - if (dir === 'TB' || dir === 'BT') { - commitPos.set(commit.id, { x: x, y: posWithOffset }); - } else { - commitPos.set(commit.id, { x: posWithOffset, y: y }); - } - pos = dir === 'BT' && isParallelCommits ? pos + commitStep : pos + commitStep + layoutOffset; - if (pos > maxPos) { - maxPos = pos; - } + commitPos.set(commit.id, { x: commitPosition.posWithOffset, y: commitPosition.y }); + } + pos = dir === 'BT' && isParallelCommits ? pos + COMMIT_STEP : pos + COMMIT_STEP + LAYOUT_OFFSET; + if (pos > maxPos) { + maxPos = pos; } }); }; @@ -904,65 +914,269 @@ const drawBranches = ( }); }; +const setBranchPosition = function ( + name: string, + pos: number, + index: number, + bbox: DOMRect, + rotateCommitLabel: boolean +): number { + branchPos.set(name, { pos, index }); + pos += 50 + (rotateCommitLabel ? 40 : 0) + (dir === 'TB' || dir === 'BT' ? bbox.width / 2 : 0); + return pos; +}; + export const draw: DrawDefinition = function (txt, id, ver, diagObj) { clear(); const conf = getConfig(); const gitGraphConfig = conf.gitGraph; - // try { + log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver); + if (!gitGraphConfig) { + throw new Error('GitGraph config not found'); + } + const rotateCommitLabel = gitGraphConfig.rotateCommitLabel ?? false; const db = diagObj.db as GitGraphDB; allCommitsDict = db.getCommits(); const branches = db.getBranchesAsObjArray(); dir = db.getDirection(); const diagram = select(`[id="${id}"]`); - // Position branches let pos = 0; + branches.forEach((branch, index) => { const labelElement = drawText(branch.name); const g = diagram.append('g'); const branchLabel = g.insert('g').attr('class', 'branchLabel'); const label = branchLabel.insert('g').attr('class', 'label branch-label'); - // @ts-ignore: TODO Fix ts errors - label.node().appendChild(labelElement); const bbox = labelElement.getBBox(); - - branchPos.set(branch.name, { pos, index }); - pos += - 50 + - // @ts-ignore: TODO Fix ts errors - (gitGraphConfig.rotateCommitLabel ? 40 : 0) + - (dir === 'TB' || dir === 'BT' ? bbox.width / 2 : 0); + pos = setBranchPosition(branch.name, pos, index, bbox, rotateCommitLabel); label.remove(); branchLabel.remove(); g.remove(); }); drawCommits(diagram, allCommitsDict, false); - // @ts-ignore: TODO Fix ts errors if (gitGraphConfig.showBranches) { drawBranches(diagram, branches); } drawArrows(diagram, allCommitsDict); drawCommits(diagram, allCommitsDict, true); + utils.insertTitle( diagram, 'gitTitleText', - // @ts-ignore: TODO Fix ts errors - gitGraphConfig.titleTopMargin, + gitGraphConfig.titleTopMargin ?? 0, db.getDiagramTitle() ); // Setup the view box and size of the svg element - setupGraphViewbox( - undefined, - diagram, - // @ts-ignore: TODO Fix ts errors - gitGraphConfig.diagramPadding, - // @ts-ignore: TODO Fix ts errors - gitGraphConfig.useMaxWidth ?? conf.useMaxWidth - ); + setupGraphViewbox(undefined, diagram, gitGraphConfig.diagramPadding, gitGraphConfig.useMaxWidth); }; export default { draw, }; + +if (import.meta.vitest) { + const { it, expect, describe } = import.meta.vitest; + + describe('drawText', () => { + it('should drawText', () => { + const svgLabel = drawText('main'); + expect(svgLabel).toBeDefined(); + expect(svgLabel.children[0].innerHTML).toBe('main'); + }); + }); + + describe('drawBranchPositions', () => { + const bbox: DOMRect = { + x: 0, + y: 0, + width: 10, + height: 10, + top: 0, + right: 0, + bottom: 0, + left: 0, + toJSON: () => '', + }; + + it('should setBranchPositions LR with two branches', () => { + dir = 'LR'; + + const pos = setBranchPosition('main', 0, 0, bbox, true); + expect(pos).toBe(90); + expect(branchPos.get('main')).toEqual({ pos: 0, index: 0 }); + const posNext = setBranchPosition('develop', pos, 1, bbox, true); + expect(posNext).toBe(180); + expect(branchPos.get('develop')).toEqual({ pos: pos, index: 1 }); + }); + + it('should setBranchPositions TB with two branches', () => { + dir = 'TB'; + bbox.width = 34.9921875; + + const pos = setBranchPosition('main', 0, 0, bbox, true); + expect(pos).toBe(107.49609375); + expect(branchPos.get('main')).toEqual({ pos: 0, index: 0 }); + + bbox.width = 56.421875; + const posNext = setBranchPosition('develop', pos, 1, bbox, true); + expect(posNext).toBe(225.70703125); + expect(branchPos.get('develop')).toEqual({ pos: pos, index: 1 }); + }); + }); + /* + describe('drawCommits', () => { + dir = 'TB'; + const commits = new Map([ + [ + 'commitZero', + { + id: 'ZERO', + message: '', + seq: 0, + type: commitType.NORMAL, + tags: [], + parents: [], + branch: 'main', + }, + ], + [ + 'commitA', + { + id: 'A', + message: '', + seq: 1, + type: commitType.NORMAL, + tags: [], + parents: ['ZERO'], + branch: 'feature', + }, + ], + [ + 'commitB', + { + id: 'B', + message: '', + seq: 2, + type: commitType.NORMAL, + tags: [], + parents: ['A'], + branch: 'feature', + }, + ], + [ + 'commitM', + { + id: 'M', + message: 'merged branch feature into main', + seq: 3, + type: commitType.MERGE, + tags: [], + parents: ['ZERO', 'B'], + branch: 'main', + customId: true, + }, + ], + [ + 'commitC', + { + id: 'C', + message: '', + seq: 4, + type: commitType.NORMAL, + tags: [], + parents: ['ZERO'], + branch: 'release', + }, + ], + [ + 'commit5_8928ea0', + { + id: '5-8928ea0', + message: 'cherry-picked [object Object] into release', + seq: 5, + type: commitType.CHERRY_PICK, + tags: [], + parents: ['C', 'M'], + branch: 'release', + }, + ], + [ + 'commitD', + { + id: 'D', + message: '', + seq: 6, + type: commitType.NORMAL, + tags: [], + parents: ['5-8928ea0'], + branch: 'release', + }, + ], + [ + 'commit7_ed848ba', + { + id: '7-ed848ba', + message: 'cherry-picked [object Object] into release', + seq: 7, + type: commitType.CHERRY_PICK, + tags: [], + parents: ['D', 'M'], + branch: 'release', + }, + ], + ]); + + branchPos.set('main', { pos: 0, index: 0 }); + branchPos.set('feature', { pos: 107.49609375, index: 1 }); + branchPos.set('release', { pos: 224.03515625, index: 2 }); + + commits.forEach((commit) => { + it(`should draw commit ${commit.id}`, () => { + const commitPosition = getCommitPosition(commit, 0, false); + expect(commitPosition).toBeDefined(); + }); + it(`should draw commit ${commit.id} with position`, () => { + const commitPosition = getCommitPosition(commit, 0, false); + expect(commitPosition.x).toBeDefined(); + expect(commitPosition.y).toBeDefined(); + expect(commitPosition.posWithOffset).toBeDefined(); + } + it(`should draw commit ${commit.id} bullet`, () => { + const gBullets = svg.append('g').attr('class', 'commit-bullets'); + const typeClass = getCommitClassType(commit); + const branchIndex = branchPos.get(commit.branch)?.index ?? 0; + drawCommitBullet(gBullets, commit, commitPosition, typeClass, branchIndex, commit.type); + } + it(`should draw commit ${commit.id} label`, () => { + const gLabels = svg.append('g').attr('class', 'commit-labels'); + drawCommitLabel(gLabels, commit, commitPosition, 0, gitGraphConfig); + } + }); +*/ + describe('drawBranches', () => { + it('should drawBranches', () => { + expect(true).toBe(true); + }); + }); + + describe('drawArrows', () => { + it('should drawArrows', () => { + expect(true).toBe(true); + }); + }); + + it('add', () => { + commitPos.set('parent1', { x: 1, y: 1 }); + commitPos.set('parent2', { x: 2, y: 2 }); + commitPos.set('parent3', { x: 3, y: 3 }); + dir = 'LR'; + const parents = ['parent1', 'parent2', 'parent3']; + const closestParent = findClosestParent(parents); + + expect(closestParent).toBe('parent3'); + commitPos.clear(); + }); +}