Найти тему
Игорь Назаров

Графический модуль

После того, как мы расширили функционал массива, можно приступать к созданию модуля отрисовки. Его задача - принять массивы данных, масштабировать их к области отрисовки экрана и затем выводить на элемент canvas.

Начнем с того, что в ранее намеченном (и пока пустом graphics.js) создадим заготовку для класса графики. Вот так:

Конструктор для объекта-отрисовщика
Конструктор для объекта-отрисовщика

Здесь handler - ссылка на элемент canvas, в котором будет происходить отрисовка, context - контекст отрисовки, на котором выполняются команды по выводу графики. Пустые пока что объекты lineStyle, markerStyle, axisStyle, numberStyle, tickStyle - это заготовки под хранение данных об отрисовке отдельных элементов графиков - самого графика функции, маркеров точек, координатный осей, чисел на графике и рисок на координатных осях.

Переменные scaleX, scaleY, dX, dY - параметры масштабирования и переноса области отрисовки графика относительно начала координат. Они вычисляются из тех соображений, что минимальные координаты X и Y соответствуют левому и нижней краю графика, а максимальные - верхнему и правому.

graphMargin - параметр, соответствующий дополнительному масштабированию, чтобы создать дополнительный отступ вокруг области построения

Теперь определим метод init, который связывает объект-отрисовщик со ссылкой на элемент canvas:

Метод-инициализатор, связующий наш объект с html-элементом canvas
Метод-инициализатор, связующий наш объект с html-элементом canvas

Чтобы сразу после инициализации можно было вызывать другие методы, мы попросим возвращать нам ссылку на объект - через return this.

Мы уже упоминали про масштабирование. Размеры холста ограничены (в предыдущем примере для канвы отрисовки была задана ширина и высота в 750 px), а значения, которые мы будем выводить, могут быть как порядка миллионов, так и порядка тысячных.

Метод масштабирования. Основан на простых линейных преобразованиях.
Метод масштабирования. Основан на простых линейных преобразованиях.

Преобразования в этом модуле сжимают(или растягивают) отрезок от xMin до xMax и от yMin до yMax (границы отрезков значений независимой переменной и значений функции) до области построения экрана, а затем переносят точки xMin и yMin в начало области отрисовки. Стоит учесть, что по умолчанию ось Y на html-канве направлена вниз (а потому мы делаем масштаб по оси Y со знаком "минус").

Теперь мы можем масштабировать произвольные числа, приводя их к области отрисовки через функции transformX и transformY:

Масштабирование по каждой из осей
Масштабирование по каждой из осей

Когда базовые процедуры готовы, можно приступать к самой отрисовке. Функция будет принимать на вход два расширенных массива (поскольку JS не является сильно типизированным языком, то здесь нужна осторожность, и по-хорошему нужно продумать случай, когда неосторожный пользователь попытается запитать функцию обычными массивами).

Метод-отрисовщик
Метод-отрисовщик

Этот метод оценивает полученные массивы, находя их граничные элементы, а затем запускает методы adjust (получает коэффициенты масштабирования и сдвига) и drawAxis (метод отрисовки осей и вывода числовых подписей, опишем его чуть позже, он пусть и простой, но достаточно громоздкий)

После всех приготовлений мы масштабируем первую точку, переходим в нее, затем масштабируем последующую точку, строим между ними линию, после чего "предыдущая" точка получает координаты "последующей". В результате прохода по всему массиву получается кусочно-линейный график.

Теперь - отрисовка осей. Ничего сложно, но в ней используется пара приятных языковых нюансов:

Метод отрисовки осей и нанесения рисок
Метод отрисовки осей и нанесения рисок

Сначала в методе с помощью функций масштабирования определяются границы отрезка и шаги между рисками на осях X и Y. Затем с помощью новой фичи `` - строкового шаблона, внутри которого можно заключать выражения js в обертке ${...всякий жабоскриптовый код...}, мы назначаем стиль для выводимых значений.

В самом начале создания модуля отрисовки мы задали в конструкторе пустые объекты для свойств элементов графики. Теперь наполним их содержанием:

Стили элементов графика
Стили элементов графика

Теперь для всех элементов графика сформированы стили, мы можем масштабировать область построения, выводить и подписывать оси графика, выводить сам график.

Осталось объединить эти элементы вместе и испытать в нашем html-
шаблоне.

Запуск модуля графики на загрузке документа
Запуск модуля графики на загрузке документа

Мы создаем для документа обработчик события DOMContentLoaded ( которое выстреливает, когда изначальный html загружен и отпарсен, но очередь до стилей еще не дошла). Мы создаем два расширенных массива для независимой переменной и значения функции - range и funcValues, затем создаем объект графики testGrapher и сначала крепим его к канве через init (канвы мы вытаскиваем через querySelector, поскольку она всего одна в документе), а затем запускаем метод отрисовки графика drawGraphic.

Результат запуска с локальной машины:

График тестовой функции
График тестовой функции

Теперь осталось разобраться с тем, ради чего все затевалось - с численным решением уравнений. Но это - тема следующей статьи.