После того, как мы расширили функционал массива, можно приступать к созданию модуля отрисовки. Его задача - принять массивы данных, масштабировать их к области отрисовки экрана и затем выводить на элемент canvas.
Начнем с того, что в ранее намеченном (и пока пустом graphics.js) создадим заготовку для класса графики. Вот так:
Здесь handler - ссылка на элемент canvas, в котором будет происходить отрисовка, context - контекст отрисовки, на котором выполняются команды по выводу графики. Пустые пока что объекты lineStyle, markerStyle, axisStyle, numberStyle, tickStyle - это заготовки под хранение данных об отрисовке отдельных элементов графиков - самого графика функции, маркеров точек, координатный осей, чисел на графике и рисок на координатных осях.
Переменные scaleX, scaleY, dX, dY - параметры масштабирования и переноса области отрисовки графика относительно начала координат. Они вычисляются из тех соображений, что минимальные координаты X и Y соответствуют левому и нижней краю графика, а максимальные - верхнему и правому.
graphMargin - параметр, соответствующий дополнительному масштабированию, чтобы создать дополнительный отступ вокруг области построения
Теперь определим метод init, который связывает объект-отрисовщик со ссылкой на элемент 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.
Результат запуска с локальной машины:
Теперь осталось разобраться с тем, ради чего все затевалось - с численным решением уравнений. Но это - тема следующей статьи.