@@ -25,12 +25,12 @@ def __init__(self):
25
25
self .trimmed = False
26
26
self .prevRef = None
27
27
self .topref = None
28
- self .i = 0
29
28
self .numCommits = settings .commits
30
29
self .defaultNumCommits = settings .commits
31
30
self .selected_branches = []
32
31
self .stop = False
33
32
self .zone_title_offset = 2.6 if platform .system () == "Windows" else 2.6
33
+ self .arrow_map = []
34
34
35
35
self .logo = m .ImageMobject (settings .logo )
36
36
self .logo .width = 3
@@ -81,31 +81,50 @@ def get_commits(self, start="HEAD"):
81
81
self .get_commits (start = start )
82
82
83
83
def parse_commits (
84
- self , commit , prevCircle = None , shift = numpy .array ([0.0 , 0.0 , 0.0 ]), dots = False
84
+ self , commit , i , prevCircle = None , shift = numpy .array ([0.0 , 0.0 , 0.0 ])
85
85
):
86
- if self .stop :
87
- return
88
- if self . i < self .numCommits and commit in self .commits :
86
+ isNewCommit = commit . hexsha not in self .drawnCommits
87
+
88
+ if i < self .numCommits and commit in self .commits :
89
89
commitId , circle , arrow , hide_refs = self .draw_commit (
90
- commit , prevCircle , shift , dots
90
+ commit , i , prevCircle , shift
91
91
)
92
92
93
93
if commit != "dark" :
94
- if not hide_refs and not self .stop :
95
- self .draw_head (commit , commitId )
96
- self .draw_branch (commit )
97
- self .draw_tag (commit )
98
- self .draw_arrow (prevCircle , arrow )
99
- if self .stop :
100
- return
101
- if self .i == 0 and len (self .drawnRefs ) < 2 :
94
+ if not hide_refs and isNewCommit :
95
+ self .draw_head (commit , i , commitId )
96
+ self .draw_branch (commit , i )
97
+ self .draw_tag (commit , i )
98
+ if (
99
+ not isinstance (arrow , m .CurvedArrow )
100
+ and [arrow .start .tolist (), arrow .end .tolist ()] not in self .arrow_map
101
+ ):
102
+ self .draw_arrow (prevCircle , arrow )
103
+ self .arrow_map .append ([arrow .start .tolist (), arrow .end .tolist ()])
104
+ elif (
105
+ isinstance (arrow , m .CurvedArrow )
106
+ and [arrow .get_start ().tolist (), arrow .get_end ().tolist ()]
107
+ not in self .arrow_map
108
+ ):
109
+ self .draw_arrow (prevCircle , arrow )
110
+ self .arrow_map .append (
111
+ [arrow .get_start ().tolist (), arrow .get_end ().tolist ()]
112
+ )
113
+ if i == 0 and len (self .drawnRefs ) < 2 :
102
114
self .draw_dark_ref ()
103
115
104
- if self .i < len (self .commits ) - 1 :
105
- self .i += 1
106
- self .parse_commits (self .commits [self .i ], circle , dots = True )
107
- else :
108
- self .i = 0
116
+ if i < self .numCommits : # len(self.commits) - 1:
117
+ i += 1
118
+ commitParents = list (commit .parents )
119
+ if len (commitParents ) > 0 :
120
+ if settings .invert_branches :
121
+ commitParents .reverse ()
122
+
123
+ if settings .hide_merged_chains :
124
+ self .parse_commits (commitParents [0 ], i , circle )
125
+ else :
126
+ for p in range (len (commitParents )):
127
+ self .parse_commits (commitParents [p ], i , circle )
109
128
110
129
def show_intro (self ):
111
130
if settings .animate and settings .show_intro :
@@ -170,9 +189,7 @@ def get_centers(self):
170
189
centers .append (commit .get_center ())
171
190
return centers
172
191
173
- def draw_commit (
174
- self , commit , prevCircle , shift = numpy .array ([0.0 , 0.0 , 0.0 ]), dots = False
175
- ):
192
+ def draw_commit (self , commit , i , prevCircle , shift = numpy .array ([0.0 , 0.0 , 0.0 ])):
176
193
if commit == "dark" :
177
194
commitFill = m .WHITE if settings .light_mode else m .BLACK
178
195
elif len (commit .parents ) <= 1 :
@@ -193,29 +210,54 @@ def draw_commit(
193
210
prevCircle , m .RIGHT if settings .reverse else m .LEFT , buff = 1.5
194
211
)
195
212
196
- start = (
197
- prevCircle .get_center ()
198
- if prevCircle
199
- else (m .LEFT if settings .reverse else m .RIGHT )
200
- )
201
- end = circle .get_center ()
213
+ while any ((circle .get_center () == c ).all () for c in self .get_centers ()):
214
+ circle .next_to (circle , m .DOWN , buff = 3.5 )
215
+
216
+ isNewCommit = commit .hexsha not in self .drawnCommits
217
+
218
+ if isNewCommit :
219
+ start = (
220
+ prevCircle .get_center ()
221
+ if prevCircle
222
+ else (m .LEFT if settings .reverse else m .RIGHT )
223
+ )
224
+ end = circle .get_center ()
225
+ else :
226
+ circle .move_to (self .drawnCommits [commit .hexsha ].get_center ())
227
+ start = (
228
+ prevCircle .get_center ()
229
+ if prevCircle
230
+ else (m .LEFT if settings .reverse else m .RIGHT )
231
+ )
232
+ end = self .drawnCommits [commit .hexsha ].get_center ()
233
+
234
+ arrow = m .Arrow (start , end , color = self .fontColor )
202
235
203
236
if commit == "dark" :
204
237
arrow = m .Arrow (
205
238
start , end , color = m .WHITE if settings .light_mode else m .BLACK
206
239
)
207
- elif commit .hexsha in self .drawnCommits :
208
- end = self .drawnCommits [commit .hexsha ].get_center ()
209
- arrow = m .Arrow (start , end , color = self .fontColor )
210
- self .stop = True
211
- else :
212
- arrow = m .Arrow (start , end , color = self .fontColor )
213
240
214
241
length = numpy .linalg .norm (start - end ) - (1.5 if start [1 ] == end [1 ] else 3 )
215
242
arrow .set_length (length )
243
+ angle = arrow .get_angle ()
244
+ lineRect = (
245
+ m .Rectangle (height = 0.1 , width = length , color = "#123456" )
246
+ .move_to (arrow .get_center ())
247
+ .rotate (angle )
248
+ )
249
+
250
+ for commitCircle in self .drawnCommits .values ():
251
+ inter = m .Intersection (lineRect , commitCircle )
252
+ if inter .has_points ():
253
+ arrow = m .CurvedArrow (start , end , color = self .fontColor )
254
+ if start [1 ] == end [1 ]:
255
+ arrow .shift (m .UP * 1.25 )
256
+ if start [0 ] < end [0 ] and start [1 ] == end [1 ]:
257
+ arrow .flip (m .RIGHT ).shift (m .UP )
216
258
217
259
commitId , commitMessage , commit , hide_refs = self .build_commit_id_and_message (
218
- commit , dots
260
+ commit , i
219
261
)
220
262
commitId .next_to (circle , m .UP )
221
263
@@ -231,15 +273,15 @@ def draw_commit(
231
273
color = self .fontColor ,
232
274
).next_to (circle , m .DOWN )
233
275
234
- if settings .animate and commit != "dark" and not self . stop :
276
+ if settings .animate and commit != "dark" and isNewCommit :
235
277
self .play (
236
278
self .camera .frame .animate .move_to (circle .get_center ()),
237
279
m .Create (circle ),
238
280
m .AddTextLetterByLetter (commitId ),
239
281
m .AddTextLetterByLetter (message ),
240
282
run_time = 1 / settings .speed ,
241
283
)
242
- elif not self . stop :
284
+ elif isNewCommit :
243
285
self .add (circle , commitId , message )
244
286
else :
245
287
return commitId , circle , arrow , hide_refs
@@ -252,7 +294,17 @@ def draw_commit(
252
294
253
295
return commitId , circle , arrow , hide_refs
254
296
255
- def build_commit_id_and_message (self , commit , dots = False ):
297
+ def get_nonparent_branch_names (self ):
298
+ branches = [b for b in self .repo .heads if not b .name .startswith ("remotes/" )]
299
+ exclude = []
300
+ for b1 in branches :
301
+ for b2 in branches :
302
+ if b1 .name != b2 .name :
303
+ if self .repo .is_ancestor (b1 .commit , b2 .commit ):
304
+ exclude .append (b1 .name )
305
+ return [b for b in branches if b .name not in exclude ]
306
+
307
+ def build_commit_id_and_message (self , commit , i , dots = False ):
256
308
hide_refs = False
257
309
if commit == "dark" :
258
310
commitId = m .Text ("" , font = "Monospace" , font_size = 20 , color = self .fontColor )
@@ -276,7 +328,7 @@ def build_commit_id_and_message(self, commit, dots=False):
276
328
commitMessage = commit .message .split ("\n " )[0 ][:40 ].replace ("\n " , " " )
277
329
return commitId , commitMessage , commit , hide_refs
278
330
279
- def draw_head (self , commit , commitId ):
331
+ def draw_head (self , commit , i , commitId ):
280
332
if commit .hexsha == self .repo .head .commit .hexsha :
281
333
headbox = m .Rectangle (color = m .BLUE , fill_color = m .BLUE , fill_opacity = 0.25 )
282
334
headbox .width = 1
@@ -297,10 +349,10 @@ def draw_head(self, commit, commitId):
297
349
self .drawnRefs ["HEAD" ] = head
298
350
self .prevRef = head
299
351
300
- if self . i == 0 :
352
+ if i == 0 :
301
353
self .topref = self .prevRef
302
354
303
- def draw_branch (self , commit ):
355
+ def draw_branch (self , commit , i ):
304
356
x = 0
305
357
306
358
remote_tracking_branches = self .get_remote_tracking_branches ()
@@ -348,17 +400,17 @@ def draw_branch(self, commit):
348
400
self .toFadeOut .add (branchRec , branchText )
349
401
self .drawnRefs [branch ] = fullbranch
350
402
351
- if self . i == 0 :
403
+ if i == 0 :
352
404
self .topref = self .prevRef
353
405
354
406
x += 1
355
407
if x >= settings .max_branches_per_commit :
356
408
return
357
409
358
- def draw_tag (self , commit ):
410
+ def draw_tag (self , commit , i ):
359
411
x = 0
360
412
361
- if settings .hide_first_tag and self . i == 0 :
413
+ if settings .hide_first_tag and i == 0 :
362
414
return
363
415
364
416
for tag in self .repo .tags :
@@ -394,7 +446,7 @@ def draw_tag(self, commit):
394
446
395
447
self .toFadeOut .add (tagRec , tagText )
396
448
397
- if self . i == 0 :
449
+ if i == 0 :
398
450
self .topref = self .prevRef
399
451
400
452
x += 1
@@ -878,7 +930,7 @@ def get_nondark_commits(self):
878
930
nondark_commits .append (commit )
879
931
return nondark_commits
880
932
881
- def draw_ref (self , commit , top , text = "HEAD" , color = m .BLUE ):
933
+ def draw_ref (self , commit , i , top , text = "HEAD" , color = m .BLUE ):
882
934
refText = m .Text (text , font = "Monospace" , font_size = 20 , color = self .fontColor )
883
935
refbox = m .Rectangle (
884
936
color = color ,
@@ -901,7 +953,7 @@ def draw_ref(self, commit, top, text="HEAD", color=m.BLUE):
901
953
self .drawnRefs [text ] = ref
902
954
self .prevRef = ref
903
955
904
- if self . i == 0 :
956
+ if i == 0 :
905
957
self .topref = self .prevRef
906
958
907
959
def draw_dark_ref (self ):
0 commit comments