This repository has been archived by the owner on Jun 7, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 33
/
Overview.src.html
7429 lines (5968 loc) 路 296 KB
/
Overview.src.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!-- @if LEVEL=1 -->
<h1>Web Animations</h1>
<!-- @endif -->
<!-- @if LEVEL=2 -->
<h1>Web Animations Level 2</h1>
<!-- @endif -->
<pre class='metadata'>
<!-- @if LEVEL=1 -->
Status: ED
<!-- @endif -->
<!-- @if LEVEL=2 -->
Status: UD
Warning: not ready
<!-- @endif -->
Shortname: web-animations
TR: http://www.w3.org/TR/web-animations/
<!-- @if LEVEL=1 -->
ED: https://w3c.github.io/web-animations/
Previous version: http://www.w3.org/TR/2014/WD-web-animations-20140605/
Previous version: http://www.w3.org/TR/2013/WD-web-animations-20130625/
<!-- @endif -->
<!-- @if LEVEL=2 -->
ED: https://w3c.github.io/web-animations/level-2/
<!-- @endif -->
Version history: https://github.com/w3c/web-animations/commits/master
Level: <!-- @echo LEVEL -->
Group: fxtf
Issue Tracking: GitHub https://github.com/w3c/web-animations/issues
Editor: Brian Birtles, Mozilla Japan, bbirtles@mozilla.com
Editor: Shane Stephens, Google Inc, shans@google.com
Editor: Alex Danilo, Google Inc, adanilo@google.com
Editor: Tab Atkins, Google Inc, jackalmage@gmail.com
Abstract: This specification defines a model for synchronization and
timing of changes to the presentation of a Web page.
This specification also defines an application programming interface
for interacting with this model and it is expected that further
specifications will define declarative means for exposing these
features.
Ignored Terms: double, boolean, DOMString, unsigned long, unrestricted double, (animationeffectreadonly or effectcallback), (unrestricted double or DOMString)
Link Defaults: dom-core-ls (interface) event, dom-core-ls (interface) document, cssom-1 (interface) pseudoelement
</pre>
<pre class="anchors">
urlPrefix: http://www.w3.org/TR/hr-time/; type: interface; text: DOMHighResTimeStamp
</pre>
<link href='https://drafts.fxtf.org/default.css' rel='stylesheet' test='text/css'>
<link href='web-animations.css' rel='stylesheet' type='text/css'>
<script src='MathJax/MathJax.js?config=MML_SVGorMML,local/local' type='text/javascript'></script>
<h2 id="introduction">Introduction</h2>
<div class='informative-bg'><em>This section is non-normative</em>
Web Animations defines a model for supporting animation and
synchronization on the Web platform.
It is intended that other specifications will build on this model and
expose its features through declarative means.
In addition, this specification also defines a programming interface to
the model that may be implemented by user agents that provide support
for scripting.
<h3 id="use-cases">Use cases</h3>
The Web Animations model is intended to provide the features necessary
for expressing CSS Transitions [[CSS3-TRANSITIONS]],
CSS Animations [[CSS3-ANIMATIONS]], and
SVG [[SVG11]].
As such, the use cases of Web Animations model is the union of use cases for
those three specifications.
The use cases for the programming interface include the following:
: Inspecting running animations
:: Often Web applications must wait for certain animated effects to complete
before updating some state.
The programming interface in this specification allows such applications
to wait for all currently running animation to complete,
regardless of whether they are defined by CSS Transitions, CSS Animations,
SVG animations, or created directly using the programming interface.
<pre class='example lang-javascript'>
// Wait until all animations have finished before removing the element
Promise.all(
elem.getAnimations().map(animation => animation.finished)
).then(() => elem.remove());
</pre>
Alternatively, applications may wish to query the playback state of
animations without waiting.
<pre class='example lang-javascript'>
var isAnimating = elem.getAnimations().some(
animation => animation.playState == 'running'
);
</pre>
: Controlling running animations
:: It is sometimes useful to perform playback control on animations
so that they can respond to external inputs.
For example, it may be necessary to pause all existing animations before
displaying a modal dialog so that they do not distract the user's
attention.
<pre class='example lang-javascript'>
// Pause all existing animations in the document
document.timeline.getAnimations().forEach(
animation => animation.pause()
);
</pre>
: Creating animations from script
:: While it is possible to use ECMAScript to perform animation using
<code>requestAnimationFrame</code> [[ANIMATION-TIMING]],
such animations behave differently to declarative animation in terms of
how they are represented in the CSS cascade and the performance
optimizations that are possible such as performing the animation on a
separate thread.
Using the Web Animations programming interface, it is possible to
create animations from script that have the same behavior and performance
characteristics as declarative animations.
<pre class='example lang-javascript'>
// Fade out quickly
elem.animate({ transform: 'scale(0)', opacity: 0 }, 300);
</pre>
: Animation debugging
:: In a complex application, it may be difficult to determine how an
element arrived in its present state.
The Web Animations programming interface may be used to inspect
running animations to answer questions such as,
“Why is the opacity of this element changing?”
<pre class='example lang-javascript'>
// Print the name of any opacity animations on elem
elem.getAnimations().filter(
animation =>
animation.effect instanceof KeyframeEffect &&
animation.effect.getFrames().some(
frame => frame.hasOwnProperty('opacity')
)
).forEach(animation => console.log(animation.effect.name));
</pre>
Likewise, in order to fine tune animations, it is often necessary to
reduce their playback rate and replay them.
<pre class='example lang-javascript'>
// Slow down and replay any transform animations
elem.getAnimations().filter(
animation =>
animation.effect instanceof KeyframeEffect &&
animation.effect.getFrames().some(
frame => frame.hasOwnProperty('transform')
)
).forEach(animation => {
animation.currentTime = 0;
animation.playbackRate = 0.5;
});
</pre>
: Testing animations
:: In order to test applications that make use of animations it is often
impractical to wait for such animations to run to completion.
Rather, it is desirable to seek the animations to specific times.
<pre class='example lang-javascript'>
// Seek to the half-way point of an animation and check that the opacity is 50%
elem.getAnimations().forEach(
animation =>
animation.currentTime =
animation.effect.computedTiming.delay +
animation.effect.computedTiming.activeDuration / 2;
);
assert_equals(getComputedStyle(elem).opacity, 0.5);
// Check that the loading screen is hidden after the animations finish
elem.getAnimations().forEach(
animation => animation.finish()
);
// Wait one frame so that event handlers have a chance to run
requestAnimationFrame(() => {
assert_equals(
getComputedStyle(document.querySelector('#loading')).display, 'none');
});
</pre>
<!-- @if LEVEL=2 -->
<h3 id="changes-since-level-1">Changes since level 1</h3>
This specification introduces the following changes compared to the
previous level of this specification:
* <a>group effects</a> and <a>sequence effects</a>,
* an <a>animation effect</a>-specific
<a lt="animation effect playback rate">playback rate</a>,
* <a>custom effects</a>.
<!-- @endif -->
<h3 id="relationship-to-other-specifications">Relationship to other specifications</h3>
CSS Transitions [[CSS3-TRANSITIONS]], CSS Animations [[CSS3-ANIMATIONS]], and
SVG [[SVG11]] all provide mechanisms that
generate animated content on a Web page.
Although the three specifications provide many similar features,
they are described in different terms.
This specification proposes an abstract animation model that
encompasses the common features of all three specifications.
This model is backwards-compatible with the current behavior of these
specifications such that they can be defined in terms of this model
without any observable change.
The animation features in SVG 1.1 are defined in terms of SMIL
Animation [[SMIL-ANIMATION]].
It is intended that by defining SVG's animation features in terms of
the Web Animations model, the dependency between SVG and SMIL
Animation can be removed.
As with Timing control for script-based animations (commonly referred
to as “requestAnimationFrame”) [[ANIMATION-TIMING]],
the programming interface component of this specification allows
animations to be created from script.
The animations created using the interface defined in this
specification, however, once created, are executed entirely by the
user agent meaning they share the same performance characteristics as
animations defined by markup.
Using this interface it is possible to create animations
from script in a simpler and more performant manner.
The time values used within the programming interface
correspond with those used in Timing control for script-based
animations [[ANIMATION-TIMING]] and their execution order is defined
such that the two interfaces can be used simultaneously without conflict.
The programming interface component of this specification makes
some additions to interfaces defined in HTML5 [[HTML5]].
<h3 id="overview-of this-specification">Overview of this specification</h3>
This specification begins by defining an abstract model for animation.
This is followed by a programming interface defined in terms of the
abstract model.
The programming interface is defined in terms of the abstract model
and is only relevant to user agents that provide scripting support.
</div>
<h2 id="web-animations-model-overview">Web Animations model overview</h2>
<div class='informative-bg'><em>This section is non-normative</em>
At a glance, the Web Animations model consists of two largely
independent pieces, a <em>timing model</em> and an <em>animation
model</em>. The role of these pieces is as follows:
: Timing model
:: Takes a moment in time and converts it to a proportional distance
within a single iteration of an animation called the <em>time
fraction</em>.
The <em>iteration index</em> is also recorded since some animations vary
each time they repeat.
: Animation model
:: Takes the <em>time fractions</em> and <em>iteration indices</em>
produced by the timing model and converts them into a series of values
to apply to the target properties and attributes.
Graphically, this flow can be represented as follows:
<div class="figure">
<img src="img/timing-and-animation-models.svg" width="600" alt="Overview of the operation of the Web Animations model.">
</div>
<p class="caption">
Overview of the operation of the Web Animations model.<br>
The current time is input to the timing model which produces a time
fraction and an iteration index.<br>
These parameters are used as input to the animation model which produces
the values to apply.<br>
</p>
For example, consider an animation that:
* starts after 3 seconds
* runs twice,
* takes 2 seconds every time, and
* changes the width of a rectangle from 50 pixels to 100 pixels.
The first three points apply to the timing model.
At a time of 6 seconds, it will calculate that the animation should be
half-way through its second iteration and produces the result 0.5.
The animation model then uses that information to calculate a width.
This specification begins with the timing model and then proceeds to
the animation model.
</div>
<h2 id="timing-model">Timing model</h2>
This section describes and defines the behavior of the Web Animations
timing model.
<h3 id="the-timing-model-at-a-glance">The timing model at a glance</h3>
<div class='informative-bg'>
<em>This section is non-normative</em>
Two features characterise the Web Animations timing model: it is
<em>stateless</em> and it is <em>hierarchical</em>.
<h4 id="stateless">Stateless</h4>
The Web Animations timing model operates by taking an input time and
producing an output time fraction.
Since the output is based solely on the input time and is independent
of previous inputs, the model may be described as stateless.
This gives the model the following properties:
: Frame-rate independent
:: Since the output is independent of previous inputs, the rate at
which the model is sampled will not affect its progress.
Provided the input times are proportional to the progress of
real-world time, animations will progress at an identical rate
regardless of the capabilities of the device running them.
: Direction-agnostic
:: Since the sequence of inputs is insignificant, the model is
directionless.
This means that the model can be sampled in reverse or even in
a backwards and forwards pattern without requiring any specialized
handling.
: Constant-time seeking
:: Since each input is independent of the previous input, the
processing required to perform a seek operation, even far into the
future, is at least potentially constant.
There are a few exceptions to the stateless behavior of the timing
model.
Firstly, a number of methods defined in the <a
href="#programming-interface" section>programming interface</a> to the model
provide play control such as pausing an animation.
These methods are defined in terms of the time at which they are
called and are therefore stative.
These methods are provided primarily for convenience and are not part
of the core timing model but are layered on top.
Similarly, the <a href="#reaching-the-end" section>finishing behavior</a> of
animations means that dynamic changes to the end time of
the media (target effect) of an animation may produce a
different result depending on when the change occurs.
This behavior is somewhat unfortunate but has been deemed intuitive
and consistent with HTML.
As a result, the model can only truly be described as stateless
<em>in the absence of dynamic changes to its timing properties</em>.
Finally, each time the model is sampled, it can be considered to
establish a temporary state.
While this temporary state affects the values returned from the <a
href="#programming-interface" section>programming interface</a>, it has no
influence on the subsequent samples and hence does not conflict with
the stateless qualities described above.
<h4 id="hierarchical">Hierarchical</h4>
The other characteristic feature of the Web Animations timing model is
that time is inherited.
Time begins with a monotonically increasing time source and cascades
down a number of steps to each animation.
At each step, time may be shifted backwards and forwards, scaled,
reversed, paused, and repeated.
<div class="figure">
<!-- @ifndef INCLUDE_GROUPS -->
<img src="img/time-hierarchy-no-groups.svg" width="350"
alt="A hierarchy of timing nodes">
<!-- @endif -->
<!-- @ifdef INCLUDE_GROUPS -->
<img src="img/time-hierarchy.svg" width="600"
alt="A hierarchy of timing nodes">
<!-- @endif -->
</div>
<p class="caption">
A hierarchy of timing nodes.
Each node in the tree derives its time from its parent node.
At the root of the tree is the global clock.
</p>
<!-- @ifndef INCLUDE_GROUPS -->
In this level of the specification the hierarchy is shallow.
A subsequent level of this specification will introduce the concept
of group effects which allows for deeper timing hierarchies.
<!-- @endif -->
<!-- @ifdef INCLUDE_GROUPS -->
A consequence of this hierarchical arrangement is that complex
animation arrangements can be reversed, scheduled, accelerated and so
on as a whole unit since the manipulations applied to the parent,
cascade down to its <a>descendants</a>.
Furthermore, since time has a common source, it is easy to synchronize
animations.
<!-- @endif -->
</div>
<h3 id="timing-model-concepts">Timing model concepts</h3>
In Web Animations, timing is based on a hierarchy of time relationships
between timing nodes.
Parent nodes provide timing information to their child nodes in the form
of <a>time values</a>.
A <dfn>time value</dfn> is a real number which nominally represents
a number of milliseconds from some moment.
The connection between <a>time values</a> and wall-clock milliseconds
may be obscured by any number of transformations applied to the value as
it passes through the time hierarchy.
<p class="annotation">
In the future we may have timelines that are based on UI gestures in
which case the connection between time values and milliseconds will be
weakened even further.
</p>
A <a>time value</a> may also be <dfn>unresolved</dfn> if, for example,
a timing node is not in a state to produce a <a>time value</a>.
Periodically, the user agent will queue a task to update the timing
model in a process called <dfn>sampling</dfn>.
On each <dfn lt='single-sample'>sample</dfn> the
<a>time values</a> of each timing node are updated.
Note: A more precise definition of when the model is updated when scripting is
involved is provided in <a
href="#script-execution-and-live-updates-to-the-model"
section></a>.
<h3 id="the-global-clock">The global clock</h3>
At the root of the Web Animations timing hierarchy is the <a>global
clock</a>.
The <dfn>global clock</dfn> is a source of monotonically increasing
<a>time values</a> unaffected by adjustments to the system clock.
The <a>time values</a> produced by the <a>global clock</a> represent
wall-clock milliseconds from an unspecified historical moment.
Because the zero time of the <a>global clock</a> is not specified,
the absolute values of the <a>time values</a> produced by the <a>global
clock</a> are not significant, only their rate of change.
Note: The <a>global clock</a> is not exposed in the <a
href="#programming-interface">programming interface</a> and nor is it
expected to be exposed by markup.
As a result the moment from which <a>global clock</a> <a>time values</a>
are measured, that is, the zero time of the clock, is
implementation-dependent.
One user agent may measure the number of milliseconds since the the user
agent was loaded whilst another may use the time when the device was
started.
Both approaches are acceptable and produce no observable difference
in the output of the model.
<h3 id="timelines">Timelines</h3>
A <dfn>timeline</dfn> provides a source of <a>time values</a> for the
purpose of synchronization.
Typically, a <a>timeline</a> is tied to the <a>global clock</a> such
that its absolute time is calculated as a fixed offset from the time of
the <a>global clock</a>.
This offset is established by designating some moment as the timeline's
<dfn>zero time</dfn> and recording the <a>time value</a> of the
<a>global clock</a> at that moment.
At subsequent moments, the <a>time value</a> of the timeline is
calculated as the difference between the current <a>time value</a> of
the <a>global clock</a> and the value recorded at the <a>zero time</a>.
Note: We anticipate that other types of timelines may be introduced
in the future that are not tied to the global clock.
For example, a timeline whose time values are related to the progress of
a UI gesture.
Since a <a>timeline</a> may be defined relative to a moment that has yet
to occur, it may not always be able to return a meaningful <a>time
value</a>, but only an <a>unresolved</a> time value.
A <a>timeline</a> is considered to be
<dfn lt="inactive timeline">inactive</dfn>
when its <a>time value</a> is <a>unresolved</a>.
<h4 id="document-timelines">Document timelines</h4>
A <dfn>document timeline</dfn> is a <a>timeline</a> that is associated with
a document.
The <a>time values</a> of a <a>document timeline</a> are calculated
as a fixed offset from the <a>global clock</a> such that the <a>zero
time</a> corresponds to the <a
href="http://www.w3.org/TR/navigation-timing/#dom-performancetiming-navigationstart">
<code>navigationStart</code></a> moment [[!NAVIGATION-TIMING]] plus a
signed delta known as the <dfn>origin time</dfn>.
Prior to establishing the <code>navigationStart</code> moment, the <a>document
timeline</a> is <a lt="inactive timeline">inactive</a>.
A <a>document timeline</a> that is associated with a document which is not
an <a href="https://html.spec.whatwg.org/#active-document"
class="externalDFN">active document</a> is also considered to be
<a lt="inactive timeline">inactive</a>.
<h4 id="the-documents-default-timeline">The default document timeline</h4>
Each <a href="https://dom.spec.whatwg.org/#concept-document">document</a>
([[!DOM]]) has a <a>document timeline</a> called the <dfn>default document
timeline</dfn>.
The <a>default document timeline</a> is unique to each document and persists for
the lifetime of the document including calls to <a
href="https://html.spec.whatwg.org/multipage/webappapis.html#dom-document-open"><code>document.open()</code></a> [[!HTML5]].
The <a>default document timeline</a> has an <a>origin time</a> of zero.
<div class="informative-bg"><em>This section is non-normative</em>
Since the <a>document timelines</a> are tied to the <a>global
clock</a> by a fixed offset, <a>time values</a> reported by
<a>document timelines</a> increase monotonically.
Furthermore, since no scaling is applied, these <a>time values</a>
are proportional to wall-clock milliseconds.
Since the <a>time values</a> of the <a>default document timeline</a> are
relative to the <code>navigationStart</code> time,
<code>document.timeline.currentTime</code> will roughly correspond to
<a href="http://www.w3.org/TR/hr-time/#dom-performance-now">
<code>Performance.now()</code></a>
[[HR-TIME]] with the exception that
<code>document.timeline.currentTime</code> does not change within
a script execution block as defined in <a
href="#script-execution-and-live-updates-to-the-model" section></a>.
</div>
<h3 id="animations">Animations</h3>
<div class="informative-bg"><em>This section is non-normative</em>
The children of a <a>timeline</a> are called <em>animations</em>.
An animation takes an <a>animation effect</a> which is a static
description of some timed behavior and binds it to a <a>timeline</a>
so that it runs.
An animation also allows run-time control of the connection between the
<a>animation effect</a> and its <a>timeline</a> by providing pausing,
seeking, and speed control.
The relationship between an animation and an <a>animation effect</a> is
analogous to that of a DVD player and a DVD.
</div>
An <dfn id="concept-animation">animation</dfn> connects a single <a>animation
effect</a>, called its <dfn>target effect</dfn>, to a <a>timeline</a> and
provides playback control.
Both of these associations are optional and configurable such that
an <a>animation</a> may have no associated <a>target effect</a> or
<a>timeline</a> at a given moment.
An <a>animation</a>'s <dfn lt="animation start time">start time</dfn> is the
<a>time value</a> of its <a>timeline</a> when its <a>target effect</a>
is scheduled to begin playback. An animation's <a
lt="animation start time">start time</a> is initially
<a>unresolved</a>.
An <a>animation</a> also maintains a <dfn>hold time</dfn> <a>time value</a>
which is used to fix the animation's output <a>time value</a>, called its
<a>current time</a>, in circumstances such as pausing</a>.
The <a>hold time</a> is initially <a>unresolved</a>.
When an <a>animation</a> is created, it is assigned a globally unique
sequence number called the <dfn>animation sequence number</dfn>.
This number is used to resolve the sort order of animations for a variety
of situations such as combining effects and returning the list of
current animations.
Issue: Should this actually be based on when the animation is attached to
a timeline? Or when it leaves the idle state?
<h4 id="setting-the-timeline">Setting the timeline of a animation</h4>
The procedure to <dfn>set the timeline of an animation</dfn>,
<var>animation</var>, to <var>new timeline</var> which may be null, is as
follows:
1. Let <var>old timeline</var> be the current <a>timeline</a> of
<var>animation</var>, if any.
1. If <var>new timeline</var> is the same object as <var>old timeline</var>,
abort this procedure.
1. Let <var>previous animation time</var> be the <a>current time</a> of
<var>animation</var>.
1. If <var>new timeline</var> is null and <var>old timeline</var> is not null,
run the procedure to <a>reset an animation's pending tasks</a> on
<var>animation</var>.
<p class="note">
Note that if <var>new timeline</var> is not null and <var>animation</var>
has a <a>pending play task</a> or a <a>pending pause task</a> no special
handling is required: the pending task will run as soon as the
<a>animation</a> is <a>ready</a> even though this may occur at a different
moment than it might have done with the old timeline.
</p>
1. Let the <a>timeline</a> of <var>animation</var> be <var>new timeline</var>.
1. If <var>previous animation time</var> is <a lt=unresolved>resolved</a>,
run the procedure to <a>silently set the current time</a> of
<var>animation</var> to <var>previous animation time</a>.
<!-- @ifdef INCLUDE_CUSTOM_EFFECTS -->
1. Issue: If <var>new timeline</var> is null, we should ensure that <a>custom
effects</a> get called with an <a>unresolved</a> <a>time fraction</a>
(unless a subsequent change in the same script execution context makes this
redundant).
<!-- @endif -->
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to false.
The procedure to <dfn>reset an animation's pending tasks</dfn> for
<var>animation</var> is as follows:
1. If <var>animation</var> has a <a>pending play task</a>, cancel that task.
2. If <var>animation</var> has a <a>pending pause task</a>, cancel that task.
3. <a lt="reject a Promise">Reject</a> <var>animation</var>'s <a>current ready
promise</a> with a DOMException named "AbortError".
4. Let <var>animation</var>'s <a>current ready promise</a> be the result of
<a lt="create a new resolved Promise">creating a new resolved Promise
object</a>.
<h4 id="setting-the-target-effect">Setting the target effect of an
animation</h4>
The procedure to <dfn>set the target effect of an animation</dfn>,
<var>animation</var>, to <var>new effect</var> which may be null, is as
follows:
1. Let <var>old effect</var> be the current <a>target effect</a> of
<var>animation</var>, if any.
1. If <var>new effect</var> is the same object as <var>old effect</var>,
abort this procedure.
1. If <var>new effect</var> is null and <var>old effect</var> is not null,
run the procedure to <a>reset an animation's pending tasks</a> on
<var>animation</var>.
1. If <var>animation</var> has a <a>pending pause task</a>, reschedule that
task to run as soon as <var>animation</var> is <a>ready</a>.
1. If <var>animation</var> has a <a>pending play task</a>, reschedule that task
to run as soon as <var>animation</var> is <a>ready</a> to play <var>new
effect</var>.
<!-- @ifdef INCLUDE_GROUPS -->
1. If <var>new effect</var> is not <code>null</code> and
if <var>new effect</var> has a <a>parent group</a>,
<a lt="remove an animation effect">remove</a> <var>new effect</var> from
its <a>parent group</a>.
<!-- @endif -->
1. If <var>new effect</var> is not <code>null</code> and
if <var>new effect</var> is the <a>target effect</a> of another
<a>animation</a>, <var>previous animation</var>, run the procedure to <a>set
the target effect of an animation</a> (this procedure) on <var>previous
animation</var> passing null as <var>new effect</var>.
1. Let the <a>target effect</a> of <var>animation</var> be <var>new
effect</var>.
<!-- @ifdef INCLUDE_CUSTOM_EFFECTS -->
<!-- As elsewhere, we'd like to change this comment based on whether we
support groups or not but npm preprocess doesn't support nested ifdefs so we
just assume that if we support custom effects we support groups too. -->
1. If <var>old effect</var> is not <code>null</code>, queue a task to call any
<a>custom effects</a> associated with <a>inclusive descendants</a> of
<var>old effect</var>
with an <a>unresolved</a> <a>time fraction</a>.
<div class="issue">
This is not quite right. If <var>old effect</var> is attached to another
animation in the same task then we should probably not do an extra
callback with <a>unresolved</a>.
The definition of when <a>custom effects</a> gets called needs to be
audited and probably rewritten.
</div>
<!-- @endif -->
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to false.
<h4 id="the-current-time-of-an-animation">The current time of an animation</h4>
<a>Animations</a> provide a <a>time value</a> to their <a>target
effect</a> called the animation's <dfn>current time</dfn>.
The <a>current time</a> is calculated from the first
matching condition from below:
<div class="switch">
: If the animation's <a>hold time</a> is <a lt="unresolved">resolved</a>,
:: The <a>current time</a> is the animation's <a>hold time</a>.
: If <em>any</em> of the following are true:
1. the animation has no associated <a>timeline</a>, or
2. the associated <a>timeline</a> is
<a lt="inactive timeline">inactive</a>, or
3. the animation's <a lt="animation start time">start time</a> is
<a>unresolved</a>.
:: The <a>current time</a> is an <a>unresolved</a> time value.
: Otherwise,
::
<blockquote>
<code><a>current time</a> =
(<var>timeline time</var> - <a lt="animation start time">start time</a>)
× <a lt="animation playback rate">playback rate</a></code>
</blockquote>
Where <var>timeline time</var> is the current <a>time value</a> of
the associated <a>timeline</a>.
The <a lt="animation playback rate">playback rate</a> value is
defined in <a href="#speed-control" section></a>.
</div>
<h4 id="setting-the-current-time-of-an-animation">Setting the current time of an animation</h4>
The <a>current time</a> of an animation can be set to a new value to
<em>seek</em> the animation.
The procedure for setting the current time is split into two parts.
The procedure to <dfn>silently set the current time</dfn> of
an animation, <var>animation</var>, to <var>seek time</var> is as follows:
1. If <var>seek time</var> is an <a>unresolved</a> time value,
then perform the following steps.
1. If the <a>current time</a> is <a lt=unresolved>resolved</a>, then
<a href="http://heycam.github.io/webidl/#dfn-throw">throw</a> a
<span class=exceptionname>TypeError</span>.
1. Abort these steps.
2. Update either <var>animation</var>'s <a>hold time</a> or <a
lt="animation start time">start time</a> as follows:
<div class="switch">
: If <em>any</em> of the following conditions are true:
* <var>animation</var>'s <a>hold time</a> is
<a lt="unresolved">resolved</a>, or
* <var>animation</var> has no associated <a>timeline</a> or the
associated <a>timeline</a> is
<a lt="inactive timeline">inactive</a>, or
* <var>animation</var>'s
<a lt="animation playback rate">playback rate</a> is 0, or
* <var>animation</var> has a <a>pending pause task</a>
:: Set <var>animation</var>'s <a>hold time</a> to <var>seek time</var>.
: Otherwise,
:: Set <var>animation</var>'s <a lt="animation start time">start time</a>
to the result of evaluating
<code><var>timeline time</var> - (<var>seek time</var> / <a
lt="animation playback rate">playback rate</a>)</code>
where <var>timeline time</var> is the current <a>time value</a>
of <a>timeline</a> associated with <var>animation</var>.
</div>
1. If <var>animation</var> has no associated <a>timeline</a> or the associated
<a>timeline</a> is <a lt="inactive timeline">inactive</a>,
make <var>animation</var>'s <a lt="animation start time">start time</a>
<a>unresolved</a>.
<p class=annotation>
This preserves the invariant that when we don't have an active timeline it
is only possible to set <em>either</em> the <a>animation start time</a>
<em>or</em> the animation's <a>current time</a>.
</p>
4. Make <var>animation</var>'s <a>previous current time</a> <a>unresolved</a>.
The procedure to <dfn>set the current time</dfn> of an animation,
<var>animation</var>, to <var>seek time</var> is as follows:
1. Run the steps to <a>silently set the current time</a> of
<var>animation</var> to <var>seek time</var>.
2. If <var>animation</var> has a <a>pending pause task</a>, cancel the
task and <a lt="resolve a Promise">resolve</a> <var>animation</var>'s
<a>current ready promise</a> with <var>animation</var>.
3. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to true.
<h4 id='setting-the-start-time-of-an-animation'>Setting the start time of an animation</h4>
The procedure to <dfn>update the animation start time</dfn>
of <a>animation</a>, <var>animation</var>, to
<a lt="animation start time">start time</a>, <var>new start time</var>,
is as follows:
1. Let <var>timeline time</var> be the current <a>time value</a> of the
<a>timeline</a> that <var>animation</var> is associated with.
If there is no <a>timeline</a> associated with <var>animation</var> or the
associated timeline is <a lt="inactive timeline">inactive</a>,
let the <var>timeline time</var> be <a>unresolved</a>.
1. If <var>timeline time</var> is <a>unresolved</a> and <var>new start
time</var> is <a lt="unresolved">resolved</a>, make <var>animation</var>'s
<a>hold time</a> <a>unresolved</a>.
<p class=annotation>
This preserves the invariant that when we don't have an active timeline it
is only possible to set <em>either</em> the <a>animation start time</a>
<em>or</em> the animation's <a>current time</a>.
</p>
1. Let <var>previous current time</var> be <var>animation</var>'s <a>current
time</a>.
Note: This is the <a>current time</a> after applying the changes from the
previous step which may cause the <a>current time</a> to become
<a>unresolved</a>.
1. Set <var>animation</var>'s <a lt="animation start time">start time</a> to
<var>new start time</var>.
1. Update <var>animation</var>'s <a>hold time</a> based on the first matching
condition from the following,
<div class="switch">
: If <var>new start time</var> is <a lt="unresolved">resolved</a>,
:: If <var>animation</var>'s <a lt="animation playback rate">playback
rate</a> is not zero, make <var>animation</var>'s <a>hold time</a>
<a>unresolved</a>.
: Otherwise (<var>new start time</var> is <a>unresolved</a>),
:: Set <var>animation</var>'s <a>hold time</a> to <var>previous current
time</var> even if <var>previous current time</var> is
<a>unresolved</a>.
</div>
1. If <var>animation</var> has a <a>pending play task</a> or
a <a>pending pause task</a>, cancel that task and
<a lt="resolve a Promise">resolve</a> <var>animation</var>'s
<a>current ready promise</a> with <var>animation</var>.
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to false.
Issue: Is this right? If you shift an animation backwards in time so that it is
now finished, should the current time jump to the end of the target effect, or
be allowed to sit past the end of the target effect?
<h4 id='waiting-for-the-target-effect'>Waiting for the target effect</h4>
<div class='informative-bg'>
<em>This section is non-normative</em>
Some operations performed by an <a>animation</a> may not occur
instantaneously.
For example, some user agents may delegate the playback of an
animation to a separate process or to specialized graphics hardware
each of which may incur some setup overhead.
If such an animation is timed from the moment when the animation was
triggered there may be a significant jump between the first and second
frames of the animation corresponding to the setup time involved.
To avoid this problem, Web Animations typically begins timing
animations from the moment when the first frame of the animation is
complete.
This is represented by an <a>unresolved</a> <a
lt="animation start time">start time</a> on the <a>animation</a> which becomes
resolved when the animation is <a>ready</a>.
Content may opt out of this behavior by setting the <a
lt="animation start time">start time</a>
to a <a lt="unresolved">resolved</a> <a>time value</a>.
</div>
An animation is <dfn>ready</dfn> at the first moment where <em>both</em> of the
following conditions are true:
* the user agent has completed any setup required to begin the playback of
<!-- @ifdef INCLUDE_GROUPS -->
each <a>inclusive descendant</a> of
<!-- @endif -->
the animation's <a>target effect</a>
including rendering the first frame of any <a>keyframe
effect</a><!-- @ifdef INCLUDE_CUSTOM_EFFECTS -->
or executing any <a>custom effects</a> associated with an
<a>animation effect</a><!-- @endif -->.
* the animation is associated with a <a>timeline</a> that is not
<a lt="inactive timeline">inactive</a>.
<h4 id='promise-objects'>Promise objects</h4>
<dfn>Promise</dfn> objects are defined by [[!ECMA-262]], <a
href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects">section
25.4</a>.
To <dfn>resolve a Promise</dfn> with <var>value</var>,
call the \[[Call]] internal method of \[[Resolve]] on the <a
href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promisecapability-records">Promise
capability</a> record for the promise, passing <code>undefined</code> as
<var>thisArgument</var> and (<var>value</var>) as <var>argumentsList</var>.
To <dfn>reject a Promise</dfn> with <var>reason</var>,
call the \[[Call]] internal method of \[[Reject]] on the <a
href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promisecapability-records">Promise
capability</a> record for the promise, passing <code>undefined</code> as
<var>thisArgument</var> and (<var>reason</var>) as <var>argumentsList</var>.
To <dfn>create a new resolved Promise</dfn> with <var>value</var>, call <a
href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.resolve">Promise.resolve</a>,
passing <var>value</var> as <var>x</var>.
<h4 id='the-current-ready-promise'>The current ready promise</h4>
Each <a>animation</a> has a <dfn>current ready promise</dfn>.
The <a>current ready promise</a> is initially a resolved <a>Promise</a> created
using the procedure to <a>create a new resolved Promise</a>.
The object is replaced with a new <a>Promise</a> object every time the animation
enters the <a>pending play state</a> as well as when the animation is
cancelled (see <a href="#cancelling-an-animation-section" section></a>).
<div class="note">
Note that since the same object is used for both pending play and
pending pause requests, authors are advised to check the state of the
animation when the <a>Promise</a> is resolved.
For example, in the following code fragment, the state of the animation
will be <a lt="running play state">running</a> when the
<a>current ready promise</a> is resolved.
This is because the animation does not leave the <a>pending play state</a>
in between the calls to <code>pause</code> and
<code>play</code> and hence the <a>current ready promise</a> does
not change.
<pre class='example lang-javascript'>
animation.pause();
animation.ready.then(function() {
// Displays 'running'
alert(animation.playState);
});
animation.play();</pre>
</div>
<h4 id='playing-an-animation-section'>Playing an animation</h4>
The procedure to <dfn>play an animation</dfn>, <var>animation</var>, is as
follows:
1. Let <var>aborted pause</var> be a boolean flag that is true if
<var>animation</var> has a <a>pending pause task</a>, and false otherwise.
1. Let <var>has pending ready promise</var> be a boolean flag that is
initially false.
1. If <var>animation</var> has a <a>pending play task</a> or a
<a>pending pause task</a>,
1. Cancel that task.
1. Set <var>has pending ready promise</var> to true.
1. Perform the steps corresponding to the <em>first</em> matching
condition from the following, if any:
<div class="switch">
: If <a>animation playback rate</a> > 0 and <em>either</em>
<var>animation</var>'s:
* <a>current time</a> is <a>unresolved</a>, or
* <a>current time</a> < zero, or
* <a>current time</a> ≥ <a>target effect end</a>,
:: Set <var>animation</var>'s <a>hold time</a> to zero.
: If <a>animation playback rate</a> < 0 and <em>either</em>
<var>animation</var>'s:
* <a>current time</a> is <a>unresolved</a>, or
* <a>current time</a> ≤ zero, or
* <a>current time</a> > <a>target effect end</a>,
:: set <var>animation</var>'s <a>hold time</a> to <a>target effect end</a>.
: If <a>animation playback rate</a> = 0 and <var>animation</var>'s
<a>current time</a> is <a>unresolved</a>,
:: Set <var>animation</var>'s <a>hold time</a> to zero.
</div>
1. If <var>aborted pause</var> is false, perform the following steps:
1. If <var>animation</var>'s <a>hold time</a> is <a>unresolved</a>,
abort this procedure.
1. Let <var>animation</var>'s <a lt="animation start time">start time</a>
be <a>unresolved</a>.
1. If <var>has pending ready promise</var> is false,