Download presentation
Presentation is loading. Please wait.
Published byDora Julie Walton Modified over 8 years ago
1
Towards programmatic control of keyframes, example 1 View this animation in a -moz- or -webkit- browser: http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g9/diver.html It provides a button to access a DOM view of the stylesheet But you will get a somewhat different result from the two types of browser
2
Firefox (-moz-) report, part 1
3
Firefox (-moz-) report, part 2
4
Chrome (-webkit-) report
5
Understanding this output - some necessary DOM details To understand the output from this program, we need some DOM details The CSS2 DOM includes this interface definition CSSRule { // RuleType const unsigned short UNKNOWN_RULE = 0; const unsigned short STYLE_RULE = 1; const unsigned short CHARSET_RULE = 2; const unsigned short IMPORT_RULE = 3; const unsigned short MEDIA_RULE = 4; const unsigned short FONT_FACE_RULE = 5; const unsigned short PAGE_RULE = 6; readonly attribute unsigned short type; attribute DOMString cssText; // raises DOMException on setting readonly attribute CSSStyleSheet parentStyleSheet; readonly attribute CSSRule parentRule; }; References: http://www.w3.org/TR/DOM-Level-2-Style/css#CSS-CSSRule http://dev.w3.org/csswg/cssom/#the-cssrulelist-sequence
6
Analysing the -mozilla- output Rule types in the CSS2 DOM: UNKNOWN_RULE = 0; STYLE_RULE = 1; CHARSET_RULE = 2; IMPORT_RULE = 3; MEDIA_RULE = 4; FONT_FACE_RULE = 5; PAGE_RULE = 6; The first three rules reported in the -mozilla- output are style rules and, appropriately, have type=1 The last three rules are @keyframes rules and are reported to have type=7, a value which is not defined in the CSS2 DOM We must look at the CSS3 DOM
7
Extract from the CSS3 DOM The CSS3 Animations DOM http://www.w3.org/TR/css3-animations/#dom-interfaces- extends the CSSRule interface as follows: CSSRule {... const unsigned short KEYFRAMES_RULE = 7; const unsigned short KEYFRAME_RULE = 8;... }; The distinction between KEYFRAMES_RULE and KEYFRAME-RULE is not clear in the W3C documentation As we shall see soon, this has caused some confusion But notice that the type=7 which was reported by -mozilla- for the @keyframes rules conforms to the CSS3 DOM
8
Analysing the -webkit- output Rule types in the CSS2 DOM: UNKNOWN_RULE = 0; STYLE_RULE = 1; CHARSET_RULE = 2; IMPORT_RULE = 3; MEDIA_RULE = 4; FONT_FACE_RULE = 5; PAGE_RULE = 6; The first three rules reported in the output are style rules and, as expected, have type=1 However, the three @keyframes rules are reported to have type=8, which is different from the type=7 that is defined in the CSS3 DOM for such rules So, we will have to implement a cross- browser approach if we intend to use rule types in our Javascript
9
A note on the -webkit- implementation In November 2011, a Gecko (Mozilla) implementor wrote: interface CSSRule {... const unsigned short KEYFRAMES_RULE = 7; const unsigned short KEYFRAME_RULE = 8; }; However, WebKit implements: const unsigned short WEBKIT_KEYFRAMES_RULE = 8; const unsigned short WEBKIT_KEYFRAME_RULE = 9; We should figure out whether we're using 7 and 8 or using 8 and 9. (I implemented what the spec says in Gecko; I only discovered the difference recently.) Reference http://lists.w3.org/Archives/Public/www-style/2011Nov/0023.html
10
Analysing the program which reported the stylesheet The HTML file differs little from that in previous programs The only difference is that it has a button - to let the user demand a view of the stylesheet through the DOM Diver created with Javascript Several divers will be created with Javascript See the DOM view of the stylesheet
11
The CSS file is unchanged from the previous program We don't need to examine the CSS page because it is the same as before #underwater { position: relative; height: 650px; width: 500px; border: solid 1px black; background: url('seascape.jpg') no-repeat top left; overflow : hidden; } #underwater > div { width: 100px; height: 100px; position: absolute; /* -webkit-animation-name : dive; */ -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-iteration-count: infinite; /*-moz-animation-name : dive;*/ -moz-animation-duration : 7s; -moz- animation-delay : 3s; -moz-animation-iteration-count: infinite; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive1 { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit- transform: translate(0px, 750px); } } @-moz-keyframes dive1 { 0% { -moz-transform : rotate(90deg) translate(0px, -50px); } 100% { -moz-transform: translate(0px, 750px); } } @-webkit-keyframes dive2 { 0% { -webkit-transform: scale(-1,1) translate(0px, 0px); } 100% { -webkit-transform: scale(-1,1) translate(0px, 750px ); } } @-moz-keyframes dive2 { 0% { -moz-transform: rotate(90deg) translate(0px, -50px); } 100% { -moz-transform: scale(- 1,1) translate(0px, 750px); } } @-webkit-keyframes dive3 { 0% { -webkit-transform: translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } } @-moz-keyframes dive3 { 0% { -moz-transform: translate(0px, -50px); } 100% { -moz-transform: translate(0px, 750px); } }
12
Before we look at the Javascript - some more necessary DOM details CSS2 introduced an interface, called DocumentStyle, by which the stylesheets embedded in a document could be retrieved The “expectation [was] that an instance of the DocumentStyle interface can be obtained by using binding-specific casting methods on an instance of the Document interface” –Reference: http://www.w3.org/TR/DOM-Level-2-Style/stylesheets#StyleSheets-extensions Interface definitions DocumentStyle { readonly attribute StyleSheetList styleSheets; }; StyleSheetList { readonly attribute unsigned long length; StyleSheet item( in unsigned long index); }; StyleSheet { readonly attribute DOMString type; attribute boolean disabled; readonly attribute Node ownerNode; readonly attribute StyleSheet parentStyleSheet; readonly attribute DOMString href; readonly attribute DOMString title; readonly attribute MediaList media; }; Stylesheet does not contain CSS information, but it has a specialization called CSSStyleSheet – see next slide
13
Some necessary DOM details (contd.) DOM Level 2 introduced the CSSStyleSheet interface as a specialization of the StyleSheet interface Interface definitions CSSStyleSheet : stylesheets::StyleSheet { readonly attribute CSSRule ownerRule; readonly attribute CSSRuleList cssRules; unsigned long insertRule(in DOMString rule, in unsigned long index) raises(DOMException); void deleteRule(in unsigned long index) raises(DOMException); }; CSSRuleList { readonly attribute unsigned long length; CSSRule item(in unsigned long index) ; }; We have already seen the CSSRule interface Now, we know enough to analyse the Javascript file
14
The diver.js file (part 1) The init() function attaches an event handler to the button const NUMBER_OF_DIVERS = 3; function init() { var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver=newDiver(); envelope.appendChild(someDiver); } var button = document.getElementById('button1'); button.addEventListener('click',cssReport,false); } function randomInteger(lower,upper) { return lower + Math.round(Math.random() * (upper-lower)); } function newDiver() { var diverDiv = document.createElement('div'); var image = document.createElement('img'); image.src = 'diver'+randomInteger(1,3)+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'+randomInteger(1,3); diverDiv.style.MozAnimationName = 'dive'+randomInteger(1,3); /*Note the Moz*/ return diverDiv; }
15
The diver.js file (part 2) function cssReport() { var sheet= document.styleSheets[0]; message='\n '; for (var j =0; j < sheet.cssRules.length; j++) {var rule = sheet. cssRules[j]; message=message+'\n\n'+ 'rule-type is '+rule.type+'\n'+ 'css-text is \n'+rule.cssText; } alert(message); } window.addEventListener('load', init, false);
16
Manipulating the @keyframes rules in a stylesheet We have just seen how to access a stylesheet through the DOM Now let's see how to manipulate the @keyframes rules in a stylesheet The CSS3 Animations DOM defined a CSSKeyframesRule Interface It represents a complete set of keyframes for a single animation Reference: http://www.w3.org/TR/css3-animations/ It is defined as a specialization of CSSRule, as follows: CSSKeyframesRule : CSSRule { attribute DOMString name; readonly attribute CSSRuleList cssRules; void insertRule(in DOMString rule); void deleteRule(in DOMString key); CSSKeyframeRule findRule(in DOMString key); }; The name attribute contains the name of the animation The cssRules attribute contains the list of individual keyframes for the animation in the form of a CSSRuleList, whose interface definition we have already seen
17
Manipulating @keyframes rules (contd.) As we have just seen, the CSSKeyframesRule interface provides three methods: void insertRule(in DOMString rule); void deleteRule(in DOMString key); CSSKeyframeRule findRule(in DOMString key); The findRule() method does not modify an animation –It takes a "when" key and returns the corresponding individual keyframe in the form of a CSSKeyframeRule the CSSKeyframeRule interface is defined on the next slide The insertRule() and deleteRule() methods can be used to modify an animation
18
Manipulating @keyframes rules (contd.) A CSSKeyframeRule represents an individual keyframe, –that is a mapping from a "when" key to the corresponding style specification The interface is defined as a specialization of CSSRule, as follows: CSSKeyframeRule : CSSRule { attribute DOMString keyText; readonly attribute CSSStyleDeclaration style; }; Reference: http://www.w3.org/TR/css3-animations/
19
Towards programmatic control of keyframes, example 2 View this animation in a -moz- or -webkit- browser: http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g10/diver.html It provides a button to to list the names of the animations in the stylesheet
20
Analysing the program The HTML file differs little from that in previous programs Accessing list of animation names Several divers will be created with Javascript List the animation names
21
The CSS file is unchanged from the previous program We don't need to examine the CSS page because it is the same as before #underwater { position: relative; height: 650px; width: 500px; border: solid 1px black; background: url('seascape.jpg') no-repeat top left; overflow : hidden; } #underwater > div { width: 100px; height: 100px; position: absolute; /* -webkit-animation-name : dive; */ -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-iteration-count: infinite; /*-moz-animation-name : dive;*/ -moz-animation-duration : 7s; -moz- animation-delay : 3s; -moz-animation-iteration-count: infinite; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive1 { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit- transform: translate(0px, 750px); } } @-moz-keyframes dive1 { 0% { -moz-transform : rotate(90deg) translate(0px, -50px); } 100% { -moz-transform: translate(0px, 750px); } } @-webkit-keyframes dive2 { 0% { -webkit-transform: scale(-1,1) translate(0px, 0px); } 100% { -webkit-transform: scale(-1,1) translate(0px, 750px ); } } @-moz-keyframes dive2 { 0% { -moz-transform: rotate(90deg) translate(0px, -50px); } 100% { -moz-transform: scale(- 1,1) translate(0px, 750px); } } @-webkit-keyframes dive3 { 0% { -webkit-transform: translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } } @-moz-keyframes dive3 { 0% { -moz-transform: translate(0px, -50px); } 100% { -moz-transform: translate(0px, 750px); } }
22
The diver.js file (part 1) The Javascript is only slightly different from before const NUMBER_OF_DIVERS = 3; function init() { var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver=newDiver(); envelope.appendChild(someDiver); } var button = document.getElementById('button1'); button.addEventListener('click',listAnimationNames,false); } function randomInteger(lower,upper) { return lower + Math.round(Math.random() * (upper-lower)); } function newDiver() { var diverDiv = document.createElement('div'); var image = document.createElement('img'); image.src = 'diver'+randomInteger(1,3)+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'+randomInteger(1,3); diverDiv.style.MozAnimationName = 'dive'+randomInteger(1,3); /*Note the Moz*/ return diverDiv; }
23
The diver.js file (part 2) function listAnimationNames() { var sheet=document.styleSheets[0]; var message='The animation names are\n\n'; for (var j=0; j< sheet.cssRules.length; j++) { var rule = sheet.cssRules[j]; if ( (rule.type==7 || rule.type==8) ) { message=message+rule.name+'\n'; } } alert(message); } window.addEventListener('load', init, false);
24
Programmatic control of keyframes, example 3 View this animation in a -moz- or -webkit- or -o- or -ms- browser: http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g11/diver.html Depending on the browser's capability, it may generate random animations by randomly choosing different maximum depths for each diver
25
Analysing the program The HTML file differs little from that in previous programs Creating random animations Several divers will be created with Javascript
26
The CSS file contains no @keyframe rules The CSS file contains no @keyframe rules but, to prepare for a wider ranger of browsers, it does support more vendor prefixes than before #underwater { position: relative; height: 650px; width: 500px; border: solid 1px black; background: url('seascape.jpg') no-repeat top left; overflow: hidden; } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-delay : 3s; -webkit-animation-duration : 7s; -webkit-animation-direction : alternate; -webkit-animation-iteration-count: infinite; -moz-animation-delay : 3s; -moz-animation-duration : 7s; -moz-animation-direction : alternate; -moz-animation-iteration-count: infinite; -o-animation-delay : 3s; -o-animation-duration : 7s; -o-animation-direction : alternate; -o-animation-iteration-count: infinite; -ms-animation-delay : 3s; -ms-animation-duration : 7s; -ms-animation-direction : alternate; -ms-animation-iteration-count: infinite; animation-delay : 3s; animation-duration : 7s; animation-direction : alternate; animation-iteration-count: infinite; } #underwater > div > img { width: 100px; height: 100px; }
27
The diver.js file - overview The Javascript file is extended to cope with the Microsoft event model and to include a function for generating new (vendor-prefixed) @keyframes rules function init() {... } function newDiver(counter) {... } function randomInteger(lower,upper) {... } function nameOfNewAnimation(counter) {... } function newAtKeyframesRule(animationName,bottomOfDive) {... } function detectedPrefix() {... } if (window.addEventListener) { window.addEventListener('load', init, false); } else if (window.attachEvent) /*Microsoft event model*/ { window.attachEvent('onload', init); }
28
The diver.js file (contd.) - the init() function The main difference from previous programs is that, when the init() function calls the newDiver() function to create a new diver, it passes the counter as a parameter As we shall see later, this is to enable the programmatically-generated animations to have distinct names function init() { NUMBER_OF_DIVERS = 3; var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver = newDiver(i); envelope.appendChild(someDiver); } }
29
The diver.js file (contd.) - the newDiver() function The main difference from previous programs is that newDiver() uses a function, called nameOfNewAnimation(), to generate a customized new animation for each diver and return the name of the new animation, the name is derived from the counter, passed as a parameter Also, since the counter is available, it is used to try to ensure that the diver images are as distinct as possible function newDiver(counter) { var diverDiv = document.createElement('div'); var image = document.createElement('img'); imageNumber=(counter % 3)+1; /*Number of distinct diver images is 3*/ image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; var someAnimationName=nameOfNewAnimation(counter); diverDiv.style.webkitAnimationName=someAnimationName; diverDiv.style.MozAnimationName=someAnimationName; diverDiv.style.msAnimationName=someAnimationName; diverDiv.style.oAnimationName=someAnimationName; diverDiv.style.animationName=animationName; return diverDiv; }
30
The diver.js file (contd.) - the nameOfNewAnimation() function counter is used to get the new name animation name All animations have the same pattern, differing only in the maximum depth to which the diver descends this is a random integer in the range 200 to 750 newAtKeyframesRule () is called to construct the @keyframes rule for the new animation –if the browser does not support @keyframes rules, "undefined" is returned if a @keyframes rule is successfully built, insertRule() is called to insert it at the top of the stylesheet function nameOfNewAnimation(counter) { var animationName="randomDive"+counter; var bottomOfDive=randomInteger(200,750); rule=newAtKeyframesRule(animationName,bottomOfDive); if (rule != "undefined") { var styleSheet=document.styleSheets[0]; styleSheet.insertRule(rule,0); } return animationName; }
31
The diver.js file (contd.) - the newAtKeyframesRule() function detectedPrefix() is called to check if the browser supports @keyframes rules and, if so, to get the correct vendor prefix detectedPrefix() reports 'unknown' if the browser does not support @keyframes rules if detectedPrefix() reports the empty string as a prefix, an unprefixed rule is built function newAtKeyframesRule(animationName,bottomOfDive) { var prefix=detectedPrefix(); if (prefix=='') { rule="@keyframes "+animationName+ " { 0% { transform: translate(0px, 0px); } "+ " 100% { transform: translate(0px, "+bottomOfDive+"px); } }"; } else if (prefix != 'unknown') {rule="@-"+prefix+"-keyframes "+animationName+" { 0% { -"+prefix+ "-transform: translate(0px, 0px); } "+ " 100% { -"+prefix+ "-transform: translate(0px, " +bottomOfDive+"px); } }"; } else rule="undefined"; return rule; }
32
The diver.js file (contd.) - the detectedPrefix() function To determine the correct prefix to use we check for the presence or absence of a (possibly not vendor-prefixed) feature called requestAnimationFrame (which we will use later, in canvas animations) if an un-prefixed version of the feature is available, no prefix is needed for the @keyframes rule if the feature is not available, it is probable that the browser does not support CSS animations and 'unknown' is returned as the prefix, in order to prevent Javascript aborting because of an attempt to insert a @keyframes rule function detectedPrefix() { if (window.webkitRequestAnimationFrame) { return 'webkit'; } else if (window.mozRequestAnimationFrame) { return 'moz'; } else if (window.oRequestAnimationFrame) { return 'o'; } else if (window.msRequestAnimationFrame) { return 'ms'; } else if (window.requestAnimationFrame) { return ''; } else { alert('Your browser does not (fully) support animation'); return 'unknown'; } }
33
Programmatic control of keyframes, example 4 View this animation in a -moz- or -webkit- or -o- or -ms- browser: http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g12/diver.html If the browser fully supports animation, it will generate random animations by randomly choosing different maximum depths for each diver in addition, it will insert a random keyframe into each @keyframes rule (This random insertion of a keyframe is not needed but is shown to illustrate how the technology can be used) the browser reports the stylesheet to show what the @keyframes rules look like after an additional keyframe has been inserted into each of them
34
Analysing the program The HTML file differs little from that in previous programs Creating random animations Several divers will be created with Javascript
35
The CSS file is modified, to illustrate the effects of randomization To show the effect of the randomized horizontal movement, we provide a left margin and allow overflow material to be seen #underwater { position: relative; height: 650px; width: 500px; margin-left:300;border: solid 1px black; background: url('seascape.jpg') no-repeat top left; /* overflow: hidden; */ } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-delay : 3s; -webkit-animation-duration : 7s; -webkit-animation-direction : alternate; -webkit-animation-iteration-count: infinite; -moz-animation-delay : 3s; -moz-animation-duration : 7s; -moz-animation-direction : alternate; -moz-animation-iteration-count: infinite; -o-animation-delay : 3s; -o-animation-duration : 7s; -o-animation-direction : alternate; -o-animation-iteration-count: infinite; -ms-animation-delay : 3s; -ms-animation-duration : 7s; -ms-animation-direction : alternate; -ms-animation-iteration-count: infinite; animation-delay : 3s; animation-duration : 7s; animation-direction : alternate; animation-iteration-count: infinite; } #underwater > div > img { width: 100px; height: 100px; }
36
The diver.js file - overview The architecture of the Javascript file is almost unchanged –there are some new functions to introduce a random keyframe into a @keyframes rule –there is a function to report the state of the CSS stylesheet function init() {... } function newDiver(counter) {... } function randomInteger(lower,upper) {... } function nameOfNewAnimation(counter) {... } function newAtKeyframesRule(animationName,bottomOfDive) {... } function detectedPrefix() {... } function introduceRandomKeyframe(someAnimationName) {... } function newKeyframe(someAnimationName) {... } function cssReport() {... } if (window.addEventListener) { window.addEventListener('load', init, false); } else if (window.attachEvent) /*Microsoft event model*/ { window.attachEvent('onload', init); }
37
The diver.js file (contd.) - the init() function The only difference from previous programs is that, when the init() function has finished its work, it reports the state of the modified CSS stylesheet function init() { NUMBER_OF_DIVERS = 3; var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver = newDiver(i); envelope.appendChild(someDiver); } cssReport(); }
38
The diver.js file (contd.) - the newDiver() function The only difference from the previous program is that, after nameOfNewAnimation() has generated the animation for a new diver, it then inserts a random new keyframe into the @keyframes rule for the animation that has just been created –this is done only to illustrate the technology –nameOfNewAnimation() could easily have included the additional keyframe when building the @keyframes rule function newDiver(counter) { var diverDiv = document.createElement('div'); var image = document.createElement('img'); imageNumber=(counter % 3)+1; /*Number of distinct diver images is 3*/ image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; var someAnimationName=nameOfNewAnimation(counter); introduceRandomKeyframe(someAnimationName); diverDiv.style.webkitAnimationName=someAnimationName; diverDiv.style.MozAnimationName=someAnimationName; diverDiv.style.msAnimationName=someAnimationName; diverDiv.style.oAnimationName=someAnimationName; diverDiv.style.animationName=animationName; return diverDiv; }
39
The diver.js file (contd.) - the nameOfNewAnimation() function This function is unchanged from the previous program function nameOfNewAnimation(counter) { var animationName="randomDive"+counter; var bottomOfDive=randomInteger(200,750); rule=newAtKeyframesRule(animationName,bottomOfDive); if (rule != "undefined") { var styleSheet=document.styleSheets[0]; styleSheet.insertRule(rule,0); } return animationName; }
40
The diver.js file (contd.) - the newAtKeyframesRule() function This function is unchanged from the previous program function newAtKeyframesRule(animationName,bottomOfDive) { var prefix=detectedPrefix(); if (prefix=='') { rule="@keyframes "+animationName+ " { 0% { transform: translate(0px, 0px); } "+ " 100% { transform: translate(0px, "+bottomOfDive+"px); } }"; } else if (prefix != 'unknown') {rule="@-"+prefix+"-keyframes "+animationName+" { 0% { -"+prefix+ "-transform: translate(0px, 0px); } "+ " 100% { -"+prefix+ "-transform: translate(0px, " +bottomOfDive+"px); } }"; } else rule="undefined"; return rule; }
41
The diver.js file (contd.) - the detectedPrefix() function This function is unchanged from the previous program function detectedPrefix() { if (window.webkitRequestAnimationFrame) { return 'webkit'; } else if (window.mozRequestAnimationFrame) { return 'moz'; } else if (window.oRequestAnimationFrame) { return 'o'; } else if (window.msRequestAnimationFrame) { return 'ms'; } else if (window.requestAnimationFrame) { return ''; } else { alert('Your browser does not (fully) support animation'); return 'unknown'; } }
42
The diver.js file (contd.) - the introduceRandomKeyframe() function We search through the stylesheet for the right @keyframes rule Then we insert generate a random x value for the middle of the dive And insert a keyframe for this into the @keyframes rule function introduceRandomKeyframe(someAnimationName) { var styleSheet=document.styleSheets[0]; var foundRule=false; var counter=0; while (!foundRule && counter < styleSheet.cssRules.length) { var rule = styleSheet.cssRules[counter]; if ( ( (rule.type==7 || rule.type==8) ) && rule.name==someAnimationName ) { foundRule=true; var middleOfDive=randomInteger(-500,350); var keyframe=newKeyframe(middleOfDive); if (keyframe != "undefined") { rule.insertRule(keyframe,0); } } else { counter = counter+1; } }
43
The diver.js file (contd.) - the newKeyframe() function We check whether the browser supports keyframes and, if so, whether a prefix is needed If keyframes are not supported, we return "undefined" as the keyframe text Otherwise, we return (possibly prefixed) keyframe text using middleOfDive as the X coordinate for at the 50% time point function newKeyframe(middleOfDive) { var prefix=detectedPrefix(); if (prefix=='') { frame="50% { transform: translate("+middleOfDive+"px,300px); } "; } else if (prefix != 'unknown') { frame="50% { -"+prefix+ "-transform: translate("+middleOfDive+"px,300px); } "; } else frame="undefined"; return frame; }
44
The diver.js file (contd.) - the cssReport() function We have seen this function in a previous program, so it will not be considered in any detail here function cssReport() { var sheet= document.styleSheets[0]; message='\n '; for (var j =0; j < sheet.cssRules.length; j++) {var rule = sheet. cssRules[j]; message=message+'\n\n'+ 'rule-type is '+rule.type+'\n'+ 'css-text is \n'+rule.cssText; } alert(message); }
45
Note on animated property values The value of a style property for an element is affected by an animation only in the interval between these two points in time the expiry of the delay (if any) after the animation was applied to the element the end of the animation-duration after the expiry of the delay (if any) Reference: http://www.w3.org/TR/css3-animations/
46
An attempt at an interactive animation Try to use this animation in a -moz- browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g13/diver.html The aim was to create an interactive animation in which the user could control whether the diver is descending or moving rightwards. To make the diver move in a new direction, we must pause the animation, specify the new direction and then resume the animation We could build the @keyframes rule to animate the new direction if we knew where the paused diver was However, at present (February 2012) it appears that no mechanism is available for querying the current value of an animated property So, since we cannot determine the diver's current position when he is suspended in mid-animation, he will start from the default position when we resume the animation
47
Animation events Try to use this animation in a -webkit- browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g14/diver.html As it starts the animation for each diver, it outputs an alert message, naming the animation it is starting and the diver to which it is applying this animation
48
Analysing the program The HTML file differs little from that in previous programs Diver created with Javascript Several divers will be created with Javascript
49
Just webkit keyframes in the CSS At present, CSS animation events are supported only in -webkit- browsers #underwater { position: relative; height: 650px; width: 500px; overflow:hidden; border: solid 1px black;background: url('seascape.jpg') no-repeat top left; } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-iteration-count: infinite; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive1 { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } } @-webkit-keyframes dive2 { 0% { -webkit-transform: scale(-1,1) rotate(-45deg) translate(0px, 0px); } 100% { -webkit-transform: scale(-1,1) translate(0px, 750px); } } @-webkit-keyframes dive3 { 0% { -webkit-transform: translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } }
50
The diver.js file We add an event listener to each diverDiv, listening for animationStart events const NUMBER_OF_DIVERS = 3; function init() { var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver=newDiver(i); envelope.appendChild(someDiver); } } function randomInteger(lower,upper) { return lower + Math.round(Math.random() * (upper-lower)); } function newDiver(counter) { var diverDiv = document.createElement('div'); diverDiv.setAttribute('id','diver'+counter); var image = document.createElement('img'); imageNumber=(counter % 3)+1; /*Number of diver images is 3*/ image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'+randomInteger(1,3); diverDiv.addEventListener('webkitAnimationStart', reportStart, false ); return diverDiv; } function reportStart(...) {... } window.addEventListener('load', init, false);
51
The reportStart() function The reportStart() function uses several attributes of the event object As we shall see on the next few slides, these attributes were introduced in DOM2 and DOM3 function reportStart(e) { alert( 'Just starting an instance of animation '+ e.animationName+ ' on '+ e.target.getAttribute("id") ); }
52
CSS Animation events CSS3 defined the AnimationEvent as a specialization of the Event class that had been defined in DOM2 AnimationEvent : Event { readonly attribute DOMString animationName; readonly attribute float elapsedTime; void initAnimationEvent( in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg; in DOMString animationNameArg, in float elapsedTimeArg ); }; There are three types of animation event –animationstart - occurs at the start of an animation –animationend - occurs when the animation finishes –animationiteration -occurs at the end of each iteration of an animation for which animation-iteration-count is greater than one; does not occur for animations with an iteration count of one elapsedTime - time, in seconds, between start of animation and this event, excluding any time animation was paused; not affect by animation-delay; is always zero for animationstart events We will consider the initAnimationEvent() method later Reference:http://www.w3.org/TR/css3-animations/
53
Reminder: DOM2 Event class The Event class was defined in DOM2 as follows: Event { // PhaseType const unsigned short CAPTURING_PHASE = 1; const unsigned short AT_TARGET = 2; const unsigned short BUBBLING_PHASE = 3; readonly attribute DOMString type; readonly attribute EventTarget target; /*where event happened*/ readonly attribute EventTarget currentTarget; /*loc'n of current handler*/ readonly attribute unsigned short eventPhase; readonly attribute boolean bubbles; readonly attribute boolean cancelable; readonly attribute DOMTimeStamp timeStamp; void stopPropagation(); void preventDefault(); void initEvent(in DOMString eventTypeArg, in boolean canBubbleArg, in boolean cancelableArg); }; Reference: http://www.w3.org/TR/DOM-Level-2-Events/events.html
54
Using events: message to user before/after animation Try to use this animation in a -webkit- browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g15/diver.html Before the animation starts, the window contains a message asking the user to wait This message disappears when the animation starts A new message appears when the animation is finished
55
Analysing the HTML file Only novelty is presence of div containing message Diver created with Javascript Please wait for start of animation
56
Analysing the CSS file Only novelty is that there is a finite iteration count #underwater { position: relative; height: 650px; width: 500px; overflow:hidden; border: solid 1px black;background: url('seascape.jpg') no-repeat top left; } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-iteration-count: 2; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive1 { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } } @-webkit-keyframes dive2 { 0% { -webkit-transform: scale(-1,1) rotate(-45deg) translate(0px, 0px); } 100% { -webkit-transform: scale(-1,1) translate(0px, 750px); } } @-webkit-keyframes dive3 { 0% { -webkit-transform: translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } }
57
The diver.js file Javascript architecture is mostly the same But now, two animation event handlers are attached to each diver const NUMBER_OF_DIVERS = 3; function init() {... } function randomInteger(lower,upper) {... } function processStart(e) {... } function processEnd(e) {...} function newDiver(counter) { var diverDiv = document.createElement('div'); diverDiv.setAttribute('id','diver'+counter); var image = document.createElement('img'); imageNumber=(counter % 3)+1; image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px";diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'+randomInteger(1,3); diverDiv.addEventListener('webkitAnimationStart', reportStart, false); diverDiv.addEventListener('webkitAnimationEnd', reportEnd, false); return diverDiv; } window.addEventListener('load', init, false);
58
The processStart() and processEnd() functions processStart() just hides the message div processEnd() changes its content before making it visible again function processStart(e) { var waitDiv = document.getElementById('messageDiv'); if (waitDiv.style.visibility=="visible") { waitDiv.style.visibility="hidden"; } } function processEnd(e) { var waitDiv = document.getElementById('messageDiv'); if (waitDiv.style.visibility=="hidden") { elapsedTime = e.elapsedTime; newMessage = "Here's hoping you enjoyed the animation! "+ "It lasted "+elapsedTime+" seconds"; waitDiv.innerHTML=newMessage; waitDiv.style.visibility="visible"; } }
59
Transition Events View this page in a -webkit- or -moz- or -o- or -ms- browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/transitionEvent/transitionEvent.html The images below show what happens, using Chrome as an example The text in the red area starts to transition to a larger font-size When the transition ends, the message on the top of the page is changed
60
Analysing the HTML file We shall see later that –the div element is affected by a transition specified in the stylesheet –the Javascript specifies that when the transition ends, the content of the h1 element will be changed Transition events Hold your mouse over the red area below and see what happens Hello
61
Analysing the CSS file When the mouse hovers over the div element, 8 seconds will be spent transitioning the font-size from 10px to 50px #helloDiv:hover {font-size:50px; -webkit-transition-duration:8s; -moz-transition-duration:8s; -ms-transition-duration:8s; -o-transition-duration:8s; transition-duration:8s; } #helloDiv {background-color:red; font-size:10px}
62
The diver.js file Javascript architecture is familiar An event handler is used to watch for the end of the transition Notice the unusual form of the Mozilla event name function processEnd(e) {var messageHeader = document.getElementById('message'); newMessage="OK, you can remove your mouse now. "+ e.elapsedTime+" seconds was spent changing the "+e.propertyName; messageHeader.innerHTML=newMessage; } function init () { var helloDiv=document.getElementById("helloDiv"); helloDiv.addEventListener( 'webkitTransitionEnd', processEnd, false); helloDiv.addEventListener( 'transitionend', processEnd, false); /*Mozilla*/ helloDiv.addEventListener( 'oTransitionEnd', processEnd, false); helloDiv.addEventListener( 'MSTransitionEnd', processEnd, false); } window.addEventListener('load', init, false);
63
CSS Transition Events The CSS3 DOM interace definition for transition events is as follows TransitionEvent : Event { readonly attribute DOMString propertyName; readonly attribute float elapsedTime; void initTransitionEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString propertyNameArg, in float elapsedTimeArg); }; The only type of transition event supported is the end of a transition –the start of a transition does not trigger an event W3C reference: http://dev.w3.org/csswg/css3-transitions/
64
Simulating events programmatically The DOM provides features which allow us to write Javascript that simulates events, such as user interactions with a page, etc. The initAnimationEvent() and initTransitionEvent() methods which we saw earlier are intended to allow us to simulate animation and simulation events Before we try to use these methods, we should look at the basic approach to simulating events programmatically
65
Simulating a mouse click on a check box View this page in a modern browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/eventSimulation/example.html When the user clicks on the button, the document responds as if he had clicked his mouse in the checkbox This was achieved using features provided by the DOM to allow us to programmatically simulate events
66
Analysing the HTML file We will use a click on button1 to trigger a simulation of a click on checkBox1 Simulating an event Simulate a mouse click in the check box above
67
The Javascript file It is a three-stage process: –creation, initialization, dispatch We create a new event of type MouseEvents We initialize the new event with values appropriate for a mouse event We use dispatchEvent to simulate the new event happening on the check box function init() { var button1 = document.getElementById('button1'); button1.addEventListener('click', simulateMouseClickOnCheckBox, false); } function simulateMouseClickOnCheckBox() { var checkBox1=document.getElementById('checkBox1'); var newEvent = document.createEvent("MouseEvents"); newEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0,false, false, false, false, 0, null); checkBox1.dispatchEvent(newEvent); } window.addEventListener('load', init, false);
68
Simulating an animation end event, first run We will view this page in a -webkit- browser twice http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g16/diver.html First time, we will not use the button provided on the page We will wait until all animation stops and look at the output We see that, at the end of each diver's animation, text is added to the top message area, saying that the animation lasted 21 seconds
69
Simulating an animation end event, second run Now, reload this page and view it a second time in a -webkit- browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g16/diver.html This time, click on the button just after the animation starts Immediately, we get a (untruthful) message saying that diver1's animation is finished and lasted more than 10 minutes! But all three divers continue to move until, a little later, we are told that each animation, including diver1's, lasted 21 seconds. So, clicking the button simulated the end of diver1's animation but did not actually end it
70
Analysing the HTML file Only novelty is button for invoking the simulation Diver created with Javascript Please wait for start of animation Simulate an end to animation on diver1
71
Analysing the CSS file For illustrative purposes, overflow is visible Each animation runs for three iterations As we shall see in the Javascript, each diver's animation is an instance of the animation called dive which is defined below #underwater { position: relative; height: 650px; width: 500px; border: solid 1px black; background: url('seascape.jpg') no-repeat top left; /* overflow: hidden; */ } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-direction : alternate; -webkit-animation-iteration-count: 3; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } }
72
The diver.js file Javascript architecture is mostly the same But there is a new function, called simulateAnimationEnd(), which, as we shall see, is attached as an event listener to button1 const NUMBER_OF_DIVERS = 3; function init() {... } function randomInteger(lower,upper) {... } function processStart(e) {... } function processEnd(e) {...} function newDiver(counter) {... } function simulateAnimationEnd() {... } window.addEventListener('load', init, false);
73
function init() Only novelty is that it attaches simulateAnimationEnd as an event listener to button1 function init() { var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver=newDiver(i); envelope.appendChild(someDiver); } var button1 = document.getElementById('button1'); button1.addEventListener('click', simulateAnimationEnd, false); }
74
The randomInteger() and processStart() functions These are almost the same as before Only difference is that processStart() does not hide the messageDiv –instead, it just makes the content equal to the empty string –this simplifies the processEnd() function which is on the next slide function randomInteger(lower,upper) { return lower + Math.round(Math.random() * (upper-lower)); } function processStart(e) { var messageDiv = document.getElementById('messageDiv'); messageDiv.innerHTML="" }
75
The processEnd() function This function reacts to an animationEnd event Whether the event actually happens or is simulated, –the identity of the diver involved in the event object is found and –information about the length of the animation involved in the event object is added to the message div function processEnd(e) { /*Find the diver whose animationEnd just happened or is being simulated*/ diverID=e.target.getAttribute("id"); /*Add appropriate output to the message div*/ var messageDiv = document.getElementById('messageDiv'); oldMessage=messageDiv.innerHTML; newMessage="The animation on "+diverID+ " lasted "+e.elapsedTime+" seconds."; messageDiv.innerHTML=oldMessage+newMessage; }
76
The newDiver() function Same as before, except that although the divers are given different starting points, they are all given the same animation function newDiver(counter) { var diverDiv = document.createElement('div'); diverDiv.setAttribute('id','diver'+counter); var image = document.createElement('img'); imageNumber=(counter % 3)+1; /*Number of diver images is 3*/ image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'; diverDiv.addEventListener('webkitAnimationStart', processStart,false ); diverDiv.addEventListener('webkitAnimationEnd', processEnd, false ); return diverDiv; }
77
And, now for the beef in the sandwich......, that is, the simulateAnimationEnd() function It is on the next slide
78
The simulateAnimationEnd() function Same architecture as function for simulating a mouse click event –createEvent, initEvent, dispatchEvent Note the use of the vendor-specific prefix in three places Note, also, the use of an element called anyObject –the next slide provides a note about this function simulateAnimationEnd() { var diver1=document.getElementById('diver1'); var newEvent = document.createEvent("WebKitAnimationEvent"); var anyObject = document.createElement(); newEvent.initWebKitAnimationEvent("webkitAnimationEnd", true, true,anyObject,600.5); diver1.dispatchEvent(newEvent); }
79
Note on the initWebKitAnimationEvent() method, part 1 CSS3 defined the initAnimationEvent() method as follows void initAnimationEvent( in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg; in DOMString animationNameArg, in float elapsedTimeArg ); }; Reference: http://www.w3.org/TR/css3-animations/http://www.w3.org/TR/css3-animations/ The fourth argument is supposed to be a string and, apparently, should be the name of an animation Thus, in the simulateAnimationEnd() function, I expected that the fourth argument to initWebKitAnimationEvent() should be "dive" However, when I tried that, it did not work Then, I found that this web-page used the window object in this position http://cubiq.org/spinning-wheel-on-webkit-for-iphone-ipod-touch After experimentation, I discovered that the window object is not necessary –any object is good enough –so, to emphasise this, I just create a new element object and use that var anyObject = document.createElement(); newEvent.initWebKitAnimationEvent("webkitAnimationEnd",true,true,anyObject,60);
80
Note on the initWebKitAnimationEvent() method, part 2 The previous slide referred to the use of the window object as an argument to initWebKitAnimationEvent() method This was in a web-page that talked about programming for an Apple product, the iPod touch Since -webkit- browsers are based on the Safari model, it may be useful to consult documentation on the Safari DOM: –The initWebKitAnimationEvent() method is partly desribed in this PDF document, entitled Safari DOM Extensions Reference, and dated 21 November 2008: http://pooky.sourceforge.net/data/SafariJSRef.pdf
81
Really creating an animation end event, first run In the last program, we just simulated the end of an animation Suppose that we want to actually create the end of an animation The button on this web-page does so http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g17/diver.html First time you view this page, do not use the button –wait until all animation stops and look at the output Note that, as in the last program, text is added to the top message area, saying that each animation lasted 21 seconds
82
Really creating an animation end event, second run Now, reload this page and view it a second time in a -webkit- browser http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g17/diver.html This time, click on the button just after the animation starts Immediately, diver1 stops –and we get a message lying about the length of its animation The other two divers continue until their animations are finished
83
The HTML file is unchanged from before Diver created with Javascript Please wait for start of animation Simulate an end to animation on diver1
84
The CSS file is unchanged from before #underwater { position: relative; height: 650px; width: 500px; border: solid 1px black; background: url('seascape.jpg') no-repeat top left; /* overflow: hidden; */ } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-direction : alternate; -webkit-animation-iteration-count: 3; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } }
85
The Javascript architecture is the same as before const NUMBER_OF_DIVERS = 3; function init() {... } function randomInteger(lower,upper) {... } function processStart(e) {... } function processEnd(e) {...} function newDiver(counter) {... } function simulateAnimationEnd() {... } window.addEventListener('load', init, false);
86
function init() is the same as before function init() { var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver=newDiver(i); envelope.appendChild(someDiver); } var button1 = document.getElementById('button1'); button1.addEventListener('click', simulateAnimationEnd, false); }
87
The randomInteger() and processStart() functions are unchanged function randomInteger(lower,upper) { return lower + Math.round(Math.random() * (upper-lower)); } function processStart(e) { var messageDiv = document.getElementById('messageDiv'); messageDiv.innerHTML="" }
88
The processEnd() function has one extra statement When an animationEnd event object involves a diver, we eliminate that diver's animation This means that, even if the event was only simulated, the diver stops moving function processEnd(e) { /*Find the diver whose animationEnd just happened or is being simulated*/ diverID=e.target.getAttribute("id"); /*Eliminate this diver's animation*/ diver.style.webkitAnimationName=""; /*Add appropriate output to the message div*/ var messageDiv = document.getElementById('messageDiv'); oldMessage=messageDiv.innerHTML; newMessage="The animation on "+diverID+ " lasted "+e.elapsedTime+" seconds."; messageDiv.innerHTML=oldMessage+newMessage; }
89
The newDiver() function is unchanged function newDiver(counter) { var diverDiv = document.createElement('div'); diverDiv.setAttribute('id','diver'+counter); var image = document.createElement('img'); imageNumber=(counter % 3)+1; /*Number of diver images is 3*/ image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'; diverDiv.addEventListener('webkitAnimationStart', processStart,false ); diverDiv.addEventListener('webkitAnimationEnd', processEnd, false ); return diverDiv; }
90
The simulateAnimationEnd() function is unchanged function simulateAnimationEnd() { var diver1=document.getElementById('diver1'); var newEvent = document.createEvent("WebKitAnimationEvent"); var anyObject = document.createElement(); newEvent.initWebKitAnimationEvent("webkitAnimationEnd", true, true,anyObject,600.5); diver1.dispatchEvent(newEvent); }
91
Reporting the correct elapsed time In the last program, an untruthful elapsed time was reported when diver1's animation was artificially ended This program tells the truth when we forcibly end diver1's animation: http://www.cs.ucc.ie/j.bowen/cs4506/slides/diving/g18/diver.html
92
The HTML file is unchanged from before Diver created with Javascript Please wait for start of animation Simulate an end to animation on diver1
93
The CSS file is unchanged from before #underwater { position: relative; height: 650px; width: 500px; border: solid 1px black; background: url('seascape.jpg') no-repeat top left; /* overflow: hidden; */ } #underwater > div { width: 100px; height: 100px; position: absolute; -webkit-animation-duration : 7s; -webkit-animation-delay : 3s; -webkit-animation-direction : alternate; -webkit-animation-iteration-count: 3; } #underwater > div > img { width: 100px; height: 100px; } @-webkit-keyframes dive { 0% { -webkit-transform: rotate(90deg) translate(0px, 0px); } 100% { -webkit-transform: translate(0px, 750px); } }
94
The Javascript architecture is slightly changed We introduce a global variable to hold the time that diver1's animation is started const NUMBER_OF_DIVERS = 3; var startOfDiver1Animation; function init() {... } function randomInteger(lower,upper) {... } function processStart(e) {... } function processEnd(e) {...} function newDiver(counter) {... } function simulateAnimationEnd() {... } window.addEventListener('load', init, false);
95
function init() is the same as before function init() { var envelope = document.getElementById('underwater'); var someDiver; for (var i = 0; i < NUMBER_OF_DIVERS; i++) { someDiver=newDiver(i); envelope.appendChild(someDiver); } var button1 = document.getElementById('button1'); button1.addEventListener('click', simulateAnimationEnd, false); }
96
The randomInteger() function is unchanged function randomInteger(lower,upper) { return lower + Math.round(Math.random() * (upper-lower)); }
97
The processStart() function is slightly changed Each time an animation is started, we check whether the diver involved is diver1 If so, we set the global variable startOfDiver1Animation to the current time in millseconds function processStart(e) { /*Find the diver whose animationStart just happened */ diverID=e.target.getAttribute("id"); if (diverID=="diver1") { now=new Date(); startOfDiver1Animation =now.getTime(); } var messageDiv = document.getElementById('messageDiv'); messageDiv.innerHTML="" }
98
The processEnd() function is unchanged function processEnd(e) { /*Find the diver whose animationEnd just happened or is being simulated*/ diverID=e.target.getAttribute("id"); /*Eliminate this diver's animation*/ diver.style.webkitAnimationName=""; /*Add appropriate output to the message div*/ var messageDiv = document.getElementById('messageDiv'); oldMessage=messageDiv.innerHTML; newMessage="The animation on "+diverID+ " lasted "+e.elapsedTime+" seconds."; messageDiv.innerHTML=oldMessage+newMessage; }
99
The newDiver() function is unchanged function newDiver(counter) { var diverDiv = document.createElement('div'); diverDiv.setAttribute('id','diver'+counter); var image = document.createElement('img'); imageNumber=(counter % 3)+1; /*Number of diver images is 3*/ image.src = 'diver'+imageNumber+'.png'; diverDiv.appendChild(image); diverDiv.style.top = "-100px"; diverDiv.style.left = randomInteger(100,400)+'px'; diverDiv.style.webkitAnimationName = 'dive'; diverDiv.addEventListener('webkitAnimationStart', processStart,false ); diverDiv.addEventListener('webkitAnimationEnd', processEnd, false ); return diverDiv; }
100
The simulateAnimationEnd() function is slightly changed We compute the elapsed time for diver1's animation, whose end we are simulating, to be the current time (in milliseconds) minus the time that diver1's animation was started We divide the elapsed time by 1000 to get it in seconds We use this computed time when initializing the event function simulateAnimationEnd() {var now=new Date(); var elapsedTime=(now.getTime()-startOfDiver1Animation)/1000; var diver1=document.getElementById('diver1'); var newEvent = document.createEvent("WebKitAnimationEvent"); var anyObject = document.createElement(); newEvent.initWebKitAnimationEvent("webkitAnimationEnd", true, true,anyObject,elapsedTime); diver1.dispatchEvent(newEvent); }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.