События в HTML5 Canvas (как они работают)

в 2:45, , рубрики: canvas, метки:

Вы замечали множество приложений, написанных на Canvas. Почти все они используют тяжеловесные библиотеки для реализации событий. Дело в том, что обычный HTML5 Canvas не умеет использовать события, но я научу вас их внедрять в Canvas, а если точнее — реализовывать их работу.

В теории

Мы как-бы разделяем процесс рисования и процесс выявления событий. В зависимости от ситуации, можно использовать один или два Canvas элемента (в моем случае — один). Мы находим самую верхнюю фигуру (используя алгоритмы) по координате мыши (при этом оставляя предыдущую для события mouseout) и задействуем определенные события.
Сегодня я дам упрощенный туториал по реализации событий. В дальнейшем дам тот же самый туториал, но уже с применением различных классов, объектов и т.п.

Реализация

Для реализации нам потребуется:
— Несколько фигур
— Алгоритм выделения фигуры
— События на Canvas элементе

Для начала начнем с простого кода — инициализация фигур.

var shapes = [];

function circle(ctx){
  ctx.beginPath();
  ctx.arc(0,0,40,0,Math.PI*2,true);
  ctx.closePath();
}

function rect(ctx){
  ctx.beginPath();
  ctx.rect(-50,-50,100,100);
  ctx.closePath();
}

shapes.push(rect,circle);

function useShape(ctx,func){
   func(ctx);
}

Здесь мы видим две фигуры: круг и квадрат, и функция для их задействования. Для рисования будет использовать следующий код:

function draw(ctx){
  clear(ctx);
  for(var i=0;i<shapes.length;i++){
     useShape(shapes[i]);
     ctx.fill();
  }
}

Для поиска фигуры будем использовать другой код:

function findShape(ctx,x,y){
  for(var i = shapes.length - 1; i >= 0; i--){
    var shape = shapes[i];
    useShape(ctx,shape);
    var a = ctx.isPointInPath(x,y); //Простейший алгоритм, также могу предложить использовать отдельный Canvas элемент для рисования изображения и определения уровня альфа-канала
    if(a) return shape;
  }
}

Теперь интересный момент

Мы реализовали базовые функции. Теперь мы должны привязать некоторые события к самому Canvas элементу.

window.onload = function(){
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");
  ctx.translate(64,64);
  
  draw(ctx);

  var mouseover, mouseout;

  canvas.addEventListener("mousemove",function(e){
    var x = e.clientX - this.getClientBoundingRect().left;
    var y = e.clientY - this.getClientBoundingRect().top;
  
    mouseout = mouseover;
    mouseover = findShape(x,y);

    if(mouseover != mouseout){
      if(mouseout){
         //Событие mouseout у фигуры mouseout
      }
      if(mouseover){
         //Событие mouseover у фигуры mouseover
      }
    } else if(mouseover){
        //Событие mousemove у фигуры mousemove
    }
  });

  canvas.addEventListener("click",function(){
    if(mouseover){
      //Событие click у текущей фигуры
    }
  });
}

HTML содержимое

Для нас подойдет практически любое HTML содержание. Главное, чтобы содержал Canvas элемент с id=«canvas».

Вот самый простой пример:

<!DOCTYPE html>
<html>
  <head>
    <title>Canvas Events</title>
    <script src="demo.js"></script>
  </head>
  <body>
    <canvas id="canvas" width="320" height="240"></canvas>
  </body>
</html>

Недостающий фрагмент

Вы наверное заметили незатронутую функцию clear? Вот сама функция:

function clear(ctx){
  ctx.save();
  ctx.setTransform(1,0,0,1,0,0);
  ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
  ctx.restore();
}

В итоге

У нас должен получится черный квадрат с кругом внутри (который мы вряд ли увидим). Однако его события должны срабатывать при наведении на него. Я дал простой туториал по событиям в Canvas элементе.

Вы можете написать свой код, с уже более сложным содержанием (использовать классы, объекты, привязка событий к фигуре). Я лишь даю совет, как реализовать работу событий.

Прошу работу сильно не критиковать, я старался сделать свой как можно проще, передать основную мысль. Если что-то не понятно, могу дать пояснений.

Автор: Alexei03a

  1. Александр:

    Здравствуйте, у Вас тут ошибка, нужно исправить.

    function draw(ctx){
    clear(ctx);
    for(var i=0;i<shapes.length;i++){
    useShape(ctx, shapes[i]);
    ctx.fill();
    }
    }

  2. Admin:

    Александр, спасибо !

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js