В этой серии из двух частей мы объединим универсальный элемент canvas с надежной библиотекой jQuery, чтобы создать плагин для построения графиков. Во второй части мы собираемся преобразовать его в плагин jQuery, а затем добавим немного конфет и дополнительных функций.
Завершая серию Fun with canvas из двух частей, сегодня мы собираемся создать плагин для построения графиков; заметьте, не обычный плагин. Мы собираемся показать некоторую любовь jQuery к элементу canvas, чтобы создать очень надежный плагин.
В первой части мы рассматривали исключительно реализацию логики плагина как отдельного скрипта. В конце первой части наша гистограмма выглядела так.
Результат в конце части 1
В этой заключительной части мы будем работать над преобразованием нашего кода и превращением его в надлежащий плагин jQuery, добавив некоторые визуальные тонкости и, наконец, включив некоторые дополнительные функции. В конечном итоге наш результат будет выглядеть так:
Готовый продукт
Все прогрелись? Давайте погрузимся в!
Плагин Формальности
Прежде чем мы начнем преобразовывать наш код в плагин, нам сначала нужно взглянуть на несколько формальностей, когда дело доходит до создания плагина.
Называя плагин
Мы начнем с выбора имени для плагина. Я выбрал barGraph и переименовал файл JavaScript в jquery.barGraph.js. Теперь мы вложим весь код из предыдущей статьи в следующий фрагмент.
1
2
3
|
$.fn.barGraph = function(settings) {
//code here
}
|
Настройки содержат все необязательные параметры, передаваемые плагину.
Работа вокруг проблемы $ Symbol
При разработке плагинов jQuery обычно рекомендуется использовать jQuery вместо псевдонима $ в вашем коде, чтобы минимизировать конфликты с другими библиотеками Javascript. Вместо того, чтобы преодолевать все эти проблемы, мы можем просто использовать пользовательские псевдонимы, как указано в документации по jQuery . Мы заключаем весь наш код плагина в эту самостоятельно выполняемую анонимную функцию, как показано ниже:
1
2
3
4
5
|
(function($) {
$.fn.barGraph = function(settings) {
//plugin implementation code here
}
})(jQuery);
|
По сути, мы инкапсулируем весь наш код в функцию и передаем ей jQuery. Теперь мы можем свободно использовать псевдоним $ столько, сколько нам нужно, внутри нашего кода, не беспокоясь о том, что он может конфликтовать с другими библиотеками JavaScript.
По умолчанию
При разработке плагина имеет смысл предоставить пользователю разумное количество настроек, при этом используя разумные параметры по умолчанию, если пользователи используют плагин, не передавая ему никаких опций. Имея это в виду, мы дадим возможность пользователю изменять каждую из переменных параметров графика, которые я упоминал в предыдущей статье этой серии. Это легко сделать; мы просто определяем каждую из этих переменных как свойства объекта, а затем получаем к ним доступ.
01
02
03
04
05
06
07
08
09
10
|
var defaults = {
barSpacing = 20,
barWidth = 20,
cvHeight = 220,
numYlabels = 8,
xOffset = 20,
maxVal,
gWidth=550,
gHeight=200;
};
|
Наконец, нам нужно объединить параметры по умолчанию с переданными параметрами, отдав предпочтение переданным. Эта линия заботится об этом.
1
|
var option = $.extend(defaults, settings);
|
Не забудьте изменить имена переменных, где это необходимо. Как в —
1
|
return (param*barWidth)+((param+1)*barSpacing)+xOffset;
|
…изменения в:
1
|
return (param*option.barWidth)+((param+1)*option.barSpacing)+option.xOffset;
|
Рефакторинг
Это где плагин выбит. Наша старая реализация могла создавать только один граф на странице, и способность создавать несколько графов на странице является основной причиной, по которой мы создаем плагин для этой функциональности. Кроме того, нам нужно убедиться, что пользователю не нужно создавать элемент canvas для каждого создаваемого графика. Имея это в виду, мы будем создавать элементы canvas динамически по мере необходимости. Давайте продолжим. Мы рассмотрим более ранние и обновленные версии соответствующих частей кода.
Вызов плагина
Прежде чем мы начнем, я хотел бы указать, как наш плагин будет вызываться.
1
2
3
4
5
6
|
$(«#years»).barGraph
({
barSpacing = 30,
barWidth = 25,
numYlabels = 12,
});
|
Просто как тот. Лет — это идентификатор таблицы, содержащей все наши значения. Мы передаем варианты по мере необходимости.
Получение источника данных
Для начала нам понадобится ссылка на источник данных для графиков. Теперь мы получаем доступ к исходному элементу и получаем его идентификатор. Добавьте следующую строку в группу графовых переменных, которые мы объявили ранее.
1
|
var dataSource = $(this).attr(«id»);
|
Мы определяем новую переменную и присваиваем ей значение атрибута ID переданного элемента. В нашем коде это относится к текущему выбранному элементу DOM. В нашем примере это относится к таблице с идентификатором лет .
В предыдущей реализации идентификатор источника данных был жестко запрограммирован. Теперь мы заменим его на атрибут ID, который мы извлекли ранее. Более ранняя версия функции grabValues приведена ниже:
01
02
03
04
05
06
07
08
09
10
11
12
|
function grabValues ()
{
// Access the required table cell, extract and add its value to the values array.
$(«#data tr td:nth-child(2)»).each(function(){
gValues.push($(this).text());
});
// Access the required table cell, extract and add its value to the xLabels array.
$(«#data tr td:nth-child(1)»).each(function(){
xLabels.push($(this).text());
});
}
|
Обновляется до этого:
01
02
03
04
05
06
07
08
09
10
11
12
|
function grabValues ()
{
// Access the required table cell, extract and add its value to the values array.
$(«#»+dataSource+» tr td:nth-child(2)»).each(function(){
gValues.push($(this).text());
});
// Access the required table cell, extract and add its value to the xLabels array.
$(«#»+dataSource+» tr td:nth-child(1)»).each(function(){
xLabels.push($(this).text());
});
}
|
Впрыскивание холста
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
function initCanvas ()
{
$(«#»+dataSource).after(«<canvas id=\»bargraph-«+dataSource+»\» class=\»barGraph\»> </canvas>»);
// Try to access the canvas element
cv = $(«#bargraph-«+dataSource).get(0);
if (!cv.getContext)
{ return;
// Try to get a 2D context for the canvas and throw an error if unable to
ctx = cv.getContext(‘2d’);
if (!ctx)
{ return;
}
|
Мы создаем элемент canvas и внедряем его в DOM после таблицы, которая выступает в качестве источника данных. Функция after в jQuery очень удобна. Атрибут класса barGraph и атрибут ID в формате barGraph-dataSourceID также применяются, чтобы позволить пользователю стилизовать их все как группу или индивидуально по мере необходимости.
Езда на велосипеде через пройденные элементы
Есть два способа вызвать этот плагин на самом деле. Вы можете либо создать каждый график отдельно, передавая только один источник данных, либо передать несколько источников. В последнем случае наша текущая конструкция встретится с ошибкой и завершится. Чтобы исправить это, мы используем каждую конструкцию для перебора набора переданных элементов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
(function($){
$.fn.barGraph = function(settings) {
// Option variables
var defaults = {
// options here
};
// Merge the passed parameters with the defaults
var option = $.extend(defaults, settings);
// Cycle through each passed object
this.each(function() {
// Implementation code here
});
// Returns the jQuery object to allow for chainability.
return this;
}
})(jQuery);
|
Мы инкапсулируем весь код после получения и объединения настроек внутри конструкции this.each . Мы также обязательно возвращаем объект jQuery в конце, чтобы включить возможность цепочки.
На этом наш рефакторинг завершен. Мы должны иметь возможность вызывать наш плагин и создавать столько графиков, сколько необходимо.
Добавление глазных конфет
Теперь, когда наше преобразование завершено, мы можем сделать его визуально лучше. Мы собираемся сделать несколько вещей здесь. Мы рассмотрим каждый из них в отдельности.
Темы
Более старая версия использовала мягкий серый для рисования графиков. Мы собираемся внедрить механизм тем для баров. Это само по себе состоит из серии шагов.
Океан: тема по умолчанию
листва
вишня в цвету
Спектр
Добавление его в настройки
1
2
3
4
|
var defaults = {
// Other defaults here
theme: «Ocean»,
};
|
Мы добавляем опцию темы к настройкам по умолчанию, позволяя пользователю изменить тему на любую из четырех доступных предустановок.
Установка текущей выбранной темы
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
function grabValues ()
{
// Previous code
switch(option.theme)
{
case ‘Ocean’:
gTheme = thBlue;
break;
case ‘Foliage’:
gTheme = thGreen;
break;
case ‘Cherry Blossom’:
gTheme = thPink;
break;
case ‘Spectrum’:
gTheme = thAssorted;
break;
}
}
|
Простая конструкция переключателя просматривает настройку option.theme и указывает переменную gTheme на массив необходимых цветов. Мы используем описательные имена для тем вместо общих.
Определение массива цветов
1
2
3
4
5
|
// Themes
var thPink = [‘#FFCCCC’,’#FFCCCC’,’#FFC0C0′,’#FFB5B5′,’#FFADAD’,’#FFA4A4′,’#FF9A9A’,’#FF8989′,’#FF6D6D’];
var thBlue = [‘#ACE0FF’,’#9CDAFF’,’#90D6FF’,’#86D2FF’,’#7FCFFF’,’#79CDFF’,’#72CAFF’,’#6CC8FF’,’#57C0FF’];
var thGreen = [‘#D1FFA6′,’#C6FF91′,’#C0FF86′,’#BCFF7D’,’#B6FF72′,’#B2FF6B’,’#AAFE5D’,’#A5FF51′,’#9FFF46′];
var thAssorted = [‘#FF93C2′,’#FF93F6′,’#E193FF’,’#B893FF’,’#93A0FF’,’#93D7FF’,’#93F6FF’,’#ABFF93′,’#FF9B93′];
|
Затем мы определяем количество массивов, каждый из которых содержит серию оттенков определенного цвета. Они начинают с более светлого оттенка и продолжают увеличиваться. Мы пройдемся по этим массивам позже. Добавление тем так же просто, как добавление массива для нужного вам цвета, а затем изменение предыдущего переключателя для отражения изменений.
Вспомогательная функция
1
2
3
4
|
function getColour (param)
{
return Math.ceil(Math.abs(((gValues.length/2) -param)));
}
|
Это крошечная функция, которая позволяет нам достигать и применять градиентоподобный эффект к графикам. По сути, мы вычисляем абсолютную разницу между половиной числа значений, которые должны быть представлены, и переданным параметром, который является индексом выбранного в данный момент элемента в массиве. Таким образом, мы можем создать плавный градиент. Поскольку мы определили только девять цветов в каждом массиве цветов, мы ограничены восемнадцатью значениями графика. Расширение этого числа должно быть довольно тривиальным.
Установка fillStyle
01
02
03
04
05
06
07
08
09
10
|
function drawGraph ()
{
for(index=0; index<gValues.length; index++)
{
ctx.save();
ctx.fillStyle = gTheme[getColour(index)];
ctx.fillRect( x(index), y(gValues[index]), width(), height(gValues[index]));
ctx.restore();
}
}
|
Это где мы на самом деле темы графиков. Вместо того чтобы устанавливать статическое значение для свойства fillStyle , мы используем функцию getColour для получения необходимого индекса элемента в массиве текущей выбранной темы.
помутнение
Далее мы дадим пользователю возможность контролировать прозрачность нарисованных баров. Настройки это двухступенчатый процесс.
Без прозрачности
Со значением 0,8
Добавление его в настройки
1
2
3
4
|
var defaults = {
// Other defaults here
barOpacity : 0.8,
};
|
Мы добавляем опцию barOpacity к значениям по умолчанию, позволяя пользователю изменять непрозрачность графиков до значения от 0 до 1, где 0 полностью прозрачен, а 1 полностью непрозрачен.
Установка глобальной альфы
01
02
03
04
05
06
07
08
09
10
11
|
function drawGraph ()
{
for(index=0; index<gValues.length; index++)
{
ctx.save();
ctx.fillStyle = gTheme[getColour(index)];
ctx.globalAlpha = option.barOpacity;
ctx.fillRect( x(index), y(gValues[index]), width(), height(gValues[index]));
ctx.restore();
}
}
|
Свойство globalAlpha контролирует непрозрачность или прозрачность отображаемого элемента. Мы устанавливаем значение этого свойства в переданное значение или значение по умолчанию, чтобы добавить немного прозрачности. В качестве разумного значения по умолчанию мы используем значение 0,8, чтобы сделать его немного прозрачным.
сетка
Сетка может быть чрезвычайно полезна при обработке данных, представленных на графике. Хотя изначально мне требовалась правильная сетка, позже я остановился на серии горизонтальных линий, совпадающих с метками оси Y, и полностью отбросил вертикальные линии, поскольку они просто мешали данным. После этого давайте реализуем способ визуализации.
С сеткой отключена
С включенной сеткой
Создание линий с использованием путей и метода lineTo казалось наиболее очевидным решением для рисования графиков, но я столкнулся с ошибкой рендеринга, которая сделала этот подход непригодным. Поэтому я придерживаюсь метода fillRect для создания этих строк. Вот функция в полном объеме.
1
2
3
4
5
6
7
8
|
function drawGrid ()
{
for(index=0; index<option.numYlabels; index++)
{
ctx.fillStyle = «#AAA»;
ctx.fillRect( option.xOffset, y(yLabels[index])+3, gWidth, 1);
}
}
|
Это очень похоже на отрисовку меток оси Y, за исключением того, что вместо отрисовки метки мы рисуем горизонтальную линию, охватывающую ширину графика шириной 1 пиксель. Функция у помогает нам в позиционировании.
Добавление его в настройки
1
2
3
4
|
var defaults = {
// Other defaults here
disableGrid : false,
};
|
Мы добавляем параметр disableGrid к значениям по умолчанию, позволяя пользователю контролировать, отображается ли сетка или нет. По умолчанию он отображается.
1
2
|
// Function calls
if(!option.disableGrid) { drawGrid();
|
Мы просто проверяем, хочет ли пользователь отображать сетку, и действуем соответственно.
контуры
Теперь, когда все полосы окрашены, на светлом фоне не хватает акцента. Чтобы исправить это, нам нужен ход в 1 пиксель. Есть два способа сделать это. Первый и самый простой способ — просто добавить метод strokeRect в метод drawGraph ; или мы могли бы использовать метод lineTo для быстрого обводки прямоугольников. Я выбрал прежний маршрут, поскольку, как и прежде, метод lineTo выдал мне странную ошибку рендеринга.
Без поглаживания
С поглаживанием
Добавление его в настройки
Сначала мы добавляем его к объекту по умолчанию, чтобы дать пользователю контроль над тем, применяется он или нет.
1
2
3
4
|
var defaults = {
// Other defaults here
showOutline : true,
};
|
01
02
03
04
05
06
07
08
09
10
11
|
function drawGraph ()
{
// Previous code
if (option.showOutline)
{
ctx.fillStyle = «#000»;
ctx.strokeRect( x(index), y(gValues[index]), width(), height(gValues[index]));
}
// Rest of the code
}
}
|
Мы проверяем, хочет ли пользователь отобразить контуры, и, если да, мы продолжаем. Это почти то же самое, что и рендеринг реальных баров, за исключением того, что вместо использования метода fillRect мы используем метод strokeRect .
затенение
В исходной реализации нет различия между самим элементом canvas и фактическим пространством рендеринга панелей. Мы исправим это сейчас.
Без затенения
С затенением
1
2
3
4
5
|
function shadeGraphArea ()
{
ctx.fillStyle = «#F2F2F2»;
ctx.fillRect(option.xOffset, 0, gWidth-option.xOffset, gHeight);
}
|
Это крошечная функция, которая затеняет необходимую область. Мы покрываем элемент canvas за вычетом области, покрытой метками обеих осей. Первые два параметра указывают на координаты x и y начальной точки, а последние два указывают на требуемую ширину и высоту. Начиная с option.offset , мы удаляем область, покрытую метками оси Y, и ограничивая высоту до gHeight , мы удаляем метки оси X.
Добавление функций
Теперь, когда наш график выглядит достаточно симпатично, мы можем сосредоточиться на добавлении некоторых новых функций в наш плагин. Мы рассмотрим каждый в отдельности.
Рассмотрим этот график знаменитых пиков 8K.
Когда самое высокое значение достаточно высоко, и большинство значений находится в пределах 10% от максимального значения, график перестает быть полезным. У нас есть два способа исправить это.
ShowValue
Сначала мы собираемся начать с более простого решения. При отображении значения соответствующих графиков вверху, проблема практически решена, поскольку отдельные значения могут быть легко дифференцированы. Вот как это реализовано.
1
2
3
4
|
var defaults = {
// Other defaults here
showValue: true,
};
|
Сначала мы добавляем запись в объект по умолчанию, чтобы пользователь мог включать и выключать его по своему желанию.
1
2
|
// Function calls
if(option.showValue) { drawValue();
|
Мы проверяем, хочет ли пользователь отображать значение, и действуем соответственно.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
function drawValue ()
{
for(index=0; index<gValues.length; index++)
{
ctx.save();
ctx.fillStyle= «#000»;
ctx.font = «10px ‘arial'»;
var valAsString = gValues[index].toString();
var valX = (option.barWidth/2)-(valAsString.length*3);
ctx.fillText(gValues[index], x(index)+valX, y(gValues[index])-4);
ctx.restore();
}
}
|
Мы перебираем массив gValues и отрисовываем каждое значение отдельно. Вычисления, включающие valAsString и valX, являются ничем иным, как крошечными вычислениями, которые помогают нам в правильных отступах, поэтому они не выглядят неуместными.
Масштаб
Это сложнее из двух решений. В этом методе вместо того, чтобы начинать метки оси Y с 0, мы начинаем намного ближе к минимальному значению. Я объясню, как мы идем. Обратите внимание, что в приведенном выше примере разница между последующими значениями по отношению к максимальному значению довольно незначительна и не так сильно показывает ее эффективность. Другие наборы данных должны облегчить анализ результатов.
Добавление его в настройки
1
2
3
4
|
var defaults = {
// Other defaults here
scale: false
};
|
Обновление функции масштабирования
Поскольку функция масштабирования является неотъемлемой частью процесса рендеринга, нам необходимо обновить ее, чтобы включить функцию масштабирования. Мы обновляем это так:
1
2
3
4
|
function scale (param)
{
return ((option.scale) ? Math.round(((param-minVal)/(maxVal-minVal))*gHeight) : Math.round((param/maxVal)*gHeight));
}
|
Я знаю, что это выглядит немного сложным, но это выглядит так только благодаря использованию троичного условного оператора. По сути, мы проверяем значение option.scale и, если оно говорит false, старый код выполняется. Если это правда, вместо нормализации значения как функции от максимального значения в массиве, мы теперь нормализуем его как функцию от разницы между максимальным и минимальным значениями. Что приводит нас к:
Обновление функции maxValues
Теперь нам нужно выяснить как максимальное, так и минимальное значение, а не только максимальное, которое мы имели до этого. Функция обновлена до этого:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
function minmaxValues (arr)
{
maxVal=0;
for(i=0; i<arr.length; i++)
{
if (maxVal<parseInt(arr[i]))
{
maxVal=parseInt(arr[i]);
}
}
minVal=maxVal;
for(i=0; i<arr.length; i++)
{
if (minVal>parseInt(arr[i]))
{
minVal=parseInt(arr[i]);
}
}
maxVal*= 1.1;
minVal = minVal — Math.round((maxVal/10));
}
|
Я уверен, что вы могли бы сделать то же самое в одном цикле, не используя столько строк кода, сколько я, но в то время я чувствовал себя особенно не креативно, так что терпите меня. С учетом формальностей вычислений мы увеличиваем переменную maxVal на 5% и переменную minVal , вычитаем значение, равное 5% значения maxVal . Это делается для того, чтобы полосы не касались вершины каждый раз, а различия между метками на каждой оси Y были одинаковыми.
Обновление функции drawYlabels
Завершив все основы, мы приступаем к обновлению процедуры рендеринга метки оси Y, чтобы отразить масштабирование.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
function drawYlabels()
{
ctx.save();
for(index=0; index<option.numYlabels; index++)
{
if (!option.scale)
{
yLabels.push(Math.round(maxVal/option.numYlabels*(index+1)));
}
else
{
var val= minVal+Math.ceil(((maxVal-minVal)/option.numYlabels)*(index+1));
yLabels.push(Math.ceil(val));
}
ctx.fillStyle = option.labelColour;
var valAsString = yLabels[index].toString();
var lblX = option.xOffset — (valAsString.length*7);
ctx.fillText(yLabels[index], lblX, y(yLabels[index])+10);
}
if (!option.scale)
{
ctx.fillText(«0», option.xOffset -7, gHeight+7);
}
else
{
var valAsString = minVal.toString();
var lblX = option.xOffset — (valAsString.length*7);
ctx.fillText(minVal, lblX, gHeight+7);
}
ctx.restore();
}
|
Довольно мясистое обновление, если вы спросите меня! Суть функции остается прежней. Мы просто проверяем, активировал ли пользователь масштабирование, и разветвляем код по мере необходимости. Если этот параметр включен, мы изменяем способ назначения меток Y, чтобы они соответствовали новому алгоритму. Вместо максимального значения, разделенного на n чисел с равным интервалом, мы теперь вычисляем разницу между максимальным и минимальным значением, делим его на равномерно распределенные числа и добавляем его к минимальному значению, чтобы построить наш массив меток оси Y. После этого мы продолжаем как обычно, визуализируя каждую метку отдельно. Поскольку мы рендерили самый нижний 0 вручную, мы должны проверить, включено ли масштабирование, а затем отобразить минимальное значение на его месте. Не обращайте внимания на небольшие числовые добавления к каждому передаваемому параметру; это просто для того, чтобы убедиться, что каждый элемент графика выстраивается в соответствии с ожиданиями.
Динамическое изменение размера
В нашей предыдущей реализации мы жестко закодировали размеры графика, что представляет значительную трудность при изменении числа значений. Мы собираемся исправить это сейчас.
Добавление его в настройки
1
2
3
4
|
var defaults = {
// Other defaults here
cvHeight: 250, //In px
};
|
Мы позволяем пользователю установить высоту элемента canvas отдельно. Все остальные значения рассчитываются динамически и применяются по мере необходимости.
Обновление функции initCanvas
Функция initCanvas обрабатывает всю инициализацию холста и, следовательно, должна быть обновлена для реализации новой функциональности.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
function initCanvas ()
{
$(«#»+dataSource).after(«<canvas id=\»bargraph-«+dataSource+»\» class=\»barGraph\»> </canvas>»);
// Try to access the canvas element
cv = $(«#bargraph-«+dataSource).get(0);
cv.width=gValues.length*(option.barSpacing+option.barWidth)+option.xOffset+option.barSpacing;
cv.height=option.cvHeight;
gWidth=cv.width;
gHeight=option.cvHeight-20;
if (!cv.getContext)
{ return;
// Try to get a 2D context for the canvas and throw an error if unable to
ctx = cv.getContext(‘2d’);
if (!ctx)
{ return;
}
|
После внедрения элемента canvas мы получаем ссылку на созданный элемент. Ширина элемента canvas рассчитывается как функция количества элементов в массиве — gValues , расстояния между каждым баром — option.barSpacing , ширины самого бара — option.barWidth и, наконец, option.xOffset . Ширина графика изменяется динамически в зависимости от каждого из этих параметров. Высота может быть изменена пользователем и по умолчанию равна 220px с областью рендеринга для самого бара, равной 220px. 20 пикселей назначается меткам оси X.
Сокрытие источника
Имеет смысл, что пользователь может захотеть скрыть исходную таблицу после создания графика. Имея это в виду, мы позволяем пользователю решать, удалять таблицу или нет.
1
2
3
4
|
var defaults = {
// Other defaults here
hideDataSource: true,
};
|
1
|
if (option.hideDataSource) { $(«#»+dataSource).remove();}
|
Мы проверяем, хочет ли пользователь скрыть таблицу, и если да, мы полностью удаляем ее из DOM, используя метод удаления jQuery.
Оптимизация нашего кода
Теперь, когда вся тяжелая работа выполнена, мы можем рассмотреть, как оптимизировать наш код. Поскольку этот код был написан исключительно для учебных целей, большая часть работы была заключена в отдельные функции, и, кроме того, они намного более многословны, чем должны быть.
Если вы действительно хотите самый простой из возможных кодов, весь наш плагин, исключая инициализацию и вычисления, может быть переписан в два цикла. Один цикл по массиву gValues для рисования самих столбцов и меток оси X; и второй цикл, повторяющийся от 0 до numYlabels для отображения сетки и меток оси Y. Код выглядел бы намного более запутанным, однако это должно привести к значительно меньшей базе кода.
Резюме
Вот и все, ребята! Мы создали плагин высокого уровня с нуля. Мы рассмотрели ряд тем в этой серии, в том числе:
- Рассмотрим схему рендеринга элемента canvas.
- Некоторые из методов рендеринга элемента canvas.
- Нормализация значений позволяет нам выразить это как функцию другого значения.
- Некоторые полезные методы извлечения данных с использованием jQuery.
- Основная логика рендеринга графа.
- Преобразование нашего скрипта в полноценный плагин jQuery.
- Как улучшить его визуально и еще более расширить его функциональность.
Надеюсь, вам было так же весело читать это, как и мне. Это работа с 270 с лишним строк, я уверен, что что-то пропустил. Не стесняйтесь нажимать на комментарии и спрашивать меня. Или критикуй меня. Или похвали меня. Вы знаете, это ваш звонок! Удачного кодирования!