14. Обработка событий

Примеры

Пример 01. Тестируем всплытие

praxis/14/examples/01/index.htm

Содержимое файла index.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
  "http://www.w3.org/TR/html4/loose.dtd">
<HTML id="html" lang="ru">
  <HEAD>
    <META http-equiv="Content-Type" 
          content="text/html; charset=windows-1251">
    <META http-equiv="imagetoolbar" content="no">
    <SCRIPT type="text/javascript" src="main.js"></SCRIPT>
    <TITLE>Тестируем всплытие</TITLE>
  </HEAD>
  <BODY id="body">
    <H1>Тестируем всплытие</H1>

    <P id="p">
<IMG id="pic" src="pic/pic.png" width=119 height=91 alt="" title="">
    </P>

    <H2>Протокол работы обработчиков событий</H2>

  </BODY>
</HTML>

Содержимое файла main.js


// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа 
// и построения DOM  
window.onload = function ()
{
 // Назначим единственный обработчик события всем объектам
  document.getElementById("pic").onclick = say;
  document.getElementById("p").onclick = say;
  document.getElementById("body").onclick = say;
  document.getElementById("html").onclick = say;
 
 // Сам обработчик
 function say()
 {
   var text = "id элемента: " + this.id;
   appendP(text); // Добавим абзац в документ
 }

  // Добавить абзац к документу
  function appendP(text)
  {
    // Создадим элемент "абзац"
    var el = document.createElement("p"); 
    // Добавим к созданному элементу потомка -- текстовый элемент 
    el.appendChild(document.createTextNode(text));
    // Добавим построенный элемент к BODY -- и он сразу отобразится на экране
    document.body.appendChild(el);
  }
};
Пример 02. Тестируем распространение события (захват и всплытие)

praxis/14/examples/02/index.htm (не работает в IE)

Содержимое файла index.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
  "http://www.w3.org/TR/html4/loose.dtd">
<HTML id="html" lang="ru">
  <HEAD>
    <META http-equiv="Content-Type" 
          content="text/html; charset=windows-1251">
    <META http-equiv="imagetoolbar" content="no">
    <SCRIPT type="text/javascript" src="main.js"></SCRIPT>
    <TITLE>Тестируем распространение события</TITLE>
  </HEAD>
  <BODY id="body">
    <H1>Тестируем распространение события</H1>
    
    <P id="p">
<IMG id="pic" src="pic/pic.png" width=119 height=91 alt="" title="">
    </P>

    <H2>Протокол работы обработчиков событий</H2>

  </BODY>
</HTML>

Содержимое файла main.js


// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа 
// и построения DOM  
window.onload = function ()
{
 // Назначим обработчик события объектам на фазе захвата
  document.getElementById("pic").addEventListener("click",say1,true);
  document.getElementById("p").addEventListener("click",say1,true);
  document.getElementById("body").addEventListener("click",say1,true);
  document.getElementById("html").addEventListener("click",say1,true);
 
 // Назначим обработчик события объектам на фазе всплытия
  document.getElementById("pic").addEventListener("click",say2,false);
  document.getElementById("p").addEventListener("click",say2,false);
  document.getElementById("body").addEventListener("click",say2,false);
  document.getElementById("html").addEventListener("click",say2,false);

 // Обработка на этапе захвата
 function say1()
 {
   var text = "Захват, id элемента: " + this.id;
   appendP(text); // Добавим абзац в документ
 }
 // Обработка на этапе всплытия
 function say2()
 {
   var text = "Всплытие, id элемента: " + this.id;
   appendP(text); // Добавим абзац в документ
 }

  // Добавить абзац к документу
  function appendP(text)
  {
    // Создадим элемент "абзац"
    var el = document.createElement("p"); 
    // Добавим к созданному элементу потомка -- текстовый элемент 
    el.appendChild(document.createTextNode(text));
    // Добавим построенный элемент к BODY -- и он сразу отобразится на экране
    document.body.appendChild(el);
  }
};
Пример 03. Картинки, которые возвращаются (не работает в IE)

praxis/14/examples/03/index.htm

Содержимое файла index.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
  "http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
  <HEAD>
    <META http-equiv="Content-Type" 
          content="text/html; charset=windows-1251">
    <META http-equiv="imagetoolbar" content="no">
    <LINK rel="stylesheet" type="text/css" href="main.css">
    <SCRIPT type="text/javascript" src="animateCSS.js"></SCRIPT>
    <SCRIPT type="text/javascript" src="main.js"></SCRIPT>
    <TITLE>Картинки, которые возвращаются</TITLE>
  </HEAD>
  <BODY>
    <H1>Картинки, которые возвращаются</H1>

    <P>
<IMG src="pic/06.png" width=119 height=91 alt="" title="">
На этой странице много картинок. Их можно перетаскивать мышью в 
любое место окна. Когда перетаскивание завершается, картинка 
возвращается на прежнее место. Однако HTML-код совершенно не в курсе,
что для картинок на странице задано такое поведение. Все делает 
скрипт, подключенный к странице.

    <P>
<IMG src="pic/00.png" width=364 height=55 alt="" title="">

    <P>
<IMG src="pic/01.png" width=65  height=106 alt="" title="">
<IMG src="pic/02.png" width=56  height=96  alt="" title="">
<IMG src="pic/03.png" width=105 height=103 alt="" title="">
<IMG src="pic/04.png" width=98  height=74  alt="" title="">
<IMG src="pic/05.png" width=107 height=104 alt="" title="">
    </P>
  </BODY>
</HTML>

Содержимое файла main.js


// ===================================================================
// Cкрипт, который после подключения к странице, позволяет все 
// картинки на странице перетаскивать мышью. По окончанию 
// перетаскивания, картинка самостоятельно возвращается на прежнее 
// место по сложной траектории. Этот скрипт наделяет таким 
// свойством любую страницу, к которой подключается, без каких 
// либо дополнительных разметок на этой страницы.
// 
// Это скрипт работает во всех браузерах кроме IE.
// ===================================================================

// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа 
// и построения его объектной модели 
window.onload = function ()
{
  // Назначим обработчики события mousedown на все картинки страницы
  // и зададим для них относительное позиционирование 
  for(var i=0; i<document.images.length; i++)
  {
    // Обработка нажатия кнопки мыши
    document.images[i].onmousedown = downHandler;
    // Назначим относительное позиционирование 
    document.images[i].style.position = "relative";
  }
  
  // Общие переменные
  var xStartMouse, yStartMouse; // Координаты мыши во время нажатия на кнопку
  var element;  // Элемент на котором выполнено нажатие на кнопку
  var isСomeBack = false; // Картинка двигается на место?

  // Обработать нажатие кнопки мыши  
  function downHandler(event)
  {
    if(!isСomeBack) // Реагировать только на неподвижную картинку
    {               // (игнорировать щелчок по двигающейся картинке)

      // Работа началась, щелчки не обрабатывать
      isСomeBack = true; 
      // Запомним элемент, на котором выполнено нажатие на кнопку
      element = this;
  
      // Сохраним координаты мыши во время нажатия на кнопку
      xStartMouse = event.clientX;
      yStartMouse = event.clientY;

      // Поднимем картинку на слой выше
      this.style.zIndex = 1;

      // Зарегистрируем обработчики событий mousemove и mouseup, 
      // которые последуют за событием mousedown. Зарегистрируем эти 
      // события на весь документ, так как перетаскиваемый объект может 
      // не поспевать за указателем мыши, и события возникнут вне его.
      // В методе addEventListener укажем true, что будет означать 
      // обработку события на фазе захвата.
      document.addEventListener("mousemove", moveHandler, true);
      document.addEventListener("mouseup", upHandler, true);
    
      // Событие mousedown обработано, прервём 
      // его дальнейшее распространение
      event.stopPropagation();
    
      // На всякий случай запретим действие по умолчанию 
      event.preventDefault();
    }
  }

  // Обработать перемещение мыши  
  function moveHandler(event)
  {
     // Переместить элемент в текущие координаты указателя мыши
     element.style.left = event.clientX-xStartMouse + "px";
     element.style.top  = event.clientY-yStartMouse + "px";
   
     // Прервать дальнейшее распространение события
     event.stopPropagation();
  }

  // Обработать заключительное событие -- отпускание кнопки мыши  
  function upHandler(event)
  {
    // Удалить обработчики событий mouseup и mousemove 
    document.removeEventListener("mousemove", moveHandler, true);
    document.removeEventListener("mouseup", upHandler, true);

     // Прервать дальнейшее распространение события
     event.stopPropagation();

    // Запустить анимацию, которая возвратит элемент на место
    toHome();
  }

  function toHome()
  {
    var numFrames = 100; // Число кадров в анимации картинки
    var v0 = 10;         // Начальная скорость картинки
    // Коодинаты картинки относительно её исходного положения, 
    // которое есть (0,0). Функция parseInt забирает число, отбрасывая "px"
    var left  = parseInt(element.style.left); 
    var top   = parseInt(element.style.top);
    // Вычисляем ускорения по двум направлениям
    var aLeft = (Math.abs(left)-v0*numFrames)/(numFrames*numFrames);
    var aTop  = (Math.abs(top)-v0*numFrames)/(numFrames*numFrames);
    // Запускаем анимацию
    animateCSS(element, numFrames, 10, 
               {
                 left: function(frame,time) 
                 { 
                   return (left-sign(left)*(v0*frame+aLeft*frame*frame))+"px";
                 },
                 top: function(frame,time) 
                 { 
                   return (top-sign(top)*(v0*frame+aTop*frame*frame))+"px";
                 }
               }, function ()
                  {
                    // Картинка закончила движение
                    isСomeBack = false; // Теперь ее снова можно двигать  
                    // Подровняем картинку на её законном месте
                    element.style.left = element.style.top = 0;
                    // Поставим её в свой слой 
                    element.style.zIndex = 0;
                  });
  }
 // Функция, вычисляющая знак числа 
 function sign(a) { return a<0 ? -1:1;}
};
Пример 04. Картинки, которые возвращаются

praxis/14/examples/04/index.htm

Содержимое файла index.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
  "http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
  <HEAD>
    <META http-equiv="Content-Type" 
          content="text/html; charset=windows-1251">
    <META http-equiv="imagetoolbar" content="no">
    <LINK rel="stylesheet" type="text/css" href="main.css">
    <SCRIPT type="text/javascript" src="animateCSS.js"></SCRIPT>
    <SCRIPT type="text/javascript" src="main.js"></SCRIPT>
    <TITLE>Картинки, которые возвращаются</TITLE>
  </HEAD>
  <BODY>
    <H1>Картинки, которые возвращаются</H1>

    <P>
<IMG src="pic/06.png" width=119 height=91 alt="" title="">
На этой странице много картинок. Их можно перетаскивать мышью в 
любое место окна. Когда перетаскивание завершается, картинка 
возвращается на прежнее место. Однако HTML-код совершенно не в курсе,
что для картинок на странице задано такое поведение. Все делает 
скрипт, подключенный к странице.

    <P>
<IMG src="pic/00.png" width=364 height=55 alt="" title="">

    <P>
<IMG src="pic/01.png" width=65  height=106 alt="" title="">
<IMG src="pic/02.png" width=56  height=96  alt="" title="">
<IMG src="pic/03.png" width=105 height=103 alt="" title="">
<IMG src="pic/04.png" width=98  height=74  alt="" title="">
<IMG src="pic/05.png" width=107 height=104 alt="" title="">
    </P>
  </BODY>
</HTML>

Содержимое файла main.js


// ===================================================================
// Cкрипт, который после подключения к странице, позволяет все 
// картинки на странице перетаскивать мышью. По окончанию 
// перетаскивания, картинка самостоятельно возвращается на прежнее 
// место по сложной траектории. Этот скрипт наделяет таким 
// свойством любую страницу, к которой подключается, без каких 
// либо дополнительных разметок на этой страницы.
// 
// Это скрипт работает во всех браузерах (и в IE).
// ===================================================================

// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа 
// и построения его объектной модели 
window.onload = function ()
{
  // Назначим обработчики события mousedown на все картинки страницы
  // и зададим для них относительное позиционирование 
  for(var i=0; i<document.images.length; i++)
  {
    // Обработка нажатия кнопки мыши
    document.images[i].onmousedown = downHandler;
    // Назначим относительное позиционирование 
    document.images[i].style.position = "relative";
  }
  
  // Общие переменные
  var xStartMouse, yStartMouse; // Координаты мыши во время нажатия на кнопку
  var element;  // Элемент на котором выполнено нажатие на кнопку
  var isСomeBack = false; // Картинка двигается на место?

  // -------------- для IE-4 -----------------------------------------
  // Переменные, в которых будем хранить старые значения     
  // свойств mousemove и mouseup. Вместо удаления соответствующих        
  // событий (удаление нет в IE-4) будем возвращать сохранненные значения 
  var oldMoveHandler; 
  var oldUpHandler;   
  // -----------------------------------------------------------------
  
  // Обработать нажатие кнопки мыши  
  function downHandler(event)
  {
    if(!isСomeBack) // Реагировать только на неподвижную картинку
    {               // (игнорировать щелчок по двигающейся картинке)

      // Если аргумент не передан, это IE, и тогда присвоим локальной 
      // переменной event ссылку на глобальный объект window.event,
      // в котором IE хранит свойства события.
      event = event || window.event; 

      // Работа началась, щелчки не обрабатывать
      isСomeBack = true; 

      // Запомним элемент, на котором выполнено нажатие на кнопку
      element = this;
  
      // Сохраним координаты мыши во время нажатия на кнопку
      xStartMouse = event.clientX;
      yStartMouse = event.clientY;

      // Поднимем картинку на слой выше
      this.style.zIndex = 1;

      // Зарегистрируем обработчики событий mousemove и mouseup, 
      // которые последуют за событием mousedown. Зарегистрируем эти 
      // события на весь документ, так как перетаскиваемый объект может 
      // не поспевать за указателем мыши, и события возникнут вне его.
      if (document.addEventListener) // Если работает модель DOM W3C
      {
         // В методе addEventListener укажем true, что будет означать 
         // обработку события на фазе захвата.
         document.addEventListener("mousemove", moveHandler, true);
         document.addEventListener("mouseup", upHandler, true);
      }
      else if (document.attachEvent) // Если работает модель IE5+ 
      {
         // В модели IE5+ перехват события производится вызовом 
         // метода setCapture элемента, выполняющего перехват.
         // После вызова этого метода все события мыши будут направляться
         // элементу до отмена перехвата (метод releaseCapture)
         element.setCapture();
         document.attachEvent("onmousemove", moveHandler);
         document.attachEvent("onmouseup", upHandler);
         // Интерпретировать событие потери перехвата как событие mouseup.
         // Потеря перехвата может случится в результате потери браузером
         // фокуса ввода, появления модального окна (например, alert),
         // отображения системного меню и в других подобных случаях.
         document.attachEvent("onlosecapture", upHandler);
      }   
      else // Модель событий IE4
      {
         // В модели IE4 нельзя использовать attachEvent и setCapture, 
         // поэтому вставляем обработчики и надеемся на то, что   
         // требуемые события мыши всплывут к объекту document.
         // Предварительно сохраним значения событийных свойств.  
         oldMoveHandler = document.onmousemove; 
         oldUpHandler   = document.onmouseup;
         document.onmousemove = moveHandler;
         document.onmouseup = upHandler;
      }
    
      // Событие mousedown обработано, прервём 
      // его дальнейшее распространение
      if(event.stopPropagation) // Если работает модель DOM W3C
        event.stopPropagation();      // DOM W3C
      else event.cancelBubble = true; // IE
    
      // На всякий случай запретим действие по умолчанию 
      if(event.preventDefault) // Если работает модель DOM W3C
         event.preventDefault();      // DOM W3C
      else event.returnValue = false; // IE
    }
  }

  // Обработать перемещение мыши  
  function moveHandler(event)
  {
    // Если аргумент не передан, это IE, и тогда присвоим локальной 
    // переменной event ссылку на глобальный объект window.event,
    // в котором IE хранит свойства события.
    event = event || window.event; 
  
     // Переместить элемент в текущие координаты указателя мыши
     element.style.left = event.clientX-xStartMouse + "px";
     element.style.top  = event.clientY-yStartMouse + "px";
   
     // Прервать дальнейшее распространение события
      if(event.stopPropagation) // Если работает модель DOM W3C
        event.stopPropagation();      // DOM W3C
      else event.cancelBubble = true; // IE
  }

  // Обработать заключительное событие -- отпускание кнопки мыши  
  function upHandler(event)
  {
    // Если аргумент не передан, это IE, и тогда присвоим локальной 
    // переменной event ссылку на глобальный объект window.event,
    // в котором IE хранит свойства события.
    event = event || window.event; 

     // Удалить обработчики событий mouseup и mousemove 
     if(document.removeEventListener) // Если работает модель DOM W3C
     {
       document.removeEventListener("mousemove", moveHandler, true);
       document.removeEventListener("mouseup", upHandler, true);
     }
     else if(document.detachEvent) // Если работает модель IE5+
     {
       document.detachEvent("onlosecapture", upHandler);
       document.detachEvent("onmouseup", upHandler);
       document.detachEvent("onmousemove", moveHandler);
       // Остановим перенаправление событий мыши к элементу
       element.releaseCapture();  
     }  
     else // Модель событий IE4
     {
        // Восстановить первоначальное значение событийных свойств
        document.onmousemove = oldMoveHandler; 
        document.onmouseup = oldUpHandler;
      }

     // Прервать дальнейшее распространение события
      if(event.stopPropagation) // Если работает модель DOM W3C
        event.stopPropagation();      // DOM W3C
      else event.cancelBubble = true; // IE

    // Запустить анимацию, которая возвратит элемент на место
    toHome();
  }

  function toHome()
  {
    var numFrames = 100; // Число кадров в анимации картинки
    var v0 = 10;         // Начальная скорость картинки
    // Коодинаты картинки относительно её исходного положения, 
    // которое есть (0,0). Функция parseInt забирает число, отбрасывая "px"
    var left  = parseInt(element.style.left); 
    var top   = parseInt(element.style.top);
    // Вычисляем ускорения по двум направлениям
    var aLeft = (Math.abs(left)-v0*numFrames)/(numFrames*numFrames);
    var aTop  = (Math.abs(top)-v0*numFrames)/(numFrames*numFrames);
    // Запускаем анимацию
    animateCSS(element, numFrames, 10, 
               {
                 left: function(frame,time) 
                 { 
                   return (left-sign(left)*(v0*frame+aLeft*frame*frame))+"px";
                 },
                 top: function(frame,time) 
                 { 
                   return (top-sign(top)*(v0*frame+aTop*frame*frame))+"px";
                 }
               }, function ()
                  {
                    // Картинка закончила движение
                    isСomeBack = false; // Теперь ее снова можно двигать  
                    // Подровняем картинку на её законном месте
                    element.style.left = element.style.top = 0;
                    // Поставим её в свой слой 
                    element.style.zIndex = 0;
                  });
  }
 // Функция, вычисляющая знак числа 
 function sign(a) { return a<0 ? -1:1;}
};
Пример 05. Почти Арканоид (ракетка)

praxis/14/examples/05/index.htm

Содержимое файла index.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
  "http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
  <HEAD>
    <META http-equiv="Content-Type" 
          content="text/html; charset=windows-1251">
    <META http-equiv="imagetoolbar" content="no">
    <LINK rel="stylesheet" type="text/css" href="main.css">
    <SCRIPT type="text/javascript" src="main.js"></SCRIPT>
    <TITLE>Почти Арканоид</TITLE>
  </HEAD>
  <BODY>
    <H1>Почти Арканоид</H1>

    <DIV id="field">
      <IMG id="ball" src="pic/disc.gif" width=11 height=11 alt="" title="">
      <DIV id="racket"><IMG src="pic/empty.gif" 
                            width=1 height=1 alt="" title=""></DIV>
    </DIV>
     
    <P>
Старт&nbsp;&#8212; пробел<BR>
Ракетка&nbsp;&#8212; стрелки
    </P>
  </BODY>
</HTML>

Содержимое файла main.js


// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа 
// и построения его объектной модели 
window.onload = function ()
{
  // =================== Константы и переменные ======================
  // Размеры игрового поля
  var widthField  = 600;
  var heightField = 400;
  // Размеры ракетки
  var widthRacket  = 100;
  var heightRacket = 10;
  // Движение ракетки
  var step0Racket=5;      // Начальный шаг смещения ракетки
  var stepMaxRacket=10;   // Максимальный шаг смещения ракетки
  var stepRacket=step0Racket; // Текущий шаг смещения ракетки
  var aRacket=1.05; // Ускорение: stepRacket *= aRacket на каждом шаге 
  var dtRacket = 10;      //  Временной интервал перерисовки ракетки
  var timerRacket = null; //  Таймер для движения ракетки
  var dirMoveRacket = 0;  // -1 -- ракетка двигается влево
                          //  0 -- ракетка стоит на месте
                          //  1 -- ракетка двигается вправо
  
  // =================== Ссылки на объекты ===========================
  // Ссылки на объекты
  var field  = document.getElementById("field");  // Поле
  var racket = document.getElementById("racket"); // Ракетка
  // =================================================================
  
  // =================== Представление ===============================
  // Стили игрового поля
  field.style.width  = widthField+"px";
  field.style.height = heightField+"px";

  // Стили ракетки
  racket.style.width  = widthRacket+"px";
  racket.style.height = heightRacket+"px";
  racket.style.left   = 0;
  // =================================================================

  // =================== Обработчики событий =========================
  document.onkeydown = keydownHandler; // Нажата клавиша
  document.onkeyup = keyupHandler;     // Отпущена клавиша
  
  // =================== Нажата клавиша ========================
  function keydownHandler(event)
  {
    event = event || window.event;
    switch(event.keyCode)
    {
      case 37: // Стрелка влево -------------------------------------
        if(timerRacket)       // Если ракетка уже двигается влево,
        {                     // то игнорировать нажатие. 
          if(dirMoveRacket == -1) return;
          clearMoveRacket();  // В противном случае (когда вправо),
        }                     // прекратить движение
        // Запустим движение ракетки влево 
        dirMoveRacket = -1;   
        timerRacket = setInterval(leftRacket, dtRacket);
        break;
      case 39: // Стрелка вправо ------------------------------------
        if(timerRacket)       // Если ракетка уже двигается вправо,       
        {                     // то игнорировать нажатие.                
          if(dirMoveRacket == 1) return;
          clearMoveRacket();  // В противном случае (когда влево),   
        }                     // прекратить движение                  
        // Запустим движение ракетки влево 
        dirMoveRacket = 1;
        timerRacket = setInterval(rightRacket, dtRacket);
        break;
      case 32: // Пробел ---------------------------------------------
      start();
    }
  }

  // =================== Отпущена клавиша ========================
  function keyupHandler(event)
  {
    if(!timerRacket) return; // Если движения ракетки нет, игнорировать  
    event = event || window.event; 
    // Остановить движение ракетки в каждом из двух случаев:
    // 1) Отпущена стрелка влево в тот момент, когда ракетка двигается влево
    // 2) Отпущена стрелка вправо в тот момент, когда ракетка двигается вправо
    var stop = false;
    if((event.keyCode == 37 // Отжата стрелка влево, когда ракетка двигается влево
        && dirMoveRacket == -1) || // или 
       (event.keyCode == 39 // Отжата стрелка вправо, когда ракетка двигается вправо
        && dirMoveRacket == 1)) stop = true; 
    if(stop) clearMoveRacket();
  }  
  
  // =================== Остановить движение ракетки =================
  function clearMoveRacket()
  {
    // Прервать работу таймера
    clearInterval(timerRacket); 
    timerRacket = null;         
    // Восстановить начальный шаг смещения ракетки
    stepRacket  = step0Racket;  
    // Сбросить флаг направления движения ракетки
    dirMoveRacket = 0;
  }
  // =================== Ракетка на шаг влево =================
  function leftRacket()
  {
    var x = parseInt(racket.style.left);
    if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
    if(x-stepRacket > 0) racket.style.left = (x-stepRacket)+"px"; 
    else racket.style.left = 0;
  }
  // =================== Ракетка на шаг вправо =================
  function rightRacket()
  {
   var x = parseInt(racket.style.left);
   if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
   if(x+widthRacket+stepRacket < widthField) racket.style.left = (x+stepRacket)+"px"; 
   else racket.style.left = (widthField-widthRacket)+"px";
  }

  // =================== Старт игры =========================
  function start()
  {
    alert("старт")
  }
  
};
Пример 06. Почти Арканоид (ракетка + шарик)

praxis/14/examples/06/index.htm

Содержимое файла index.htm


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
  "http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="ru">
  <HEAD>
    <META http-equiv="Content-Type" 
          content="text/html; charset=windows-1251">
    <META http-equiv="imagetoolbar" content="no">
    <LINK rel="stylesheet" type="text/css" href="main.css">
    <SCRIPT type="text/javascript" src="animateCSS.js"></SCRIPT>
    <SCRIPT type="text/javascript" src="main.js"></SCRIPT>
    <TITLE>Почти Арканоид</TITLE>
  </HEAD>
  <BODY>
    <H1>Почти Арканоид</H1>

    <DIV id="field">
      <IMG id="ball" src="pic/disc.gif" width=11 height=11 alt="" title="">
      <DIV id="racket"><IMG src="pic/empty.gif" 
                            width=1 height=1 alt="" title=""></DIV>
    </DIV>
     
    <DIV id="time">Время игры</DIV>
    <DIV id="record">Рекорд</DIV>

    <P>
Старт&nbsp;&#8212; пробел<BR>
Ракетка&nbsp;&#8212; стрелки
    </P>
  </BODY>
</HTML>

Содержимое файла main.js


// Почти Арканоид
// (C) март 2010 А.А.Дуванов
//  ------------------------
// Обработчик события onload
// Функциональный литерал будет вызван после полной загрузки документа 
// и построения его объектной модели 
window.onload = function ()
{
  // =================== Константы и переменные ======================
  // Размеры игрового поля
  var widthField  = 600;
  var heightField = 400;
  // Размеры ракетки
  var widthRacket  = 100;
  var heightRacket = 10;
  // Движение ракетки
  var step0Racket=5;      // Начальный шаг смещения ракетки
  var stepMaxRacket=10;   // Максимальный шаг смещения ракетки
  var stepRacket=step0Racket; // Текущий шаг смещения ракетки
  var aRacket=1.05; // Ускорение: stepRacket *= aRacket на каждом шаге 
  var dtRacket = 10;      // Временной интервал перерисовки ракетки
  var timerRacket = null; // Таймер для движения ракетки
  var dirMoveRacket = 0;  // -1 -- ракетка двигается влево
                          //  0 -- ракетка стоит на месте
                          //  1 -- ракетка двигается вправо
  // Шарик                       
  var widthBall  = 11;
  var heightBall = 11;
  var ismoveBall = false; // true, если шарик в игре
  var timerBall  = null;  // Таймер для шарика
  var dtBall     = 10;    // Временной интервал перерисовки шарика
  var fiBall;             // Угол, под которым двигается шарик
  var dx0Ball    = 6;     // Начальная величина шага шарика по горизонтали
  var dy0Ball    = -6;    // Начальная величина шага шарика по вертикали
  var dxBall;             // Величина шага движения шарика по горизонтали
  var dyBall;             // Величина шага движения шарика по вертикали

  // Время игры и рекорд
  var timeGame; 
  var timeRecord=0; 


  // =================== Ссылки на объекты ===========================
  // Ссылки на объекты
  var field  = document.getElementById("field");  // Поле
  var racket = document.getElementById("racket"); // Ракетка
  var ball   = document.getElementById("ball");   // Шарик
  var time   = document.getElementById("time");   // Время игры
  var record = document.getElementById("record"); // Рекорд
  // =================================================================
  
  // =================== Представление ===============================
  // Стили игрового поля
  field.style.width  = widthField+"px";
  field.style.height = heightField+"px";

  // Стили ракетки
  racket.style.width  = widthRacket+"px";
  racket.style.height = heightRacket+"px";
  racket.style.left   = 0;

  // Стили шарика
  ball.style.visibility = "hidden";
  // =================================================================

  // =================== Обработчики событий =========================
  document.onkeydown = keydownHandler; // Нажата клавиша
  document.onkeyup = keyupHandler;     // Отпущена клавиша
  
  // =================== Нажата клавиша ========================
  function keydownHandler(event)
  {
    event = event || window.event;
    switch(event.keyCode)
    {
      case 37: // Стрелка влево -------------------------------------
        if(timerRacket)       // Если ракетка уже двигается влево,
        {                     // то игнорировать нажатие. 
          if(dirMoveRacket == -1) return;
          clearMoveRacket();  // В противном случае (когда вправо),
        }                     // прекратить движение
        // Запустим движение ракетки влево 
        dirMoveRacket = -1;   
        timerRacket = setInterval(leftRacket, dtRacket);
        break;
      case 39: // Стрелка вправо ------------------------------------
        if(timerRacket)       // Если ракетка уже двигается вправо,       
        {                     // то игнорировать нажатие.                
          if(dirMoveRacket == 1) return;
          clearMoveRacket();  // В противном случае (когда влево),   
        }                     // прекратить движение                  
        // Запустим движение ракетки влево 
        dirMoveRacket = 1;
        timerRacket = setInterval(rightRacket, dtRacket);
        break;
      case 32: // Пробел ---------------------------------------------
      start();
    }
  }

  // =================== Отпущена клавиша ========================
  function keyupHandler(event)
  {
    if(!timerRacket) return; // Если движения ракетки нет, игнорировать  
    event = event || window.event; 
    // Остановить движение ракетки в каждом из двух случаев:
    // 1) Отпущена стрелка влево в тот момент, когда ракетка двигается влево
    // 2) Отпущена стрелка вправо в тот момент, когда ракетка двигается вправо
    var stop = false;
    if((event.keyCode == 37 // Отжата стрелка влево, когда ракетка двигается влево
        && dirMoveRacket == -1) || // или 
       (event.keyCode == 39 // Отжата стрелка вправо, когда ракетка двигается вправо
        && dirMoveRacket == 1)) stop = true; 
    if(stop) clearMoveRacket();
  }  
  
  // =================== Остановить движение ракетки =================
  function clearMoveRacket()
  {
    // Прервать работу таймера
    clearInterval(timerRacket); 
    timerRacket = null;         
    // Восстановить начальный шаг смещения ракетки
    stepRacket  = step0Racket;  
    // Сбросить флаг направления движения ракетки
    dirMoveRacket = 0;
  }
  // =================== Ракетка на шаг влево =================
  function leftRacket()
  {
    var x = parseInt(racket.style.left);
    if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
    if(x-stepRacket > 0) racket.style.left = (x-stepRacket)+"px"; 
    else racket.style.left = 0;
  }
  // =================== Ракетка на шаг вправо =================
  function rightRacket()
  {
   var x = parseInt(racket.style.left);
   if((stepRacket *= aRacket) > stepMaxRacket) stepRacket = stepMaxRacket;
   if(x+widthRacket+stepRacket < widthField) racket.style.left = (x+stepRacket)+"px"; 
   else racket.style.left = (widthField-widthRacket)+"px";
  }

  // =================== Старт игры =========================
  function start()
  {
    if(!ismoveBall)
    {
      // Установим флаг начала движения шарика
      ismoveBall=true;
      // Установим шарик на середину ракетки
      ball.style.left = parseInt(racket.style.left)+
        (widthRacket/2 - widthBall/2) + "px";
      ball.style.top  = (heightField-heightRacket-heightBall) + "px";
      // Сделаем шарик видимым
      ball.style.visibility = "visible";
      // Сгенерируем угол, под которым стартует шарик
      fiBall = Math.PI*Math.random()/6;
      if (fiBall > Math.PI/6) fiBall += 7*Math.PI/12;
      else                    fiBall += Math.PI/4;
      // Установим шаги движения шарика
      dxBall = dx0Ball;
      dyBall = dy0Ball;
      // Установим время игры
      timeGame = 0;
      // Запустим движение шарика
      timerBall = setInterval(moveBall, dtBall);
    }
  }

  // =================== Движение шарика =========================
  function moveBall()
  {
    // Время игры
    timeGame++;
    time.innerHTML = "Время игры: " + timeGame;
    // Смещение шарика
    var left = parseInt(ball.style.left);
    var top  = parseInt(ball.style.top);

    var dx = dxBall*Math.cos(fiBall);
    var dy = dyBall*Math.sin(fiBall);
  
    left += dx;
    top  += dy;
    if (left < -widthBall/2)
     {
        dxBall = -dxBall;
        left = -widthBall/2;
     }
     else if(left > widthField-widthBall/2)
     {
        dxBall = -dxBall;
        left = widthField-widthBall/2;
     }

     if (top < -heightBall/2)
     {
        dyBall = -dyBall;
        top = -heightBall/2;
     }
     else if (top >= heightField-heightRacket-heightBall/2)
     {
       var racketLeft = parseInt(racket.style.left);
       // Проверим, нет ли под шариком ракетки 
       if(racketLeft-widthBall/2 < left && left < 
                                 racketLeft + widthRacket+widthBall/2)
       {
         // Да, ракетка есть
         dyBall = -dyBall;
         top = heightField-heightRacket-heightBall/2;
       }
       else 
       {
         // Ракетки нет
         ismoveBall=false;
         clearInterval(timerBall);
         ball.style.visibility = "hidden";
         if (timeRecord < timeGame) timeRecord = timeGame;
         record.innerHTML = "Рекорд: " + timeRecord;
       }
     }
     ball.style.left = left + "px";
     ball.style.top = top + "px";
  }
  
};