Книга: Выразительный JavaScript
Выбор инструмента
Выбор инструмента
Первый элемент управления, который мы добавим – элемент <select>
, позволяющий выбирать инструмент рисования. Как и в случае с controls
, мы будем использовать объект для сбора необходимых инструментов, чтобы не надо было описывать их работу в коде по отдельности, и чтобы можно было легко добавлять новые. Этот объект связывает названия инструментов с функцией, которая вызывается при их выборе и при клике на холсте.
var tools = Object.create(null);
controls.tool = function(cx) {
var select = elt("select");
for (var name in tools)
select.appendChild(elt("option", null, name));
cx.canvas.addEventListener("mousedown", function(event) {
if (event.which == 1) {
tools[select.value](event, cx);
event.preventDefault();
}
});
return elt("span", null, "Tool: ", select);
};
В поле tool
есть элементы <option>
для всех определённых нами инструментов, а обработчик события "mousedown"
на холсте берёт на себя обязанность вызывать функцию текущего инструмента, передавая ей объекты event
и context
. Также он вызывает preventDefault
, чтобы зажатие и перетаскивание мыши не вызывало выделения участков страницы.
Самый простой инструмент – линия, который рисует линии за мышью. Чтобы рисовать линию, нам надо сопоставить координаты курсора мыши с координатами точек на холсте. Вскользь упомянутый в 13 главе метод getBoundingClientRect
может нам в этом помочь. Он говорит, где показывается элемент, относительно левого верхнего угла экрана. Свойства события мыши clientX
и clientY
также содержат координаты относительно этого угла, поэтому мы можем вычесть верхний левый угол холста из них и получить позицию относительно этого угла.
function relativePos(event, element) {
var rect = element.getBoundingClientRect();
return {x: Math.floor(event.clientX - rect.left),
y: Math.floor(event.clientY - rect.top)};
}
Несколько инструментов рисования должны слушать событие "mousemove"
, пока кнопка мыши нажата. Функция trackDrag
регистрирует и убирает событие для данных ситуаций.
function trackDrag(onMove, onEnd) {
function end(event) {
removeEventListener("mousemove", onMove);
removeEventListener("mouseup", end);
if (onEnd)
onEnd(event);
}
addEventListener("mousemove", onMove);
addEventListener("mouseup", end);
}
У неё два аргумента. Один – функция, которая вызывается при каждом событии "mousemove"
, а другая – функция, которая вызывается при отпускании кнопки. Каждый аргумент может быть не задан.
Инструмент для рисования линий использует две вспомогательные функции для самого рисования.
tools.Line = function(event, cx, onEnd) {
cx.lineCap = "round";
var pos = relativePos(event, cx.canvas);
trackDrag(function(event) {
cx.beginPath();
cx.moveTo(pos.x, pos.y);
pos = relativePos(event, cx.canvas);
cx.lineTo(pos.x, pos.y);
cx.stroke();
}, onEnd);
};
Функция сначала устанавливает свойство контекста lineCap
в “round”
, из-за чего концы нарисованного пути становятся закруглёнными, а не квадратными, как это происходит по умолчанию. Этот трюк обеспечивает непрерывность линий, когда они нарисованы в несколько приёмов. Если рисовать линии большой ширины, вы увидите разрывы в углах линий, если будете использовать установку lineCap
по умолчанию.
Затем, по каждому событию "mousemove"
, которое случается, пока кнопка нажата, рисуется простая линия между старой и новой позициями мыши, с использованием тех значений параметров strokeStyle
и lineWidth
, которые заданы в данный момент.
Аргумент onEnd
просто передаётся дальше, в trackDrag
. При обычном вызове третий аргумент передаваться не будет, и при использовании функции он будет содержать undefined
, поэтому в конце перетаскивания ничего не произойдёт. Но он поможет нам организовать ещё один инструмент, ластик erase
, используя очень небольшое дополнение к коду.
tools.Erase = function(event, cx) {
cx.globalCompositeOperation = "destination-out";
tools.Line(event, cx, function() {
cx.globalCompositeOperation = "source-over";
});
};
Свойство globalCompositeOperation
влияет на то, как операции рисования на холсте меняют цвет пикселей. По умолчанию, значение свойства "source-over"
, что означает, что цвет, которым рисуют, накладывается поверх существующего. Если цвет непрозрачный, он просто заменит существующий, но если он частично прозрачный, они будут смешаны.
Инструмент “erase”
устанавливает globalCompositeOperation
в "destination-out"
, что имеет эффект ластика, и делает пиксели снова прозрачными.
Вот у нас уже есть два инструмента для рисования. Мы можем рисовать чёрные линии в один пиксель шириной (это задано значениями свойств холста strokeStyle
и lineWidth
по умолчанию), и стирать их. Работающий, хотя и примитивный, прототип программы.
- Выбор инструментальных средств моделирования и методов
- 9 Расширение вашего инструментария
- 1.6. Реализация инструмента для выбора временных рамок с помощью UISlider
- 14.6. Выбор Х-инструментария
- О чем писать? Три инструмента выбора тем статей
- Приложение 5. Инструменты администрирования
- Создание и отправка почтового сообщения
- 18 Контент-маркетинг и SEO-технологии: как наладить работу в одной упряжке
- 7.6. Описание режимов работы
- Формирование накладной на приход товара
- 15.1. Операционная система, дружественная к разработчику