Мне очень приятно видеть рост числа уникальных посетителей моего блога, а потому я изо всех сил стараюсь затрагивать полезные и интересные темы. Как некоторые из Вас могли увидеть из предыдущего поста, я обзавелся аккаунтом в сети GitHub, и теперь всем будет удобнее брать исходники моего кода и следить за его развитием.
В сегодняшней статье будет много букв, примерно столько же кода и такая занимательная вещь, как HTML5. Речь пойдет о «велосипеде», который есть в любом уважающе себя js-фреймворке и в то же время является отличным примером работы со связкой HTML5+JS. Это утилита выбора цвета и получения информации и нем в народе известная под именем colorpicker
Итак, чтобы с ходу заинтересовать читателя, покажу рабочий пример
С чего же начать в разработке данного модуля? Давайте попробуем построить модель приложения. За основу возьмем цветовую модель HSV. Она состоит из:
- Выбора цвета на шкале Hue — оттенок цвета (это шкала цветов справа)
- Насыщенность цвета Saturation и его яркость — Value (квадрат с двумя градиентами по центру)
Шкалу Hue мы будем генерировать автоматически. До выхода HTML5 нам пришлось бы звать на помощь сторонние средства, но пятая версия языка разметки имеет в своем арсенале тэг <canvas>, который создает область для рисования, доступную для специализированных JavaScript-методов.
В качестве поля выбора насыщенности и яркости нам послужит div, внутрь которого мы положим квадрат с соответствующим градиентом (все можно найти в указанном в конце статьи репозитории), а подложку будем менять в зависимости от выбранного на шкале Hue цвета.
Алгоритм будет таков:
- По умолчанию мы выбираем красный цвет
- При перемещении по шкале Hue мы высчитываем положение курсора внутри шкалы, конвертируем его в RGB, изменяем подложку у SV-блока
- При перемещении внутри SV-блока также высчитываем положение курсора по осям (S — ось абсцисс, V — ординат) и вносим коррекции в полученный цвет, не меняя базовую подложку у SV-блока
Приступим!
Будем стремиться к простоте, а значит сделаем так, чтобы скрипт вызывался минимальным количеством кода. В html мы заводим div, в который будет подгружаться colorpicker (id=»picker_append»), а в базовом JS вызовем метод
colorpicker.get("picker_append");
Наш модуль будет подчиняться паттерну Singleton (Одиночка), т.е. на одной странице будем генерировать один colorpicker.
Сам модуль будет объектом Colorpicker, который имеет три метода — init (построение), get(вывод на страницу), destroy(уничтожение). С get и destroy все предельно ясно, за исключением того, что в методе get мы проверяем наличие на странице объекта Colorpicker. Конечно, это все легко обойти, но для красоты и эффектности очень полезно =)
Сразу же я подключу модуль Drag’n’Drop для корректной и удобной работы с положением курсора. Он «вшит» в код скрипта в самом его начале.
Подробно я опишу метод init. Внутри него будет три переменных-объекта : picker, hue и tones (сам механизм целиком, шкала цветов H и шкала оттенков SV соответственно). Далее мы создаем на странице DOM-элементы, необходимые для работы colorpicker-а.
Для объекта picker пишем метод init, внутри которого мы задаем параметры инициализации инструментов и производим их собственно инициализацию.
picker = { Y : 100, X : 100, init: function(){ var params = { height: 256, width: 30, show_block: "show_block", tones_block: "picker", hue: app_div }; var t_params = { show_block: "picker", marker: "circle" }; hue.init(params); tones.init(t_params); picker.show_block = document.getElementById("show_block"); } };
Сразу же появляются два метода init для объектов hue и tones, которые должны быть описаны. Начнем с hue.
Объявляем объект layer внутри hue, для которого есть метод create, внутри которого есть метод gradient. Тут самое интересное!
Мы определяем тип canvas — 2d.
var cont = layer.getContext("2d");
Далее мы создаем объект градиента внутри canvas.
var grad = cont.createLinearGradient(width/2,height,width/2,0); var cols = [[255,0,0],[255,255,0],[0,255,0],[0,255,255],[0,0,255],[255,0,255],[255,255,255]];
Cols — это массив границ цветов, внутри которых будут организовываться переходы. Три элемента в каждом вложенном массиве — это значения по каждому из каналов : red, green и blue. Обходим в цикле этот массив и генерируем дополнительный граничный цвет для градиента при помощи метода addColorStop.
for(var i=0; i<=6; i++) { color = 'rgb('+cols[i][0]+','+cols[i][1]+','+cols[i][2]+')'; grad.addColorStop(i*1/6, color); } cont.fillStyle = grad; cont.fillRect(0,0,width,height);
Два последних метода заполняют полученным градиентом указанный DOM.
Также стоит рассмотреть метод hue2rgb.conv, который преобразует положение на всех трех шкалах (HSV) в цвета форматов HEX (шестнадцатеричный) и RGB.
Поскольку шкала SV по определению предоставляет нам квадрат 100 на 100, а DIV, в котором может содержаться элемент выбора, может оказаться больше или меньше, нам необходимо определить шаг выбора. Все просто - делим перемещение курсора на 100 =) . Расчитаем отклонение цвета на SV от Hue. В зависимости от него вычисляем каждую из трех составляющих RGB и возвращаем полученное значение.
Метод getHex позволяет нам преобразовать полученное значение RGB в HEX-формат. RGB поступает в виде массива из трех элементов ([R,G,B]), после чего значение каждого из них конвертируется в шестнадцатеричный формат. Для того, что соблюсти соответствие с графическими программами, в случае, если значание канала представляет собой значение из одной цифры, то мы её дублируем (т.о. если мы на выходе конвертации получили значение канала f, то в значении цвета будет ff).
Переменная-объект tones представляет собой SV-область выбора. Внутри нее генерируется маркер-кружок, который графически демонстрирует текущий выбранный оттенок. Шаг курсора также расчитывается делением на 100.
Метод cPos отслеживает положение курсора внутри SV-области, конвертирует его в цвет и присваивает значения результирующим полям.
Остальное - обработчики событий. Думаю, не нужно их подробно описывать, иначе зачем мы все здесь собрались?
В планах на улучшение : добавить возможность ручного ввода цвета в поля и, как следствие, обратной конвертации; копирование HEX-цвета в буфер обмена. Если же у кого-то из Вас возникнет желание сделать это самостоятельно, то я с удовольствием предоставляю ссылку на мой репозиторий в GitHub
За сим все! Безошибочного Вам кода!