···
from collections import defaultdict
5
+
from numbers import Number
from .. import elements, types
from . import playback_control_ui, playback_control_js
···
repeat_count: Union[int, str] = 'indefinite'
19
+
freeze_frame_at: Optional[float] = None
show_playback_progress: bool = False
···
self, controls_width=width, controls_x=x, controls_center_y=y,
98
+
def override_args(self, args, lcontext):
99
+
if (self.freeze_frame_at is not None
100
+
and hasattr(lcontext.element, 'animation_data')):
102
+
data = lcontext.element.animation_data
103
+
args.update(data.interpolate_at_time(self.freeze_frame_at))
class AnimatedAttributeTimeline:
···
raise ValueError('out-of-order key frame times')
self.values.extend(values)
133
+
def interpolate_at_time(self, at_time):
134
+
return linear_interpolate_value(self.times, self.values, at_time)
def as_animate_element(self, config: Optional[SyncedAnimationConfig]=None):
···
self.attr_timelines[attr] = timeline
timeline.extend(times, values)
196
+
def interpolate_at_time(self, at_time):
198
+
name: timeline.interpolate_at_time(at_time)
199
+
for name, timeline in self.attr_timelines.items()
def _timelines_adjusted_for_context(self, lcontext=None):
all_timelines = dict(self.attr_timelines)
if lcontext is not None and lcontext.context.invert_y:
···
yvalues = [lcontext.element.args.get('y', 0)]
if y_timeline is not None or height_timeline is not None:
ytimes, yvalues = _merge_timeline_inverted_y_values(
215
-
ytimes, yvalues, htimes, hvalues)
236
+
ytimes, yvalues, htimes, hvalues,
237
+
linear_interpolate_value, linear_interpolate_value)
y_timeline = AnimatedAttributeTimeline(
'y', y_attrs, ytimes, yvalues)
···
def children_with_context(self, lcontext=None):
245
+
if (lcontext is not None
246
+
and lcontext.context.animation_config is not None
247
+
and lcontext.context.animation_config.freeze_frame_at
249
+
return [] # Don't animate if frame is frozen
all_timelines = self._timelines_adjusted_for_context(lcontext)
timeline.as_animate_element(lcontext.context.animation_config)
···
230
-
def _merge_timeline_inverted_y_values(ytimes, yvalues, htimes, hvalues):
257
+
def linear_interpolate_value(times, values, at_time):
258
+
print(times, values, at_time)
259
+
if len(times) == 0:
261
+
idx = sum(t <= at_time for t in times)
262
+
if idx >= len(times):
266
+
elif at_time == times[idx-1]:
267
+
return values[idx-1]
268
+
elif isinstance(values[idx], Number) and isinstance(values[idx-1], Number):
269
+
fraction = (at_time-times[idx-1]) / (times[idx]-times[idx-1])
270
+
return values[idx-1] * (1-fraction) + (values[idx] * fraction)
272
+
return values[idx-1]
274
+
def _merge_timeline_inverted_y_values(ytimes, yvalues, htimes, hvalues,
275
+
yinterpolate, hinterpolate):
return htimes, [-yvalues[0]-h for h in hvalues]
···
return ytimes, [-y-h for y, h in zip(yvalues, hvalues)]
246
-
def interpolate(times, values, at_time):
247
-
if len(times) == 0:
249
-
idx = sum(t <= at_time for t in times)
250
-
if idx >= len(times):
254
-
elif at_time == times[idx-1]:
255
-
return values[idx-1]
257
-
fraction = (at_time-times[idx-1]) / (times[idx]-times[idx-1])
258
-
return values[idx-1] * (1-fraction)+ (values[idx] * fraction)
# Offset y-value by height if invert_y
# Merge key_times for y and height animations
···
yt = ytimes[0] if len(ytimes) else inf
while ht < inf and yt < inf:
270
-
h_val = interpolate(htimes, hvalues, yt)
302
+
h_val = hinterpolate(htimes, hvalues, yt)
new_values.append(-yvalues[yi] - h_val)
275
-
y_val = interpolate(ytimes, yvalues, ht)
307
+
y_val = yinterpolate(ytimes, yvalues, ht)
new_values.append(-y_val - hvalues[hi])