Создание игры Dice Game (игра в кости) на JavaScript. Вот нашлось время и силы познакомиться с игрой такого типа. Сразу оговорюсь, что материал и пример не мой, а взят из зарубежного ресурса для изучения.
В примере рассмотрен основной принцип создания игры Dice. Можно сказать - чисто схематично. Однако этого достаточно, чтобы остальное дополнить по необходимости.
Код оказался на удивление прост. Я не сомневаюсь, что в Интернете есть примеры более сложного и совершенного JavaScript-кода для игр подобного типа. Но цель статьи - познакомиться с основным принципом создания игры, не более.
HTML разметка и стили
Разметка очень простая и состоит из четырех элементов:
Элементы
1
id="dice-side-1"
и
1
id="dice-side-2"
- это иммитация двух игральных костей; как если бы эти кости были обращены лицевой стороной к зрителю.
Кнопка
1
class="dice-roll"
служит для управления; с помощью нее мы будем “бросать” игральные кости.
Заголовок
1
id="status"
носит информативный характер - в нем будет выводиться текущая информация.
CSS-стили в комментариях не нуждаются, ибо они небольшого размера и “прозрачные”:
JavaScript - оживляем игральные кости
Далее приступим к более интересной части задачи - созданию js-кода для “оживления” наших игральных костей.
Для этого “выберем” из HTML кнопку и “повесим” на нее функцию rollDice для обработки клика по кнопке:
Затем начнем описывать функцию rollDice. Создадим три переменные, в которые поместим обе игральные кости и информативный заголовок:
Сгенерируем два случайных числа из диапазона от 1 до 6. Игральная кость имеет шесть сторон - поэтому такой диапазон. Эти числа будут иммитацией одной из шести сторон каждой игральной кости.
Другими словами. На всех сторонах игрального кубика “выбито” точками число - от 1 до 6. Поэтому можно сказать иначе - диапазон от 1 до 6 - это диапазон возможных значений, которые выпадают на каждой из игральных костей:
Переменная
1
diceTotal
служит для информативных целей - будем показывать сообщение о том, сколько в сумме выпало очков на игральных костях.
Осталось поместить случайно сгенерированную пару чисел в HTML-код. Помимо этого вывести информационное сообщение, сколько очков в сумме выпало. И предупредить, если на обеих костях выпавшее число одинаковое - тогда предоставить игроку еще один ход:
Наш JavaScript-код готов и выглядит таким несложным способом:
В заключение, как мне кажется, стоит сказать пару слов по поводу рассмотренного примера. Он является достаточно схематичным. Однако никто не мешает дополнить код возможностью смены изображений, иммитирующих грани костей.
Плюс - добавить анимацию. И получится весьма неплохой результат, как мне представляется.
Знакомство с техникой Drag-and-Drop и механизмом ее реализации с помощью JavaScript. Данный обзор не претендует на полноту покрытия материала. Задача статьи - познакомиться с созданием Drag-and-Drop на JavaScript. Понять сам принцип механизма и научиться применять основные инструменты для его реализации.
Определение Drag-and-Drop
Сам механизм Drag-and-Drop интуитивно понятен - “схватил-перетащил-бросил”. Преимущество внедрения Drag-and-Drop в интерфейсы заключается в упрощении реализации задач; в уменьшении количества пунктов меню типа “Copy-Paste”.
События Drag-and-Drop
Механизм Drag-and-Drop имеет в своем составе целую группу событий, с помощью которых можно контролировать процесс перетаскивания:
1
dragstart
- пользователь начинает перетаскивание элемента
1
dragenter
- перетаскиваемый элемент входит в область целевого объекта
1
dragover
- перетаскиваемый элемент перемещается в области целевого объекта
1
dragleave
- перетаскиваемый элемент покидает область целевого объекта
1
drag
- момент начала процесса перетаскивания объекта
1
drop
- момент, когда отпускается зажатая клавиша мыши (перетаскиваемый объект “роняется”)
1
dragend
- момент завершения процесса перетаскивания объекта
Объект dataTransfer
Механизм Drag-and-Drop также имеет в своем составе объект dataTransfer, который служит для вспомогательных целей. В этом объекте хранится необходимая информация о событии перетаскивания. Помимо этого, в объект dataTransfer можно добавлять данные; а также считывать из него данные.
Свойства (наиболее важные) объекта dataTransfer:
1
dataTransfer.effectAllowed
- задаем тип перетаскивания, которое пользователь может выполнять с элементом
1
dataTransfer.dropEffect
- задаем внешний вид курсора мыши в соответствии с заданным типом перетаскивания
Методы (наиболее важные) объекта dataTransfer:
1
setData()
- добавляет данные в нужном формате
1
clearData()
- удаляет данные
1
setDragImage()
- устанавливает изображение для перетаскивания с координатами курсора (0, 0 — левый верхний угол)
1
getData()
- возвращает данные
Ниже будет рассматриваться практический пример реализации Drag-and-Drop на JavaScript.
HTML разметка
Базовая HTML-разметка будет простой:
Что для чего служит в этой разметке?
Заголовок
1
id="dropStatus"
будет отображать текущее состояние процесса Drag-and-Drop. В него мы будет отправлять информацию о текущем состоянии Drag-and-Drop при помощи событий, о который говорилось выше.
Заголовок
1
id="dropTitle"
служит просто для декоративных целей.
Блок
1
id="dropZone"
является целевой областью - в нее мы будет перетаскивать объекты.
Объекты
1
id="object1"
,
1
id="object2"
,
1
id="object3"
- это перетаскиваемые объекты; их мы будем перемещать в область блока
1
id="dropZone"
.
Кнопка
1
id="readDropZone"
будет выводить информацию об перемещенных объектах.
Прежде чем детально рассматривать работу каждой из будущих функций по обработке событий, мне кажется, будет лучше просто понять, какие события и куда мы будем “вешать”.
Итак, начнем с перетаскиваемых элементов
1
id="object1"
,
1
id="object2"
,
1
id="object3"
. На каждый из них мы повесим два события:
1
dragstart
- событие начала процесса перетаскивания элемента
1
dragend
- событие окончания процесса перетаскивания элемента
Для каждого из элементов, при возникновении на нем события, мы будем запускать соответствующую функцию
1
dragStart
или
1
dragEnd
:
Обратим внимание на строку
1
el.setAttribute('draggable', 'true');
- здесь мы динамически добавляем для всех элементов с классом
1
.objects
атрибут
1
draggable="true"
, тем самым делая (благодаря HTML5) эти элементы доступными для перетаскивания.
На элемент
1
id="dropZone"
мы “повесим” гораздо больше событий:
1
dragenter
- перетаскиваемый объект (например,
1
id="object1"
) входит в область целевого объекта (
1
id="dropZone"
)
1
dragleave
- перетаскиваемый объект (например,
1
id="object1"
) выходит из области целевого объекта (
1
id="dropZone"
)
1
dragover
- перетаскиваемый объект (например,
1
id="object1"
) перемещается внутри области целевого объекта (
1
id="dropZone"
)
1
drop
- перетаскиваемый объект (например,
1
id="object1"
) помещается внутри целевого объекта (
1
id="dropZone"
)
И конечно же, для каждого события будет своя функция. JavaScript-код в итоге будет выглядеть таким образом:
Ну и на кнопку
1
id="readDropZone"
мы “повесим” обычный код с функцией
1
readZone
:
Если суммировать все вышесказанное, то общий вид handler’ов в нашем случае будет выглядеть таким образом:
Далее будет детально останавливаться на каждой из функций - что она делает и для чего.
Функция dragStart (event)
Начнем с начала и запустим функцию для обработки старта события перетаскивания - события
1
dragstart
. Хочу сразу оговориться, что в процессе написания кода для обработки события перетаскивания важно четко представлять себе, какое событие и на каком элементе происходит.
В данном случае мы будем обрабатывать событие
1
dragstart
, которое возникает на перетаскиваемом элементе (
1
id="object1"
,
1
id="object2"
или
1
id="object3"
- не важно).
Событие
1
dragstart
в момент своего возникновения автоматически генерирует объект dataTransfer, который (как мне кажется) можно в общих чертах сравнить с событийным объектом Event; последний также хранит в себе множество данных о произошедшем событии. Некоторыми методами и свойствами объекта Event мы воспользуемся в нашем примере:
Функция
1
dragStart
при возникновении события “берет” элемент
1
dropStatus
и методом
1
innerHTML
“пихает” внутрь него строку, часть которой представляет из себя значение атрибута
1
id
элемента, на котором произошло событие (
1
event.target
).
Для объекта dataTransfer задается значение его свойства
1
dropEffect
-
1
move
.
В третьей строке для объекта dataTransfer с помощью метода
1
setData()
задается имя переменной
1
text
и значение для этой переменной - ID текущего элемента.
Функции dragEnter(), dragLeave(), dragOver()
Три функции, каждая из которых отслеживает событие, возникающее на элементе
1
dropZone
:
Первые две функции -
1
dragEnter (event)
и
1
dragLeave (event)
очень похожи между собой. Каждая из них манипулирует содержимым заголовка
1
dropStatus
, сигнализируя о происходящем событии.
Третья функция
1
dragOver (event)
может показаться странной. Все ее назначение - это отмена действия по-умолчанию. Что это за действие по-умолчанию? Дело в том, что у браузеров имеется свой собственный (помимо HTML5) механизм реализации события перетаскивания Drag-and-Drop. И если его не отключить, то он не даст срабатывать нашему механизму.
Функция dragDrop (event)
Самая большая и самая важная функция в нашем коде. Она также срабатывает на событие, возникающее на элементе
1
dropZone
:
В строке
1
event.preventDefault();
мы снова отменяем действие по-умолчанию. На этот раз это касается самого перетаскиваемого элемента - ведь он может быть ссылкой и браузер выполнит переход по ней (действие по-умолчанию), что нам совсем не нужно.
В строке:
… мы из объекта dataTransfer получаем ID перетаскиваемого элемента. Вы же помните, что в функции
1
dragStart (event)
с помощью строки:
…мы его как раз получали?
Далее находим перетаскиваемый элемент по его ID:
И помещаем его внутрь текущего активного элемента:
Далее убираем у перетаскиваемого элемента атрибут
1
draggable
- он больше не перетаскиваемый. Визуально сигнализируем об этом, изменив вид курсора мыши:
И сообщаем об изменившемся статусе в заголовке:
Отдельного упоминания стоит строка
1
droppedIN = true;
. Это флаг, с помощью которого мы определяем, произошло ли событие
1
drop
или нет.
Может случиться так, что объект мы перетащили в область элемента
1
dropZone
, но передумали его помещать туда. И “отпустили” перетаскиваемый элемент за областью элемента
1
dropZone
. В результате событие
1
dragend
произошло, но событие
1
drop
не выполнилось.
Такую ситуацию обрабатывает функция
1
dragEnd()
:
Функция readZone ()
Последняя функция из нашего примера - это функция-счетчик. Ее задача - просто посчитать, сколько элементов на данный момент мы “бросили” в область
1
dropZone
:
Нажимаем кнопку
1
dropButton
и alert’ом последовательно выводим все элементы, помещенные внутрь объекта
1
dropZone
.
Вот, в принципе, и все, что можно вкратце сказать. Осталось только взглянуть на готовый пример работы кода - JavaScript - Drag’n’Drop - Part 2.
На этом все. Здоровая критика и полезные замечания только приветствуются.
Этот скромный обзор не смог бы появиться, если бы не было двух полезных для меня ресурсов:
Данная статья планируется как пошаговый обзор создания простой JavaScript-игры класса “Ball and Paddle” на Canvas. Примерами такой игры могут послужить старые DOS-е игры наподобие таких - Ball and Paddle.
Пример кода из этой статьи взят из видео-курса достаточно известного Интернет-ресурса, посвященного фронтенд-разработке - Udemy.
Почему Canvas и почему игра? Лично для меня процесс познания JavaScript сильно облегчается благодаря Canvas - так интереснее. А создание игры на Canvas - это еще интереснее!
Итак, с чего начнем? Дальше в меру своих сил буду стараться детально пошагово рассказывать, что делает тот или иной кусок кода. И начнем с базового набора - создания Canvas.
Базовый Canvas
HTML-разметка страницы будет предельно простой:
В JavaScript’е создадим две глобальные переменные - одну для элемента Canvas, вторую - для 2d-контекста Canvas. Когда parser браузера построит DOM-дерево документа (событие
1
DOMContentLoaded
), инициализируем обе переменные, выполним проверку удачного получения 2d-контекста Canvas и если проверка будет пройдена успешно, то динамически зададим размеры Canvas:
Базовые элементы игры
Основа Canvas была создана в предыдущем шаге. В этом шаге создадим три фигуры, которые будут учавствовать в игре. Таковыми фигурами будут:
фон игры
мячик (ball)
площадка (paddle)
Ниже я приведу JavaScript-код создания всех трех элементов, но сам код комментировать не буду, так как он очень простой и относится к основам Canvas:
Живой результат вышеприведенного кода можно посмотреть на этой странице - Lesson1-1. Это то, что должно получиться и что послужит заготовкой для игры.
Анимация мячика
В этом шаге предстоит сделать более интересные вещи. Во-первых, мы сделаем так, чтобы мячик начал двигаться как по-горизонтали, так и по-вертикали. А во-вторых, сделаем так, чтобы он вел себя как настоящий резиновый мячик - при ударе о стену отскакивал от нее и мчался в противоположном направлении.
Сделать это достаточно просто. Для этого нам понадобится одна из так называемых тайминговых функций JavaScript -
1
setInterval()
. А также немного воображения.
Анимация мячика будем делать по-простому принципу, по которому делается любой мультфильм или кино - мячик будет отрисовываться с заданной частотой (
1
1000/frames
), но каждый раз в новой позиции. В результате будет создаваться иллюзия его движения. Каждая новая позиция мячика - это его координата по оси X или Y с новым значением соответственно.
Чтобы мячик двигался достаточно быстро, изменять значения координат (
1
ballX += ballStepX
и
1
ballY += ballStepY
) мячика по оси X и Y будем с определенным шагом (
1
ballStepX
и
1
ballStepY
) - допустим, со значениями 5 или 6:
Эффект отскакивания от стенок (как резиновый мячик) обеспечивает проверка условий в участке кода:
Здесь все просто - при выполнении условия знак переменной
1
ballStepX
или
1
ballStepY
будет меняться на противоположный. В результате значение переменной
1
ballX
или
1
ballY
будет возрастать или уменьшаться. Как следствие, мячик будет двигаться в одну или в другую сторону.
Живой пример приведенного выше кода можно посмотреть и изучить на этой странице - Lesson1-2.
Двигаем paddle
В этом шаге нужно заставить двигаться paddle при помощи мыши. Для этого по событию
1
mousemove
внутри элемента Canvas будем получать значение X-координаты курсора мыши. И передавать это значение элементу paddle, его X-координате левого верхнего угла. Тем самым мы заставим paddle двигаться. За все эти действия будет отвечать функция
1
mouseCoords()
:
Обратите внимание на последнюю строку функции -
1
paddleX = mouseX - paddleWidth/2;
. Переменная
1
paddleX
необходима для того, чтобы при выходе за границы Canvas элемент paddle скрывался ровно на половину своей ширины.
Также не забудем создать переменные для paddle и передать их в код для отрисовки фигуры:
Живой пример приведенного выше кода можно посмотреть и изучить на этой странице - Lesson1-3. Подвигайте курсором мыши право-влево, чтобы увидеть эффект.
Мячик отскакивает от paddle
На этом этапе нужно сделать так, чтобы мячик отскакивал от paddle, когда последний оказывается на его пути. Выполнить эту задачу просто - ведь мячик уже отскакивает от “стен” Canvas. Следовательно, нужно научить мячик “видеть” еще и paddle.
Для этого сначала нужно опеределить внешние границы paddle - все его четыре стороны:
Когда значения всех сторон будут определены, то можно будет подставить эти значения в условие - и дело сделано:
Живой пример приведенного выше кода можно посмотреть и изучить на этой странице - Lesson1-4. Подвигайте курсором мыши право-влево и постарайтесь поймать мячик с помощью paddle, чтобы увидеть эффект.
Угол отскока мячика
В этом шаге сделаем так, чтобы наша игра смотрелась более правильной с точки зрения физики и обычной природы. То есть, при разном угле попадания на paddle мячик должен отскакивать от него с разной скоростью. Чем острее угол падения, тем с большей скоростью отскакивает от paddle мячик.
Решается эта задача несколькими строками кода:
В первой строке
1
var paddleCenter = paddleLeftEdge + paddleWidth/2;
находится X-координата середины paddle. В строке
1
var ballDistance = ballX - paddleCenter;
определяется расстояние, на котором мячик соприкоснулся с paddle относительно его середины. В строке
1
ballStepX = ballDistance * 0.35;
полученная дистанция присваивается шагу приращения по оси Х мячика -
1
ballStepX
.
Логично предположить, что чем больше величина дистанции точки соприкосновения мячика относительно середины paddle, тем выше новая скорость движения мячика по-горизонтали. Чтобы эта скорость не была слишком высокой, ее необходимо уменьшить, умножив на 0.35, к примеру.
Живой пример приведенного выше кода можно посмотреть и изучить на этой странице - Lesson1-5.
Оптимизация кода
На данный момент наша задача по построению игры практически решена. Но остался один организационный момент.
Заключается он в том, что код необходимо реорганизовать в отдельные функции. Такой код будет читаться и поддерживаться значительно лучше.
Одна из таких функций уже была создана ранее - это функция
1
mouseCoords()
. Давайте преобразуемся и весь оставшийся код подобным образом:
Готовый пример преобразованного в функции кода можно посмотреть на этой странице - Lesson1-6.
Попытка разобраться с интересной возможностью canvas, которая называется “манипуляция с пикселями” (raw pixel). Основная суть этой возможности заключается в том, что можно получить информацию о цвете и альфа-канале любого пикселя, расположенного в произвольном месте canvas.
Образно выражаясь, можно сделать снимок (снять цветовой отпечаток) с любого участка canvas. Причем, этот отпечаток может быть любого размера (20х20 пикселей, 100х100 пикселей, 1х1 пиксель) - какой потребуется.
Техника Raw Pixel возможна благодаря объекту ImageData, у которого есть три свойства:
ImageData.width - ширина объекта в пикселях
ImageData.height - высота объекта в пикселях
ImageData.data - массив данных
Первые два свойства примитивно просты - это геометрические размеры объекта ImageData.
Самым интересным свойством объекта ImageData является последнее -
1
ImageData.data
.
Данное свойство в свою очередь является объектом, а если быть точнее - одномерным массивом. В этом массиве на каждый пиксель из “отпечатка” отводится 4 байта:
imageData.data[0] — значение красного цвета (число от 0 до 255);
imageData.data[1] — значение зеленого цвета (число от 0 до 255);
imageData.data[2] — значение синего цвета (число от 0 до 255);
imageData.data[3] — значение прозрачности (число от 0 до 255);
В результате получается значение цвета в формате RGBA.
У Canvas есть несколько методов для работы с объектом ImageData:
getImageData()
putImageData()
toDataURL()
createIamgeData()
Наиболее интересные и полезные два первых метода -
1
getImageData
и
1
putImageData
.
Метод getImageData
Метод
1
getImageData
позволяет создать экземпляр объекта ImageData на основе существующего canvas. Другими словами, этот метод “делает снимок” существующего canvas и преобразует этот “снимок” в объект ImageData.
Создадим простой пример для наглядного отображения работы метода
1
getImageData
:
Что происходит в выше приведенном коде? Все просто - создаются два блока с синим и зеленым цветом, причем блок с зеленым цветом намеренно накладывается на блок с синим цветом.
А затем с помощью метода
1
getImageData
делаем снимок (снимаем отпечаток - если хотите) размером 1х1 пиксель с уже готового рисунка в canvas.
В первом случае левый верхний угол “отпечатка” будет находиться в точке (40, 40) координатной сетки canvas; во-втором случае левый верхний угол “отпечатка” будет находиться в точке (20, 20). В обоих случая ширина и высота “отпечатка” (снимка) равна 1x1 пиксель - то есть, будет делаться “снимок” размером (площадью) в 1 пиксель.
Результат метода
1
getImageData
помещается в переменную
1
rawPixel
. Так как эта переменная не что иное, как ссылка на конкретный экземпляр объекта ImageData, то мы можем воспользоваться свойством
1
data
этого объекта, а точнее - массивом данных. Обращаясь по индексу к каждому из элементов массива, в итоге мы получаем значение цвета данного пикселя в формате RGBA.
Площадь “снимка” можно произвольно увеличить и тогда массив данных также увеличиться. К примеру, такой код:
… создаст массив вида:
Как видим, к любому элементу этого массива можно обратиться по его индексу, чтобы получить значение цвета конкретного пикселя.
Сделаем приведенный выше пример более интересным (и наглядным для понимания) - добавим в него динамики. Преобразуем его так, чтобы в любой момент времени в отдельном информационном блоке выводился цвет (в формате RGBA) того участка canvas, над которым в данный момент находится курсор мыши. Будем считать, что курсор мыши имеет размер 1х1 пиксель:
В этом коде функция
1
getColor
при движении курсора мыши (событие
1
mousemove
) над областью canvas (
1
picker.canvas
) считывает координаты этого курсора в переменные
1
cx
и
1
cy
. Значения этих переменных передаются в качестве параметров методу
1
getImageData
, результат работы которого помещается в переменную
1
currentColor
.
Из переменной
1
currentColor
с помощью свойства
1
data
достаются значения (как элементы массива, по индексу) для каждого из RGBA-каналов. Все четыре значения конкатенируются и передаются в виде строкового значения - как фоновый RGBA-цвет для блока
1
colorBox
.
Для пущей наглядности с помощью свойства
1
textContent
в блок
1
colorBox
передается текущее значение цвета.
Представленный выше функционал - не что иное, как обычный Color Picker в любом графическом редакторе. Просто в данном примере достаточно изменить событие
1
mousemove
на событие
1
click
, чтобы все заработало как надо.
Метод putImageData
Возможности метода
1
putImageData
значительно шире, так как этот метод позволяет редактировать canvas. Другими словами, с помощью метода
1
getImageData
получается конкретный экземпляр объекта ImageData из текущего canvas.
Затем при помощи произвольной функции производится преобразование данных этого объекта.
Отредактировванные данные возвращаются обратно в canvas с помощью метода
1
putImageData
.
Давайте на конкретном примере рассмотрим описанный выше пример:
В приведенном выше коде динамически (с помощью конструктора) создается экземпляр изображения и задается значение для его атрибута
1
src
. Затем на это изображение “вешается” функция, задача которой - отрисовать это изображение в canvas.
Изображение отрисовывается в canvas:
… и тут же с него снимается отпечаток - создается объект ImageData:
Полученный объект
1
imageData
обрабатывается двумя произвольными функциями -
1
imageInvert()
и
1
grayScaleImage()
при событии
1
click
на кнопках:
Функция
1
imageInvert()
инвертирует цвета - “пробегается” по массиву
1
imageData.data
и производит простое вычитание текущего значения цвета из 255:
Функция
1
grayScaleImage()
также “пробегается” по массиву
1
imageData.data
, но при этом производит усреднение значения цвета для каждого из пикселов:
Приведем еще один пример инвертации цвета. В произвольной функции будет производится перемена цвета местами - значение красного канала будет помешаться в зеленый канал; значение зеленого цвета будет помещаться в красный канал:
В этом коде canvas задаются размеры оригинального изображения:
Затем в цикле производится взаимозамещение красного и зеленого каналов:
Метод toDataURL()
Еще одним интересным методом при работе с замещением пикселей является метод
1
toDataURL()
. Суть его проста - также как и метод
1
getImageData()
, этот метод получается “снимок” текущего canvas и сохраняет результат в виде изображения в двух форматах на выбор -
1
jpg
или
1
png
.
Синтаксис этого метода таков:
Стоит обратить внимание на явное указание (с помощью MIME) формата, в котором производится сохранение изображения. Помимо этого, при сохранении в формате
1
jpg
возможно указание второго параметра, который служит для задания качества сохраняемого изображения (от 0 до 1).
Кроме этого, стоит обратить внимание, что изображение кодируется в base64 формате и именно в этом виде может быть использовано; но никак не в форматах
1
jpg
или
1
png
.
Для внесения большей ясности давайте рассмотрим еще один интересный пример, в котором будет показана работа метода
1
toDataURL()
:
Что мы имеем в приведенном выше коде? Ну, во-первых, это конечно же canvas. На этом canvas’е при помощи мыши мы можем рисовать - за это отвечает функция
1
drawCanvas()
.
У этой функции работа проста, но есть одна фишка - это флаг
1
mouseDown
. Когда курсор мыши попадает в область canvas и начинает двигаться в пределах области этого canvas (событие
1
mousemove
), то запускается функция
1
drawCanvas (event)
.
Но результата работы этой функции нет, так условие внутри этой функции не срабатывает из-за значения флага
1
mouseDown == false
.
С помощью событий
1
mousedown
и
1
mouseup
в коде производится переключение состояний флага
1
mouseDown
из
1
false
в
1
true
и обратно.
Также при событии
1
mouseup
производится “снимок” текущего canvas и помещение его в атрибут
1
href
ссылки
1
a
:
Обратите внимание на редкий HTML5-атрибут
1
download
, в котором задается имя скачиваемого изображения.
Если для ссылки указан атрибут
1
download
, то при клике по этой ссылке перехода никуда не происходит, а выполняется скачивание изображения с именем по-умолчанию (заданном в атрибуте
1
download
).
Заключение
Вот в принципе и все о манипуляцих с пикселями (raw pixel) в canvas. На самом деле это конечно же не все, что можно рассказать и сделать с помощью этой техники.
Здесь я просто сам познакомился с нею и вкратце описал моменты, которые мне показались наиболее интересными.
Этой статьи бы не было, если бы не существовали источники, которые и помогли ей родиться:
Небольшая заметка, посвященная вопросу настройки тем оформления (skins) в популярном и очень полезном консольном файловом менеджере Midnight Commander.
И попутно затрагивается вопрос с настройкой отображения кириллицы в Midnight Commander под управлением OSX.
Пару хвалебных слов
Midnight Commander - это консольный файловый менеджер. Консольный - потому что он работает в консоли, из эмулятора терминала. Внешне он очень похож на аналогичный Far Manager под операционной системой Windows.
Midnight Commander - очень легкий, потому что для своей работы он использует псевдографику.
Midnight Commander - обладает большими возможностями, больше половины которых обычный пользователь даже не применяет на практике.
Устанавливается Midnight Commander из пакетного менеджера, так как эта утилита имеется в репозиториях любого дистрибутива Linux. В Debian \ Ubuntu \ Mint установка производится такой командой:
Оформление Midnight Commander
После установки Midnight Commander и его первоначального запуска внешний вид программы будет примерно таким:
Прямо скажем, зрелище не очень привлекательное, особенно - зеленый шрифт на синем фоне. Это тема оформления (skin) по умолчанию для Midnight Commander и называется она также - default.
Но оформление Midnight Commander можно (и нужно) поменять и сделать это просто, так как эта программа идет с предустановленным набором тем оформления.
Готовые темы оформления (skins) после установки Midnight Commander располагаются по пути:
Туда можно заглянуть и выбрать, что понравиться:
Выбрать тему оформления для Midnight Commander можно командой:
Здесь ключ -S указывает, что при запуске Midnight Commander необходимо использовать тему оформления. Имя темы оформления (skin) указывается после ключа. Результат приведенной выше команды будет следующим:
Уже значительно лучше, не правда ли? Таким образом можно перебрать все имеющиеся в комплекте темы и выбрать понравившуюся.
Когда тема оформления выбрана, нужно прописать ее в конфигурационном файле Midnight Commander, чтобы последний запускался каждый раз именно с этим skin’ом.
Файл настроек Midnight Commander располагается по пути:
и запускается на редактирование таким образом:
В этом файле нужно найти строчку skin и изменить значение параметра на название файла темы (из /usr/share/mc/skins):
Обратите внимание на название skin’а в данном случае - modarin256. Здесь 256 - это количество цветов отображения, которые используются в этой теме.
По умолчанию в Linux Mint консоль не поддерживает отображение такого количества цветов. Если запустить Midnight Commander с темой modarin256 (к примеру), то появится ошибка и предложении использовать тему по-умолчанию (default).
Включить поддержку отображения 256 цветов в консоли можно, добавив строку export TERM=xterm-256color в файле .bash_profile (если используется BASH), в файле .zshrc (если используется ZSH), в файле .profile (если используется macOS).
В моем случае используется ZSH и файл .zshrc будет выглядеть таким образом:
Если все сделано без ошибок, то запуск Midnight Commander выдаст такой результат (используется тема оформления modarin256):
Установка и настройка Midnight Commander в операционной системе OSX мало отличается от аналогичных действий в Linux.
Устанавливать Midnight Commander в macOS проще всего с помощью Homebrew:
Не забываем включить поддержку 256 цветов в консоли OSX, если хотим использовать богатые цветом темы оформления Midnight Commander, такие как modarin256 или xoria256.
Для этого редактируем файл .bash_profile или файл .zshrc (если используется ZSH):
Дополнительным шагом будет добавление в файл .bash_profile (или .zshrc) двух строчек:
… для того, чтобы в Midnight Commander правильно отображались русскоязычные имена файлов и директорий. Иначе вместо вразумительных имен файлов будут одни вопросительные знаки.