1 <!-- 2 Copyright (c) 2012 Cameron Adams. All rights reserved. 3 Copyright (c) 2012 Code Aurora Forum. All rights reserved. 4 Copyright (C) 2013 Google Inc. All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are 8 met: 9 * Redistributions of source code must retain the above copyright 10 notice, this list of conditions and the following disclaimer. 11 * Redistributions in binary form must reproduce the above 12 copyright notice, this list of conditions and the following disclaimer 13 in the documentation and/or other materials provided with the 14 distribution. 15 * Neither the name of Code Aurora Forum Inc., Google Inc. nor the 16 names of its contributors may be used to endorse or promote products 17 derived from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 This test is based on code written by Cameron Adams and imported from 32 http://themaninblue.com/experiment/AnimationBenchmark/html 33 --> 34 35 <!doctype html> 36 <head> 37 <title>Benchmark - Balls Animation using CSS Animations</title> 38 <style> 39 html { 40 height: 100%; 41 } 42 43 body { 44 width: 100%; 45 height: 100%; 46 overflow: hidden; 47 margin: 0; 48 padding: 0; 49 } 50 51 span { 52 position: absolute; 53 width: 12px; 54 height: 12px; 55 border-radius: 6px; 56 } 57 </style> 58 <script src="../resources/runner.js"></script> 59 <script src="resources/framerate.js"></script> 60 <script> 61 var stageWidth = 600; 62 var stageHeight = 600; 63 var maxParticles = 2500; 64 var minVelocity = 50; 65 var maxVelocity = 500; 66 var particleRadius = 6; 67 var colors = ["#cc0000", "#ffcc00", "#aaff00", "#0099cc", "#194c99", "#661999"]; 68 var animationDuration = 10; 69 70 var particles = []; 71 72 window.onload = function () { 73 PerfTestRunner.prepareToMeasureValuesAsync({done: onCompletedRun, unit: 'fps'}); 74 75 generateStyleElement(); 76 77 // Create the particles 78 for (var i = 0; i < maxParticles; i++) { 79 var particle = new Particle(i); 80 particle.start(); 81 particles.push(particle); 82 } 83 84 startTrackingFrameRate(); 85 } 86 87 function generateStyleElement() { 88 var allParticleKeyframes = ''; 89 for (var i = 0; i < maxParticles; i++) 90 allParticleKeyframes += generateParticleKeyframes(i); 91 document.querySelector('#keyframes').innerHTML = allParticleKeyframes; 92 } 93 94 function generateParticleKeyframes(index) { 95 var keyframes = '@-webkit-keyframes ' + animationNameForIndex(index) + '{\n'; 96 97 var angle = Math.PI * 2 * PerfTestRunner.random(); 98 var velocity = minVelocity + ((maxVelocity - minVelocity) * PerfTestRunner.random()); 99 var x = stageWidth / 2 - particleRadius; 100 var y = stageHeight / 2 - particleRadius; 101 var dx = Math.cos(angle) * velocity; 102 var dy = Math.sin(angle) * velocity; 103 104 function detectCollision(lineX, normalX, lineY, normalY) { 105 var dtx = Infinity; 106 var dty = Infinity; 107 if (dx * normalX < 0) 108 dtx = (lineX - x) / dx; 109 if (dy * normalY < 0) 110 dty = (lineY - y) / dy; 111 var dt = Math.min(dtx, dty); 112 var hitX = (dtx < dty); 113 return { 114 dt: dt, 115 x: hitX ? lineX : x + (dx * dt), 116 y: hitX ? y + (dy * dt) : lineY, 117 dx: hitX ? -dx : dx, 118 dy: hitX ? dy : -dy, 119 }; 120 } 121 122 var t = 0; 123 keyframes += generateKeyframe(0, x, y); 124 while (t < animationDuration) { 125 var collisionA = detectCollision(0, 1, 0, 1); 126 var collisionB = detectCollision(stageWidth, -1, stageHeight, -1); 127 var collision = collisionA.dt < collisionB.dt ? collisionA : collisionB; 128 if (t + collision.dt > animationDuration) { 129 var dt = animationDuration - t; 130 t = animationDuration; 131 x += dx * dt; 132 y += dy * dt; 133 } else { 134 t += collision.dt; 135 x = collision.x; 136 y = collision.y; 137 dx = collision.dx; 138 dy = collision.dy; 139 } 140 keyframes += generateKeyframe(t, x, y); 141 } 142 143 keyframes += '}\n'; 144 return keyframes; 145 } 146 147 function generateKeyframe(t, x, y) { 148 return (100 * t / animationDuration) + '% { left: ' + x + 'px; top: ' + y + 'px; }\n'; 149 } 150 151 function animationNameForIndex(index) { 152 return 'animation-' + index; 153 } 154 155 function Particle(index) 156 { 157 // Create visual element for the particle. 158 var domNode = document.createElement('span'); 159 document.body.appendChild(domNode); 160 161 // Set colour of element. 162 domNode.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; 163 domNode.style.webkitAnimationTimingFunction = 'linear'; 164 domNode.style.webkitAnimationIterationCount = 'infinite'; 165 domNode.style.webkitAnimationDirection = 'alternate'; 166 domNode.style.webkitAnimationDuration = animationDuration + 's'; 167 168 function start() { 169 domNode.style.webkitAnimationName = animationNameForIndex(index); 170 } 171 172 function destroy() 173 { 174 document.body.removeChild(domNode); 175 } 176 177 this.start = start; 178 this.destroy = destroy; 179 } 180 181 function onCompletedRun() { 182 testRunning = false; 183 stopTrackingFrameRate(); 184 185 for (var i = 0; i < particles.length; i++) 186 particles[i].destroy(); 187 particles = []; 188 } 189 </script> 190 <style id="keyframes"></style> 191 </head> 192 </html> 193