def adjust_lines(self): tabledict = self.tabledict cell_height = self.cell_height cell_length = self.cell_length vertlines = self.submobjects[-(len(tabledict) - 1):] lowestmobject = min(self.submobjects[0:len(self.submobjects) - (len(tabledict))], key=lambda m: m.get_y()) rightestmobject = max(self.submobjects[:len(tabledict)], key=lambda m: m.get_x()) anims = [] for line in vertlines: curr_start, curr_end = line.get_start_and_end() if line.get_angle( ) * DEGREES == 0: #This only happens when a field has been added, but a vertical separator doesnt exist for it. new_end = np.array(curr_end + (rightestmobject.get_x() - curr_end[0] + cell_length / 4, 0, 0)) newsep = Line( #This is the vertical separator for the new field. start=(rightestmobject.get_center() - (cell_length / 4, -cell_height / 4, 0)), end=(rightestmobject.get_center() - (cell_length / 4, +rightestmobject.get_y() - lowestmobject.get_y() + cell_height / 4, 0)), color=self.line_color) anims.append(ShowCreation(newsep)) self.add(newsep) else: new_end = np.array((curr_end) + (0, lowestmobject.get_y() - curr_end[1] - cell_height / 4, 0)) new_line = Line(curr_start, new_end, color=self.line_color) anims.append(Transform( line, new_line)) #Set the new bottom to the required position return AnimationGroup(*anims)
def test_succession_in_succession_timing(): """Test timing of nested successions.""" line = Line() animation_1s = FadeIn(line, shift=UP, run_time=1.0) animation_4s = FadeOut(line, shift=DOWN, run_time=4.0) nested_succession = Succession(animation_1s, animation_4s) succession = Succession( FadeIn(line, shift=UP, run_time=4.0), nested_succession, FadeIn(line, shift=UP, run_time=1.0), ) assert nested_succession.get_run_time() == 5.0 assert succession.get_run_time() == 10.0 succession._setup_scene(Mock()) succession.begin() succession.interpolate(0.1) assert succession.active_index == 0 # The nested succession must not be active yet, and as a result hasn't set active_animation yet. assert not hasattr(nested_succession, "active_animation") succession.interpolate(0.39) assert succession.active_index == 0 assert not hasattr(nested_succession, "active_animation") # The nested succession starts at 40% of total run time succession.interpolate(0.4) assert succession.active_index == 1 assert nested_succession.active_index == 0 # The nested succession second animation starts at 50% of total run time. succession.interpolate(0.49) assert succession.active_index == 1 assert nested_succession.active_index == 0 succession.interpolate(0.5) assert succession.active_index == 1 assert nested_succession.active_index == 1 # The last animation starts at 90% of total run time. The nested succession must be finished at that time. succession.interpolate(0.89) assert succession.active_index == 1 assert nested_succession.active_index == 1 succession.interpolate(0.9) assert succession.active_index == 2 assert nested_succession.active_index == 2 assert nested_succession.active_animation is None # After 100%, nothing must be playing anymore. succession.interpolate(1.0) assert succession.active_index == 3 assert succession.active_animation is None assert nested_succession.active_index == 2 assert nested_succession.active_animation is None
def test_succession_timing(): """Test timing of animations in a succession.""" line = Line() animation_1s = FadeIn(line, shift=UP, run_time=1.0) animation_4s = FadeOut(line, shift=DOWN, run_time=4.0) succession = Succession(animation_1s, animation_4s) assert succession.get_run_time() == 5.0 succession.begin() assert succession.active_index == 0 # The first animation takes 20% of the total run time. succession.interpolate(0.199) assert succession.active_index == 0 succession.interpolate(0.2) assert succession.active_index == 1 succession.interpolate(0.8) assert succession.active_index == 1 # At 100% and more, no animation must be active anymore. succession.interpolate(1.0) assert succession.active_index == 2 assert succession.active_animation is None succession.interpolate(1.2) assert succession.active_index == 2 assert succession.active_animation is None
def __init__(self): super().__init__() self.left_dot = Dot().shift((-1, 0, 0)) self.right_dot = Dot().shift((1, 0, 0)) self.line = Line(self.left_dot, self.right_dot) self.add(self.left_dot, self.right_dot, self.line)
def make_table(self): self.unchanged = True #unchanged becomes False when some record or field has been added. #Get values from CONFIG tabledict = self.tabledict buff_length = self.buff_length hbuff_length = self.hbuff_length vbuff_length = self.vbuff_length line_color = self.line_color raw_string_color = self.raw_string_color #self is now the table. so self.add has replaced table.add in this function. fields = list(tabledict.keys( )) #Since the data is recieved as a dict, the keys will be the fields #the for loop below checks that every field and record is of a valid type and converts to TextMobject if need be: for fieldnum in range(len(fields)): if isinstance(fields[fieldnum], (TextMobject, TexMobject, Text, DecimalNumber, Integer)) == False: tabledict[TextMobject( fields[fieldnum], fill_color=raw_string_color)] = tabledict.pop( fields[fieldnum]) fields = list(tabledict.keys()) for recordnum in range(0, len(tabledict[fields[fieldnum]])): if isinstance(tabledict[fields[fieldnum]][recordnum], (TexMobject, TextMobject, Text, DecimalNumber, Integer)) == False: tabledict[fields[fieldnum]][recordnum] = TextMobject( tabledict[fields[fieldnum]][recordnum], fill_color=raw_string_color) else: continue cell_length = (max( fields + Tools.flatten(tabledict.values()), key=lambda mobject: mobject.get_width())).get_width( ) + 2 * hbuff_length #The length/height of a record/field of cell_height = (max( fields + Tools.flatten(tabledict.values()), key=lambda mobject: mobject.get_height())).get_height( ) + 2 * vbuff_length #max length/height is the base cell size self.cell_height = cell_height self.cell_length = cell_length #The first position is set like so. field_position = [ (cell_length - TexMobject(fields[0]).get_width()) / 2 + TexMobject(fields[0]).get_width() / 2, 0, 0 ] #The initial position of the first field. #NOTE: Coordinates of TexMobjects in Manim are taken from centre, not top-right. Adjustments have been made by adding half the width of the object in all calculations. total_table_width = ( cell_length * len(fields) ) #The remaining width and height will be successively added total_table_height = cell_height * ( len(max(tabledict.values(), key=len)) + 1 ) #while drawing the Mobjects to the screen. +1 is added to account for headings. for n in range(0, len(fields)): field = fields[n] field_length = field.get_width( ) #This is the length that the actual field name will take up on-screen if n + 1 < len( fields ): #This gets the nxt field if it exists and chooses an empty TexMobject if it doesn't next_field = (fields[n + 1]) else: next_field = TexMobject("") next_field_length = next_field.get_width( ) #Gets the next fields length field.move_to(field_position) space_to_right_of_field = (cell_length - field_length) / 2 space_to_left_of_next_field = (cell_length - next_field_length) / 2 space_to_leave = space_to_right_of_field + space_to_left_of_next_field + next_field_length / 2 #next_field_length/2 is added to account for the fact that coordinates are taken from centre and not left edges. self.add(field) field_position = field.get_right() + (space_to_leave, 0, 0) for keynum in range(len(tabledict.keys())): key = list(tabledict.keys())[keynum] #gets the actual key recordlist = tabledict[key] #selects the list with the records for if recordlist != []: record_position = [ self[keynum].get_center()[0], -((cell_height - fields[keynum].get_height()) / 2 + fields[keynum].get_height() / 2 + cell_height), 0 ] #the record position is set to be the [center of the field it belongs to, buffer space above the record + centered height of the record, 0 ] for recordnum in range(len(recordlist)): # for each record for record = recordlist[recordnum] # the selected field if recordnum + 1 < len( recordlist ): #This gets the nxt record if it exists and chooses an empty TexMobject if it doesn't next_record = recordlist[recordnum + 1] else: next_record = TexMobject("") record.move_to(record_position) record_position = record.get_center() + (0, -cell_height, 0) self.add(record) else: pass line_hor = Line(start=(0, -2 * cell_height / 3, 0), end=(total_table_width, -2 * cell_height / 3, 0), color=line_color) self.add(line_hor) #This is the horizontal separator for l in range(len(fields) - 1): #These create the vertical separators. line = Line(start=(self[l].get_center() + (cell_length / 2, cell_height / 2, 0)), end=(self[l].get_center() + (cell_length / 2, -total_table_height, 0)), color=line_color) self.add(line)