Skip to content

Commit f6ce120

Browse files
committed
Extract arrow svg path computation into core utils
1 parent 3fef108 commit f6ce120

File tree

2 files changed

+110
-95
lines changed

2 files changed

+110
-95
lines changed

packages/gitgraph-core/src/utils.ts

+108-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Commit } from "./commit";
2-
import { Coordinate } from "./gitgraph";
2+
import { Coordinate, GitgraphCore, OrientationsEnum } from "./gitgraph";
33

44
/**
55
* Omit some keys from an original type.
@@ -127,3 +127,110 @@ export function toSvgPath(
127127
)
128128
.join(" ");
129129
}
130+
131+
/**
132+
* Return a string ready to use in `svg.path.d` to draw an arrow from params.
133+
*
134+
* @param graph Graph context
135+
* @param parent Parent commit of the target commit
136+
* @param commit Target commit
137+
*/
138+
export function arrowSvgPath(
139+
graph: GitgraphCore,
140+
parent: Commit,
141+
commit: Commit,
142+
): string {
143+
const commitRadius = commit.style.dot.size;
144+
const size = graph.template.arrow.size!;
145+
const h = commitRadius + graph.template.arrow.offset;
146+
147+
// Delta between left & right (radian)
148+
const delta = Math.PI / 7;
149+
150+
// Alpha angle between parent & commit (radian)
151+
const alpha = getAlpha(graph, parent, commit);
152+
153+
// Top
154+
const x1 = h * Math.cos(alpha);
155+
const y1 = h * Math.sin(alpha);
156+
157+
// Bottom right
158+
const x2 = (h + size) * Math.cos(alpha - delta);
159+
const y2 = (h + size) * Math.sin(alpha - delta);
160+
161+
// Bottom center
162+
const x3 = (h + size / 2) * Math.cos(alpha);
163+
const y3 = (h + size / 2) * Math.sin(alpha);
164+
165+
// Bottom left
166+
const x4 = (h + size) * Math.cos(alpha + delta);
167+
const y4 = (h + size) * Math.sin(alpha + delta);
168+
169+
return `M${x1},${y1} L${x2},${y2} Q${x3},${y3} ${x4},${y4} L${x4},${y4}`;
170+
}
171+
172+
function getAlpha(graph: GitgraphCore, parent: Commit, commit: Commit): number {
173+
const deltaX = parent.x - commit.x;
174+
const deltaY = parent.y - commit.y;
175+
const commitSpacing = graph.template.commit.spacing;
176+
177+
let alphaY;
178+
let alphaX;
179+
180+
// Angle always start from previous commit Y position:
181+
//
182+
// o
183+
// ↑ ↖ ︎
184+
// o | <-- path is straight until last commit Y position
185+
// ↑ o
186+
// | ↗︎
187+
// o
188+
//
189+
// So we need to default to commit spacing.
190+
// For horizontal orientation => same with commit X position.
191+
switch (graph.orientation) {
192+
case OrientationsEnum.Horizontal:
193+
alphaY = deltaY;
194+
alphaX = -commitSpacing;
195+
break;
196+
197+
case OrientationsEnum.HorizontalReverse:
198+
alphaY = deltaY;
199+
alphaX = commitSpacing;
200+
break;
201+
202+
case OrientationsEnum.VerticalReverse:
203+
alphaY = -commitSpacing;
204+
alphaX = deltaX;
205+
break;
206+
207+
default:
208+
alphaY = commitSpacing;
209+
alphaX = deltaX;
210+
break;
211+
}
212+
213+
if (graph.reverseArrow) {
214+
alphaY *= -1;
215+
alphaX *= -1;
216+
217+
// If arrow is reverse, the previous commit position is considered
218+
// the same on the straight part of the curved path.
219+
//
220+
// o
221+
// ↓ \
222+
// o ↓ <-- arrow is like previous commit was on same X position
223+
// | o
224+
// ↓ ↙︎
225+
// o
226+
//
227+
// For horizontal orientation => same with commit Y position.
228+
if (graph.isVertical) {
229+
if (Math.abs(deltaY) > commitSpacing) alphaX = 0;
230+
} else {
231+
if (Math.abs(deltaX) > commitSpacing) alphaY = 0;
232+
}
233+
}
234+
235+
return Math.atan2(alphaY, alphaX);
236+
}

packages/gitgraph-react/src/Gitgraph.tsx

+2-94
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import {
66
Branch,
77
Coordinate,
88
MergeStyle,
9-
OrientationsEnum,
109
} from "gitgraph-core/lib/index";
11-
import { toSvgPath } from "gitgraph-core/lib/utils";
10+
import { toSvgPath, arrowSvgPath } from "gitgraph-core/lib/utils";
1211

1312
export interface GitgraphProps {
1413
options?: GitgraphOptions;
@@ -144,17 +143,8 @@ export class Gitgraph extends React.Component<GitgraphProps, GitgraphState> {
144143
));
145144
}
146145

147-
// TODO: extract arrow logic into its own file
148146
private drawArrow(parent: Commit, commit: Commit) {
149147
const commitRadius = commit.style.dot.size;
150-
const size = this.gitgraph.template.arrow.size!;
151-
const h = commitRadius + this.gitgraph.template.arrow.offset;
152-
153-
// Delta between left & right (radian)
154-
const delta = Math.PI / 7;
155-
156-
// Alpha angle between parent & commit (radian)
157-
const alpha = getAlpha(this.gitgraph, parent, commit);
158148

159149
// Starting point, relative to commit
160150
const origin = {
@@ -166,26 +156,10 @@ export class Gitgraph extends React.Component<GitgraphProps, GitgraphState> {
166156
: commitRadius,
167157
};
168158

169-
// Top
170-
const x1 = h * Math.cos(alpha);
171-
const y1 = h * Math.sin(alpha);
172-
173-
// Bottom right
174-
const x2 = (h + size) * Math.cos(alpha - delta);
175-
const y2 = (h + size) * Math.sin(alpha - delta);
176-
177-
// Bottom center
178-
const x3 = (h + size / 2) * Math.cos(alpha);
179-
const y3 = (h + size / 2) * Math.sin(alpha);
180-
181-
// Bottom left
182-
const x4 = (h + size) * Math.cos(alpha + delta);
183-
const y4 = (h + size) * Math.sin(alpha + delta);
184-
185159
return (
186160
<g transform={`translate(${origin.x}, ${origin.y})`}>
187161
<path
188-
d={`M${x1},${y1} L${x2},${y2} Q${x3},${y3} ${x4},${y4} L${x4},${y4}`}
162+
d={arrowSvgPath(this.gitgraph, parent, commit)}
189163
fill={this.gitgraph.template.arrow.color!}
190164
/>
191165
</g>
@@ -227,71 +201,5 @@ export class Gitgraph extends React.Component<GitgraphProps, GitgraphState> {
227201
}
228202
}
229203

230-
function getAlpha(graph: GitgraphCore, parent: Commit, commit: Commit): number {
231-
const deltaX = parent.x - commit.x;
232-
const deltaY = parent.y - commit.y;
233-
const commitSpacing = graph.template.commit.spacing;
234-
235-
let alphaY;
236-
let alphaX;
237-
238-
// Angle always start from previous commit Y position:
239-
//
240-
// o
241-
// ↑ ↖ ︎
242-
// o | <-- path is straight until last commit Y position
243-
// ↑ o
244-
// | ↗︎
245-
// o
246-
//
247-
// So we need to default to commit spacing.
248-
// For horizontal orientation => same with commit X position.
249-
switch (graph.orientation) {
250-
case OrientationsEnum.Horizontal:
251-
alphaY = deltaY;
252-
alphaX = -commitSpacing;
253-
break;
254-
255-
case OrientationsEnum.HorizontalReverse:
256-
alphaY = deltaY;
257-
alphaX = commitSpacing;
258-
break;
259-
260-
case OrientationsEnum.VerticalReverse:
261-
alphaY = -commitSpacing;
262-
alphaX = deltaX;
263-
break;
264-
265-
default:
266-
alphaY = commitSpacing;
267-
alphaX = deltaX;
268-
break;
269-
}
270-
271-
if (graph.reverseArrow) {
272-
alphaY *= -1;
273-
alphaX *= -1;
274-
275-
// If arrow is reverse, the previous commit position is considered
276-
// the same on the straight part of the curved path.
277-
//
278-
// o
279-
// ↓ \
280-
// o ↓ <-- arrow is like previous commit was on same X position
281-
// | o
282-
// ↓ ↙︎
283-
// o
284-
//
285-
// For horizontal orientation => same with commit Y position.
286-
if (graph.isVertical) {
287-
if (Math.abs(deltaY) > commitSpacing) alphaX = 0;
288-
} else {
289-
if (Math.abs(deltaX) > commitSpacing) alphaY = 0;
290-
}
291-
}
292-
293-
return Math.atan2(alphaY, alphaX);
294-
}
295-
296204
export default Gitgraph;
297205
export * from "gitgraph-core/lib/index";

0 commit comments

Comments
 (0)