График на Canvas
В этой демонстрации мы создадим столбчатый график, используя Canvas API. Это интерфейс для отрисовки графики в браузере. С помощью HTML-элемента canvas
можно создавать холст (именно так canvas переводится с английского) и рисовать графику внутри него с помощью JavaScript-кода.
Для начала напишем разметку. Кроме самого графика также создадим форму для сбора данных, на основе которых будет строиться график.
Пропишем элементу canvas
размер 500×250 пикселей. По умолчанию он равен 300×150 пикселей. А также оставим внутри canvas
информационное сообщение на случай, если браузер пользователя не поддерживает эту технологию.
Теперь пропишем элементам стилизацию.
Прежде чем рисовать график, получим данные из формы. Для этого найдём все поля ввода в форме и создадим на основе введённых значений массив объектов с информацией о каждом элементе графика. В нашем случае это будут языки JavaScript, PHP и Python — три объекта.
Функция getData()
получает на вход коллекцию элементов, преобразует её в массив, а затем на основе каждого элемента создаёт объект с нужными данными: названием (язык программирования), значением (популярность в процентах) и цветом (его будем использовать для рисования столбца на графике). Цвет можно не задавать константой, а сгенерировать в формате HEX с помощью JavaScript, например. Тогда получится избежать жёсткой привязки к количеству элементов.
Из элемента canvas
можно получить объект, который называется контекстом отрисовки. Объект содержит свойства и методы для рисования, именно с помощью него можно создавать весь контент внутри Canvas, а также манипулировать им. Для получения объекта контекста нужно воспользоваться методом getContext()
:
В качестве параметра в метод getContext()
передадим значение 2d
— это контекст отрисовки для работы с двумерной графикой. Именно его мы будем использовать, но есть и другие — например, webgl
для трёхмерной графики.
Создадим функцию для отрисовки графика. На вход она должна получать массив объектов с данными из формы.
График будет состоять из столбцов определённой высоты и подписей к каждому из них. Мы будем отрисовывать их в цикле, проходясь по элементам массива items.
Для того, чтобы можно было следить за результатом отрисовки, сразу напишем обработчик события submit
, которое будет происходить при отправке формы с данными. Вызовем в этот момент функцию renderChart()
, передав данные в параметры.
Вычислим высоту столбца с учётом процентов. Все координаты, размеры и прочее вынесем в константы или перечисления.
Зададим цвет столбца и подписи с помощью свойства fillStyle. Все свойства и методы будем вызывать у контекста отрисовки ctx
, который создали ранее.
С помощью свойства font
укажем параметры шрифта для подписей. Синтаксис такой же как у CSS-свойства font
.
Подписи расположем вертикально, чтобы они шли параллельно столбцам. По умолчанию текст отрисовывается как обычно — слева направо. Чтобы изменить это поведение, нужно повернуть систему координат. По умолчанию её центр распооложен в левом верхнем углу холста — повернём её так, чтобы он оказался в нижнем левом углу. Для этого понадобятся методы translate()
и rotate()
.
translate(x, y)
примает два параметра и перемещает начало координат холста на x
по горизонтали и y
по вертикали относительно начального положения.
rotate(angle)
поворачивает систему координат по часовой стрелке на указанный угол. Значение задаётся в радианах.
Отрисуем текстовую строку с подписью в изменённой системе координат. Для отрисовки текста используется метод fillText(`text`, x, y)
, где координата x
определяет расстояние от точки отсчёта по горизонтальной оси, а y
— по вертикальной. Помним, что начало отсчёта сейчас расположено в левом нижнем углу, ось x
направлена вверх, а y
— вправо.
Для каждой последующей подписи обновим начальную координату по оси y
, чтобы учесть промежуток между столбцами.
Если сейчас задать в форме значения и нажать кнопку «Показать график», надписи отрисуются, но произойдёт что-то странное. Надпись для первого столбца отрисуется на своём месте, вторая окажется совсем не там, где задумывалось, а третья вообще улетит куда-то за границы холста. Давайте разберёмся, почему так происходит.
На каждой интерации цикла мы изменяем систему координат, а нужно сделать это один раз и потом вернуться к изначальному значению.
Реализуем это с помощью методов save()
и restore()
. Они позволяют сохранить текущее состояние холста в какой-то момент выполнения программы, а затем восстановить это состояние при необходимости. Теперь надписи располагаются как задумано.
Теперь отрисуем сами столбцы. Для этого нам нужен метод fillRect(x, y, width, height)
, который рисует прямоугольник с заливкой с указанными шириной и высотой, начиная с координат x
и y
.
Всё почти готово — график отрисовывается с учётом введённых значений, но есть одна проблема. При повторной отправке формы с другими данными график отрисовывается повторно поверх предыдущей версии.
Чтобы решить эту проблему, воспользуемся перед началом отрисовки методом clearRect(x, y, width, height)
, который принимает те же параметры, что метод fillRect()
, но вместо того, чтобы отрисовывать прямоугольник, очищает его. Очистим весь холст, передав в параметрах его ширину и высоту.
Готово! Более подробный разбор этого графика можно найти в нашем туториале.