Задача: Простая геометрическая и текстовая анимация
Исходник: Простая геометрическая и текстовая анимация, язык: javascript [code #148, hits: 10135]
автор: - [добавлен: 24.05.2006]
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  2. <html>
  3. <head>
  4. <title>Animation demo</title>
  5. <style type="text/css">
  6. #red {
  7. width: 100px;
  8. height: 100px;
  9. margin: 20px;
  10. background-color: #e24900;
  11. font-size: 1px;
  12. }
  13. #green {
  14. width: 100px;
  15. height: 100px;
  16. margin: 20px;
  17. background-color: #3aca02;
  18. font-size: 1px;
  19. }
  20. #text {
  21. border: 1px solid black;
  22. font-family: Verdana;
  23. font-size: 14px;
  24. color: black;
  25. line-height: 15px;
  26. height: 15px;
  27. margin: 20px;
  28. }
  29. </style>
  30. <script type="text/javascript">
  31. <!--
  32. /*============================- Animation queue -==========================*/
  33. AnimationQueue.prototype.settings={
  34. frameDelay: 24
  35. };
  36. /**
  37. * Анимационный поток, представляет собой цепочку анимационных функций,
  38. * запускаеммх с заданной частотой. Можно представить как процессор и тактовый
  39. * генератор =)
  40. */
  41. function AnimationQueue() {
  42. this.anims=[];
  43. this.currentAnim=0;
  44. this.timer=null;
  45. this.waittime=null;
  46. this.fromTime=null;
  47. this.loop=true;
  48. }
  49. /**
  50. * Установить повторение анимации после завершения.
  51. * По теории этого метода не должно быть. Выбираеться дефолтовое действие:
  52. * повторять(у нас так) либо не повторять. Затем если нужно выполнить действие
  53. * не равное дефолтовому, то добавляеться обьект "анимация" в ряд, что и выполнит
  54. * необходимое действие.
  55. * НО! на практике чем меньше телодвижений, тем лучше =)
  56. * @param boolean loop true - поставить повтор, false - отменить повтор
  57. */
  58. AnimationQueue.prototype.setLoop=function(loop) {
  59. this.loop=Boolean(loop);
  60. }
  61. /**
  62. * Установить паузу для следующего "кадра".
  63. * Метод необходим анимациям, работающих гораздо медленней чем "анимационный
  64. * поток". Время задаёться в миллисекундах, но меньше чем шаг аниматора быть не
  65. * может. Чем меньше время, тем мнее точней будет результирующая пауза.
  66. * @param integer ms пауза в миллисекундах
  67. */
  68. AnimationQueue.prototype.wait=function(ms) {
  69. if(typeof(ms)!='number') throw "AnimationQueue.wait: wait time '"+ms+"' must be an integer representing time in milliseconds";
  70. this.waittime=ms;
  71. this.fromTime=(new Date()).getTime();
  72. }
  73. /**
  74. * Следующая анимация.
  75. * Методы вызываеться анимациями, когда текущая полностью завершиться, что бы
  76. * отдать управлениие следующей анимации.
  77. */
  78. AnimationQueue.prototype.next=function() {
  79. if(!this.loop && (++this.currentAnim)>=this.anims.length) this.stop();
  80. else if(this.loop) this.currentAnim=(++this.currentAnim)>=this.anims.length? 0: this.currentAnim;
  81. this.waittime=null;
  82. }
  83. /**
  84. * Добавить анимацию в "анимационный поток".
  85. * Метод добавляет анимации в конец цепочки. Можно добавлять новые анимации после
  86. * вызова start, но это может порождать труднонаходимые глюки =)
  87. * Поэтому набиваем поток анимациями заранее, затем вызываем start() и забываем.
  88. * @param function animation функция аниматор, что будет вызываться каждый проход
  89. * аниматора. Параметром получает ссылку на обьект аниматора.
  90. */
  91. AnimationQueue.prototype.add=function(animation) {
  92. if(!(animation instanceof Function)) throw "AnimationQueue.add: given animation object '"+animation+"' is not a function!";
  93. this.anims[this.anims.length]=animation;
  94. }
  95. /**
  96. * Запустить анимационный поток.
  97. * Выполнение продолжаеться с момента остановки. Параметром можно указать с какой
  98. * анимации начинать выполнение, отсчёт от 0
  99. * @param integer порядковый номер стартовой анимации с 0
  100. */
  101. AnimationQueue.prototype.start=function(initAnim) {
  102. if(this.timer!=null||this.anims.length<1) return;
  103. if(typeof(initAnim)=='number') this.currentAnim=initAnim;
  104. this.currentAnim=this.currentAnim<0? 0: this.currentAnim>=this.anims.length? this.anims.length-1: this.currentAnim;
  105. var animator=this;
  106. this.timer=window.setInterval(function() {
  107. if(animator.waittime!=null) {
  108. if(((new Date()).getTime()-animator.fromTime)<animator.waittime) return;
  109. animator.waittime=null;
  110. }
  111. animator.anims[animator.currentAnim](animator);
  112. }, this.settings.frameDelay);
  113. }
  114. /**
  115. * Остановить анимационный поток.
  116. * Все анимации сохраняют своё состояние! Проще говоря останавливаеться главный
  117. * таймер, функции-анимации просто перестают регулярно вызываться. При следующем
  118. * вызове start() выполнение продолжиться со состояния на момент stop().
  119. */
  120. AnimationQueue.prototype.stop=function() {
  121. window.clearInterval(this.timer);
  122. }
  123. /*===============================- Animation Delay -=======================*/
  124. /**
  125. * Анимация - пауза.
  126. * Этот обьект-обёртка понадобился для работы с паузами в пакетах
  127. * анимаций(см. ниже). Представляеться как обычная анимационная функция.
  128. * Передаёт управление по прошествии определённого интервала времени.
  129. * Пауза срабатывает только один раз, для повторяющихся пауз нужно задать третьим
  130. * параметром true.
  131. * Вызов setDelay сбрасывает текущую паузу и устанавливает новую.
  132. * @param function anim анимационная функция
  133. * @param interger msc задержка в миллисекундах
  134. * @param boolean continous true - разрешить постоянную паузу, false(default) - отменить постоянную паузу
  135. * @return function результирующая анимационная функция
  136. */
  137. function AnimationDelay(anim, msc, continous) {
  138. var a=function(animator) {
  139. if(arguments.callee.waittime!=null) {
  140. if(((new Date()).getTime()-arguments.callee.fromTime)<arguments.callee.waittime) return;
  141. if(continous) arguments.callee.setDelay(msc);
  142. else arguments.callee.waittime=null;
  143. }
  144. anim(animator);
  145. }
  146. a.setDelay=function(ms) {
  147. if(typeof(ms)!='number') throw "AnimationDelay.setDelay: wait time '"+ms+"' must be an integer representing time in milliseconds";
  148. this.waittime=ms;
  149. this.fromTime=(new Date()).getTime();
  150. }
  151. a.setDelay(msc);
  152. }
  153. /*==============================- Animation Set -==========================*/
  154. /**
  155. * Обьединение анимаций по времени.
  156. * Иногда(часто =)) требуеться запустить несколько анимаций одновременно. Обьект
  157. * обьединяет анимации в одну. Выход из обьединения произойдёт после того как все
  158. * анимации вызовут либо next(), либо stop(). Если анимация вызвала
  159. * next()/stop(), то она удаляеться из списка анимаций и при следующем проходе
  160. * вызванна не будет.
  161. * @param array масив с функциями-анимациями, что будут выполняться одновременно
  162. * @return function результирующая анимационная функция
  163. */
  164. function AnimationSet(set) {
  165. return function(anim) {
  166. var animator={}, hasn=false;
  167. for(var i=0; i<set.length; i++) {
  168. if(!set[i]) {
  169. if(i<set.length-1||hasn) continue;
  170. else {anim.next(); return;}
  171. }
  172. hasn=true;
  173. animator.next=animator.stop=function() { set[i]=null; }
  174. animator.wait=function(ms) {
  175. if(!set[i].setDelay) set[i]=AnimationDelay(set[i], ms);
  176. else set[i].setDelay(ms);
  177. }
  178. set[i](animator);
  179. }
  180. }
  181. }
  182. /*=========================- Анимационные функции -=======================*/
  183. /**
  184. * Простая анимация создающая задержку в миллисекундах.
  185. * @param integer ms пауза в миллисекундах
  186. */
  187. function waitAnimation(ms) {
  188. var w=false;
  189. return function(animator) {
  190. if(w) {animator.next(); w=false;}
  191. animator.wait(ms);
  192. w=true;
  193. }
  194. }
  195. /**
  196. * Анимация изменяющая размер обьекта.
  197. * Изначальный размер обьекта вычисляеться при первом "кадре". Далее эти размеры
  198. * подгоняються под заданные.
  199. * Параметрами задаёться целевой обьект, размеры и время, за которое анимация
  200. * должна выполниться.
  201. * Внимание: время всегда используеться чуть больше чем заданно, т.к. анимация
  202. * на сложных обьектах браузера всё таки жутко не эффективная работа =)
  203. * @param AnimationQueue thread анимационный поток в котором будем исполняться
  204. * @param integer time длительность анимации
  205. * @param HTMLElement obj целевой обьект
  206. * @param integer width требуемая ширина обьекта
  207. * @param integer height требуемая высота обьекта
  208. */
  209. function resizeAnimation(thread, time, obj, width, height) {
  210. var steps=Math.ceil(time/thread.settings.frameDelay);
  211. var currstep=1;
  212. var owidth, oheight, hstep, wstep;
  213. return function(animator) {
  214. if(typeof(owidth)!='number') {
  215. owidth=obj.offsetWidth;
  216. oheight=obj.offsetHeight;
  217. wstep=(width-owidth)/steps;
  218. hstep=(height-oheight)/steps;
  219. }
  220. if(currstep>steps) {
  221. obj.style.width=width+'px';
  222. obj.style.height=height+'px';
  223. animator.next();
  224. return;
  225. }
  226. obj.style.width=Math.round(owidth+wstep*currstep)+'px';
  227. obj.style.height=Math.round(oheight+hstep*currstep)+'px';
  228. currstep++;
  229. }
  230. }
  231. /**
  232. * Простая анимация "печатаемого текста".
  233. * Заданная строка "печатаеться" через innerHTML в целевом обьекте.
  234. */
  235. function typeAnimation(obj, text, timedelay) {
  236. var len=0;
  237. return function(animator) {
  238. animator.wait(timedelay);
  239. if(++len>text.length) {len=0; animator.next();}
  240. else obj.innerHTML=text.substring(0, len);
  241. }
  242. }
  243. /*==============================- Задаём анимации -=======================*/
  244. var a, b; //два анимационных потока
  245. function initAnimations() {
  246. a=new AnimationQueue(); //тред для квадратов
  247. a.setLoop(false); //будем крутить только один раз
  248. b=new AnimationQueue(); //а тред для текста бесконечно
  249.  
  250. //добавляем две анимации, исполняемые друг за другом
  251. a.add(resizeAnimation(a, 1000, document.getElementById('red'), 400, 200));
  252. a.add(resizeAnimation(a, 2500, document.getElementById('green'), 400, 300));
  253.  
  254. //а эти две анимации будут исполняться параллельно
  255. var pack=[
  256. resizeAnimation(a, 2000, document.getElementById('red'), 10, 10),
  257. resizeAnimation(a, 2000, document.getElementById('green'), 10, 10)
  258. ];
  259. a.add(AnimationSet(pack));
  260.  
  261. //анимации для текста в отдельном потоке
  262. b.add(typeAnimation(document.getElementById('text'), "Текст печаетаеться со скоростью десять букв в секунду", 100));
  263. b.add(typeAnimation(document.getElementById('text'), "А этот со скоростью три буквы в секунду", 300));
  264. b.add(typeAnimation(document.getElementById('text'), "Можно ещё быстрей, пауза всего 50 миллисекунд", 50));
  265. b.add(waitAnimation(1000)); //подождём секунду, замечаем что это тоже анимация ;-)
  266. //теперь весь бутерброд запускаем =)
  267. a.start();
  268. b.start();
  269. }
  270. function stopAnimations() {
  271. a.stop();
  272. b.stop();
  273. a=b=null;
  274. }
  275. //-->
  276. </script>
  277. </head>
  278. <body>
  279. <div id="red"></div>
  280. <div id="green"></div>
  281. <div id="text"></div>
  282. <button onclick="initAnimations()">Start</button>&nbsp;&nbsp;
  283. <button onclick="stopAnimations()">Stop</button>
  284. </body>
  285. </html>
Анимируются(меняются) размеры разноцветных прямоугольников + буква за буквой высвечивается текст.

Найдено на forum.vingrad.ru
Тестировалось на: IE 6.0 SP2, Mozilla FF 1.5, Opera 8.5

+добавить реализацию