
Появилось желание взяться за изучение «убийцы Flash’а» HTML5, а в частности элемента Canvas. Это достаточно интересная технология, позволяющая создавать различные растровые 2d изображения средствами JavaScript. Просидев несколько часов за изучением технологии и вспоминании JavaScript, я написал небольшое интерактивное «приложение», которое, в первую очередь, предназначено для обучения меня и вас. Это обычные круги и прямоугольники, которые можно двигать мышью. Для ловли событий я использую jQuery, мне он кажется наиболее удобным.
Логика работы
Принцип работы прост: сначала я записываю все создаваемые объекты в общий массив объектов и отрисовываю сцену. Затем в событии, выполняемом при нажатии на сцену, я определяю тип нажатого объекта и добавляю необходимую информацию(тип, номер и смещение курсора относительно начальной точки) о нажатом объекте в массив. После этого описывается событие, которое выполняется при перемещении мыши по сцене, в котором я обновляю координаты перемещаемого объекта в общем массиве объектов. Затем просто перерисовывается вся сцена. Ну и последнее событие, выполняемое при отпускании нажатой кнопки мыши, в котором я просто очищаю массив с информацией о выбранном объекте.
Код
Простенький HTML с созданием canvas и подключением JavaScript кода:
<!DOCTYPE html> <html> <head> <title>html5movobj</title> </head> <body> <canvas id="canvas" width="1000" height="400"> Этот элемент не поддерживается </canvas> <script type="text/javascript" src="jquery-1.9.0.min.js"></script> <script type="text/javascript" src="scripts.js"></script> </body> </html>
Создадим глобальные массивы, в objs будет храниться вся информация об объектах, а в move_select будет храниться информация о перемещаемом объекте:
var objs = {Circle: [], Rectangle: []}; var move_select;
Создадим 3 класса: Circle, Rectangle и Draw. Circle, Rectangle — это классы с помощью которых я буду заносить информацию о создаваемых объектах в массив objs. А Draw — это класс, который я создал для более удобного использования функций context:
function Circle(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; } function Rectangle(x1, y1, x2, y2, color) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.color = color; } function Draw(ctx) { this.ctx = ctx; }
Создаём метод класса Draw, для перерисовки сцены:
Draw.prototype.scene = function(canvas) { // очистим сцену this.ctx.clearRect(0, 0, canvas.width, canvas.height); // рисуем круги for (var i = 0; i < objs.Circle.length; i++) { this.ctx.beginPath(); this.ctx.fillStyle = objs.Circle[i].color; this.ctx.arc(objs.Circle[i].x, objs.Circle[i].y, objs.Circle[i].radius, 0, Math.PI * 2, true); this.ctx.closePath(); this.ctx.fill(); } // рисуем прямоуголники for (var i = 0; i < objs.Rectangle.length; i++) { this.ctx.beginPath(); this.ctx.fillStyle = objs.Rectangle[i].color; this.ctx.fillRect(objs.Rectangle[i].x1, objs.Rectangle[i].y1, objs.Rectangle[i].x2, objs.Rectangle[i].y2); this.ctx.closePath(); this.ctx.fill(); } }
Методы, для работы с общим массивом объектов:
// методы для работы с кругами Draw.prototype.fillCircle = function(x, y, radius, color) { objs.Circle.push(new Circle(x, y, radius, color)); } Draw.prototype.moveCircle = function(id, offset, x, y) { objs.Circle[id].x = x + offset[0]; objs.Circle[id].y = y + offset[1]; } // методы для работы с прямоуголниками Draw.prototype.fillRect = function(x1, y1, x2, y2, color) { objs.Rectangle.push(new Rectangle(x1, y1, x2, y2, color)); } Draw.prototype.moveRect = function(id, offset, x, y) { objs.Rectangle[id].x1 = x + offset[0]; objs.Rectangle[id].y1 = y + offset[1]; }
Инициализация canvas‘а, добавление объектов в массив и отрисовка сцены:
$(function(){ var canvas = document.getElementById('canvas'); context = canvas.getContext('2d'); draw = new Draw(context); // создадим объекты draw.fillRect(363, 162, 20, 10, 'rgb(0, 162, 232)'); draw.fillCircle(373, 128, 80, '#456'); draw.fillCircle(343, 105, 20, '#321'); draw.fillCircle(405, 109, 20, '#321'); draw.fillCircle(336, 200, 20, '#321'); draw.fillCircle(409, 202, 20, '#321'); // нарисуем начальную сцену draw.scene(canvas);
Опишем действия, выполняемые при нажатии на canvas:
// действия при нажатии на canvas $('#canvas').mousedown(function(e) { var canvasPosition = $(this).offset(); var mouseX = (e.pageX - canvasPosition.left); var mouseY = (e.pageY - canvasPosition.top); for (var i = 0; i < objs.Circle.length; i++) { var circleX = objs.Circle[i].x; var circleY = objs.Circle[i].y; var radius = objs.Circle[i].radius; // проверка на нажатие в область круга if (Math.pow(mouseX - circleX, 2) + Math.pow(mouseY - circleY, 2) < Math.pow(radius, 2)) { // запишем информацию о выбранном элементе: тип, id, и смещение указателя мыши move_select = [ 'Circle', i, [circleX - mouseX, circleY - mouseY] ]; } } for (var i = 0; i < objs.Rectangle.length; i++) { var rectX1 = objs.Rectangle[i].x1; var rectY1 = objs.Rectangle[i].y1; var rectX2 = objs.Rectangle[i].x1 + objs.Rectangle[i].x2; var rectY2 = objs.Rectangle[i].y1 + objs.Rectangle[i].y2; // проверка на нажатие в область прямоуголника if (mouseX > rectX1 && mouseX < rectX2 && mouseY > rectY1 && mouseY < rectY2) { // запишем информацию о выбранном элементе: тип, id, и смещение указателя мыши move_select = [ 'Rectangle', i, [rectX1 - mouseX, rectY1 - mouseY] ]; } } });
Опишем действия, выполняемые при перемещении мыши по сцене:
// действия при перемещении указателя $('#canvas').mousemove(function(e) { var canvasPosition = $(this).offset(); var mouseX = (e.pageX - canvasPosition.left); var mouseY = (e.pageY - canvasPosition.top); if (move_select != undefined) { // обновим координаты элемента if (move_select[0] == 'Circle') { draw.moveCircle(move_select[1], move_select[2], mouseX, mouseY); } else if (move_select[0] == 'Rectangle') { draw.moveRect(move_select[1], move_select[2], mouseX, mouseY); } // перерисуем сцену draw.scene(canvas); } });
Опишем действия, выполняемые при отпускании нажатой кнопки мыши и завершим скрипт:
// действия при отпуске кнопки нажатия $('#canvas').mouseup(function(e) { move_select = undefined; }); });