0
# Timers and Animation
1
2
Timer functions and animation frame requests for time-based functionality and smooth animations in web applications. Provides Python interfaces to browser timing APIs.
3
4
## Capabilities
5
6
### Basic Timers
7
8
Execute functions after delays or at regular intervals.
9
10
```python { .api }
11
def set_timeout(func: Callable, interval: int, *args) -> int:
12
"""
13
Execute function after specified delay.
14
15
Args:
16
func: Function to execute
17
interval: Delay in milliseconds
18
*args: Arguments to pass to function
19
20
Returns:
21
Timer ID for cancellation
22
"""
23
24
def set_interval(func: Callable, interval: int, *args) -> int:
25
"""
26
Execute function repeatedly at specified interval.
27
28
Args:
29
func: Function to execute
30
interval: Interval in milliseconds
31
*args: Arguments to pass to function
32
33
Returns:
34
Timer ID for cancellation
35
"""
36
37
def clear_timeout(timer_id: int) -> None:
38
"""
39
Cancel scheduled timeout.
40
41
Args:
42
timer_id: Timer ID returned by set_timeout
43
"""
44
45
def clear_interval(timer_id: int) -> None:
46
"""
47
Cancel repeating interval.
48
49
Args:
50
timer_id: Timer ID returned by set_interval
51
"""
52
```
53
54
**Usage:**
55
```python
56
from browser.timer import set_timeout, set_interval, clear_timeout, clear_interval
57
58
def delayed_message():
59
print("This message appears after 2 seconds")
60
61
def periodic_update():
62
print("Updating every 5 seconds...")
63
64
# Schedule one-time execution
65
timeout_id = set_timeout(delayed_message, 2000)
66
67
# Schedule repeating execution
68
interval_id = set_interval(periodic_update, 5000)
69
70
# Cancel timers if needed
71
def cancel_timers():
72
clear_timeout(timeout_id)
73
clear_interval(interval_id)
74
print("All timers cancelled")
75
76
# Cancel after 30 seconds
77
set_timeout(cancel_timers, 30000)
78
```
79
80
### Animation Frames
81
82
Smooth animations synchronized with browser refresh rate.
83
84
```python { .api }
85
def request_animation_frame(func: Callable) -> int:
86
"""
87
Request function execution on next animation frame.
88
89
Args:
90
func: Animation function to execute
91
92
Returns:
93
Animation frame ID for cancellation
94
95
The callback function receives timestamp as parameter.
96
"""
97
98
def cancel_animation_frame(frame_id: int) -> None:
99
"""
100
Cancel pending animation frame request.
101
102
Args:
103
frame_id: Frame ID returned by request_animation_frame
104
"""
105
```
106
107
**Usage:**
108
```python
109
from browser.timer import request_animation_frame, cancel_animation_frame
110
from browser import document
111
from browser.html import DIV
112
113
# Create animated element
114
animated_div = DIV("Animated Content", style={
115
'position': 'absolute',
116
'left': '0px',
117
'top': '100px',
118
'width': '100px',
119
'height': '100px',
120
'background': 'blue',
121
'color': 'white',
122
'text-align': 'center'
123
})
124
125
document.body <= animated_div
126
127
# Animation state
128
animation_state = {
129
'x': 0,
130
'direction': 1,
131
'running': False,
132
'frame_id': None
133
}
134
135
def animate_element(timestamp):
136
"""Animation loop function."""
137
if not animation_state['running']:
138
return
139
140
# Update position
141
animation_state['x'] += animation_state['direction'] * 2
142
143
# Reverse direction at boundaries
144
if animation_state['x'] >= 500 or animation_state['x'] <= 0:
145
animation_state['direction'] *= -1
146
147
# Apply position
148
animated_div.style.left = f"{animation_state['x']}px"
149
150
# Continue animation
151
animation_state['frame_id'] = request_animation_frame(animate_element)
152
153
def start_animation():
154
"""Start the animation."""
155
if not animation_state['running']:
156
animation_state['running'] = True
157
animation_state['frame_id'] = request_animation_frame(animate_element)
158
159
def stop_animation():
160
"""Stop the animation."""
161
animation_state['running'] = False
162
if animation_state['frame_id']:
163
cancel_animation_frame(animation_state['frame_id'])
164
animation_state['frame_id'] = None
165
166
# Control buttons
167
from browser.html import BUTTON
168
from browser import bind
169
170
start_btn = BUTTON("Start Animation")
171
stop_btn = BUTTON("Stop Animation")
172
173
@bind(start_btn, 'click')
174
def handle_start(event):
175
start_animation()
176
177
@bind(stop_btn, 'click')
178
def handle_stop(event):
179
stop_animation()
180
181
document.body <= start_btn
182
document.body <= stop_btn
183
```
184
185
### Performance Timing
186
187
Monitor and optimize timing performance.
188
189
```python { .api }
190
def set_loop_timeout(seconds: int) -> None:
191
"""
192
Set maximum execution time for loops to prevent blocking.
193
194
Args:
195
seconds: Maximum execution time in seconds
196
"""
197
198
def get_timestamp() -> float:
199
"""
200
Get high-resolution timestamp.
201
202
Returns:
203
Timestamp in milliseconds with microsecond precision
204
"""
205
```
206
207
**Usage:**
208
```python
209
from browser.timer import set_loop_timeout, get_timestamp
210
211
# Set timeout for long-running operations
212
set_loop_timeout(5) # 5 second limit
213
214
def performance_test():
215
"""Measure function execution time."""
216
start_time = get_timestamp()
217
218
# Simulate work
219
total = 0
220
for i in range(1000000):
221
total += i
222
223
end_time = get_timestamp()
224
execution_time = end_time - start_time
225
226
print(f"Execution time: {execution_time:.2f}ms")
227
print(f"Total: {total}")
228
229
performance_test()
230
```
231
232
### Advanced Animation
233
234
Complex animations with easing and chaining.
235
236
```python { .api }
237
class Animator:
238
"""
239
Advanced animation controller.
240
"""
241
242
def __init__(self):
243
"""Initialize animator."""
244
245
def animate(self, element: Element, properties: dict, duration: int,
246
easing: str = 'linear') -> 'Animation':
247
"""
248
Animate element properties.
249
250
Args:
251
element: Target element
252
properties: Properties to animate with end values
253
duration: Animation duration in milliseconds
254
easing: Easing function name
255
256
Returns:
257
Animation object for control
258
"""
259
260
def chain(self, *animations) -> 'AnimationChain':
261
"""Chain multiple animations in sequence."""
262
263
def parallel(self, *animations) -> 'AnimationGroup':
264
"""Run multiple animations in parallel."""
265
266
class Animation:
267
"""Individual animation instance."""
268
269
def start(self) -> None:
270
"""Start animation."""
271
272
def pause(self) -> None:
273
"""Pause animation."""
274
275
def resume(self) -> None:
276
"""Resume paused animation."""
277
278
def stop(self) -> None:
279
"""Stop animation."""
280
281
def on_complete(self, callback: Callable) -> 'Animation':
282
"""Set completion callback."""
283
```
284
285
**Usage:**
286
```python
287
from browser.timer import Animator
288
from browser import document
289
from browser.html import DIV
290
291
# Create animator
292
animator = Animator()
293
294
# Create elements to animate
295
box1 = DIV("Box 1", style={
296
'position': 'absolute',
297
'width': '50px',
298
'height': '50px',
299
'background': 'red',
300
'left': '0px',
301
'top': '200px'
302
})
303
304
box2 = DIV("Box 2", style={
305
'position': 'absolute',
306
'width': '50px',
307
'height': '50px',
308
'background': 'blue',
309
'left': '0px',
310
'top': '260px'
311
})
312
313
document.body <= box1
314
document.body <= box2
315
316
# Create animations
317
move_right = animator.animate(box1, {
318
'left': '300px',
319
'background': 'green'
320
}, 2000, easing='ease-out')
321
322
move_up = animator.animate(box2, {
323
'top': '100px',
324
'width': '100px',
325
'height': '100px'
326
}, 1500, easing='ease-in-out')
327
328
# Chain animations
329
sequence = animator.chain(move_right, move_up)
330
331
# Parallel animations
332
parallel = animator.parallel(
333
animator.animate(box1, {'opacity': '0.5'}, 1000),
334
animator.animate(box2, {'opacity': '0.5'}, 1000)
335
)
336
337
# Start animations with callbacks
338
move_right.on_complete(lambda: print("Box 1 finished moving"))
339
sequence.start()
340
341
def complex_animation():
342
"""Complex multi-stage animation."""
343
344
# Stage 1: Move elements
345
stage1 = animator.parallel(
346
animator.animate(box1, {'left': '200px'}, 1000),
347
animator.animate(box2, {'left': '200px'}, 1000)
348
)
349
350
# Stage 2: Rotate and scale
351
stage2 = animator.parallel(
352
animator.animate(box1, {
353
'transform': 'rotate(180deg) scale(1.5)',
354
'background': 'purple'
355
}, 1500),
356
animator.animate(box2, {
357
'transform': 'rotate(-180deg) scale(0.8)',
358
'background': 'orange'
359
}, 1500)
360
)
361
362
# Stage 3: Return to original
363
stage3 = animator.parallel(
364
animator.animate(box1, {
365
'left': '0px',
366
'transform': 'rotate(0deg) scale(1)',
367
'background': 'red'
368
}, 2000),
369
animator.animate(box2, {
370
'left': '0px',
371
'transform': 'rotate(0deg) scale(1)',
372
'background': 'blue'
373
}, 2000)
374
)
375
376
# Chain all stages
377
full_sequence = animator.chain(stage1, stage2, stage3)
378
full_sequence.on_complete(lambda: print("Complex animation complete"))
379
full_sequence.start()
380
381
# Trigger complex animation
382
from browser.html import BUTTON
383
from browser import bind
384
385
complex_btn = BUTTON("Start Complex Animation")
386
387
@bind(complex_btn, 'click')
388
def handle_complex(event):
389
complex_animation()
390
391
document.body <= complex_btn
392
```
393
394
### Timer Utilities
395
396
Helper functions for common timing patterns.
397
398
```python { .api }
399
class Timer:
400
"""
401
Timer utility class with advanced features.
402
"""
403
404
def __init__(self):
405
"""Initialize timer."""
406
407
def debounce(self, func: Callable, delay: int) -> Callable:
408
"""
409
Create debounced function that delays execution.
410
411
Args:
412
func: Function to debounce
413
delay: Delay in milliseconds
414
415
Returns:
416
Debounced function
417
"""
418
419
def throttle(self, func: Callable, limit: int) -> Callable:
420
"""
421
Create throttled function that limits execution rate.
422
423
Args:
424
func: Function to throttle
425
limit: Minimum interval between calls in milliseconds
426
427
Returns:
428
Throttled function
429
"""
430
431
def countdown(self, seconds: int, callback: Callable,
432
tick_callback: Callable = None) -> int:
433
"""
434
Create countdown timer.
435
436
Args:
437
seconds: Countdown duration
438
callback: Function to call when complete
439
tick_callback: Function to call each second (receives remaining time)
440
441
Returns:
442
Timer ID for cancellation
443
"""
444
445
timer_utils = Timer()
446
```
447
448
**Usage:**
449
```python
450
from browser.timer import Timer
451
from browser import document, bind
452
from browser.html import INPUT, DIV
453
454
timer = Timer()
455
456
# Debounced search function
457
search_results = DIV()
458
document.body <= search_results
459
460
def perform_search(query):
461
"""Simulate search operation."""
462
print(f"Searching for: {query}")
463
search_results.text = f"Results for: {query}"
464
465
# Debounce search to avoid excessive API calls
466
debounced_search = timer.debounce(perform_search, 500) # 500ms delay
467
468
search_input = INPUT(placeholder="Type to search...")
469
470
@bind(search_input, 'input')
471
def handle_search_input(event):
472
query = event.target.value
473
if query.strip():
474
debounced_search(query)
475
476
document.body <= search_input
477
478
# Throttled scroll handler
479
def handle_scroll():
480
"""Handle scroll events."""
481
scroll_position = window.pageYOffset
482
print(f"Scroll position: {scroll_position}")
483
484
# Throttle scroll events to improve performance
485
throttled_scroll = timer.throttle(handle_scroll, 100) # Max 10 times per second
486
487
@bind(window, 'scroll')
488
def on_scroll(event):
489
throttled_scroll()
490
491
# Countdown timer
492
countdown_display = DIV()
493
document.body <= countdown_display
494
495
def start_countdown():
496
"""Start 10-second countdown."""
497
498
def on_tick(remaining):
499
countdown_display.text = f"Countdown: {remaining} seconds"
500
501
def on_complete():
502
countdown_display.text = "Countdown finished!"
503
print("Timer expired!")
504
505
timer.countdown(10, on_complete, on_tick)
506
507
from browser.html import BUTTON
508
509
countdown_btn = BUTTON("Start 10s Countdown")
510
511
@bind(countdown_btn, 'click')
512
def handle_countdown(event):
513
start_countdown()
514
515
document.body <= countdown_btn
516
```
517
518
### Animation Easing
519
520
Built-in easing functions for natural animations.
521
522
```python { .api }
523
# Available easing functions
524
EASING_FUNCTIONS = {
525
'linear': 'linear progression',
526
'ease': 'default ease',
527
'ease-in': 'slow start',
528
'ease-out': 'slow end',
529
'ease-in-out': 'slow start and end',
530
'cubic-bezier': 'custom cubic bezier curve'
531
}
532
533
def create_easing(p1: float, p2: float, p3: float, p4: float) -> str:
534
"""
535
Create custom cubic-bezier easing function.
536
537
Args:
538
p1, p2, p3, p4: Bezier curve control points
539
540
Returns:
541
CSS cubic-bezier string
542
"""
543
```
544
545
This comprehensive timing system enables sophisticated time-based functionality and smooth animations for creating engaging and responsive user interfaces in Brython applications.