1. Web Design
  2. HTML/CSS
  3. HTML

Как рисовать гистограммы используя JavaScript и HTML5

В ранних уроках мы описывали как нарисовать график в виде куска пирога или пончика используя HTML5. В этом уроке я покажу как использовать JavaScript и HTML5 чтобы отобразить графически данные используя графики.
Scroll to top

Russian (Pусский) translation by Andy Yur (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

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

Простой способ создать графики используя код, к примеру используя полную библиотеку графиков из CodeCanyon.

Infographic charts and graphics HTML tags libraryInfographic charts and graphics HTML tags libraryInfographic charts and graphics HTML tags library
Инфографика библиотеки графиков из CodeCanyon

Но если вы хотите знать что нужно для того чтобы создать библиотеку как эту, этот урок для вас.

Что такое линейная диаграмма?

Линейные графики очень востребовательный инструмент, который используют для представления числовых данных. От финансовых отчётов в презентациях PowerPoint до инфографиков, линейные графики используются в отображении числовых данных, которые легко понять.

Линейные график представляют числовые бары использования данных, которые являются прямоугольниками или с их шириной или с высотой, пропорциональными числовыми данными, которые они предоставляют.

Существует много типов линейных графиков:

  • горизонтальный и вертикальный графики, в зависимости от ориентации
  • сложенные гистограммы или классические графики для представления многократной серии данных
  • гистограммы 2В или 3D
  • прочие

Какие компоненты у гистограмм?

Давайте посмотрим на компоненты, которые составляют гистограмму независимо от ее типа:

Components of a bar chartComponents of a bar chartComponents of a bar chart
  • Данные диаграммы: это наборы чисел и связанных категорий, которые представлены диаграммой.
  • Название серии данных (1)
  • Диаграмма графика (2): справочная система представлена так, чтобы визуальное восприятие могло быть понятным.
  • Гистограмма (3): цветные прямоугольники с размерами, соответствующие данным.
  • Описание диаграммы (4): Показывает описание каждого цвета прямоугольника и соответствующему ему значение.

Теперь мы знаем компоненты гистограммы, а теперь посмотрим, как мы сможем написать код JavaScript для прорисовки диаграммы вроде этой.

Рисуем диаграмму используя JavaScript

Настраиваем проект JavaScript

Для старта прорисовки с использованием JavaScript и HTML5 мы нужно настроить проект вот так:

  • Создать папку для файлов проекта и назовём её bar-chart-tutorial.
  • В папке проекта создайте файл и назовите его index.html. Он будет содержать наш HTML-код
  • Также в папку проекта добавим ещё одни файл с названием script.js. В нём будет содержаться код JavaScript для прорисовки диаграммы.

Мы будем выполнять всё очень просто и добавим следующий код во внутрь index.html:

1
<html>
2
<body>
3
    <canvas id="myCanvas"></canvas>
4
    <script type="text/javascript" src="script.js"></script>
5
</body>
6
</html>

У нас есть элемент <canvas> с id myCanvas, поэтому мы можем ссылаться на него в нашем коде JavaScript. Тогда мы загрузим наш скрипт с помощью тега <script>.

Добавьте следующий код в файл script.js:

1
var myCanvas = document.getElementById("myCanvas");
2
myCanvas.width = 300;
3
myCanvas.height = 300;
4
 
5
var ctx = myCanvas.getContext("2d");

Это даёт ссылку на элемент и тогда определим ширину и высоту в 300 пикселей. Для прорисовки на странице, нам нужно только сослаться на 2D контекст, который содержит все методы прорисовки.

Добавляем несколько вспомогательных функций

Рисование гистограммы требует только знания, как потянуть два элемента:

  • рисование линии: для рисования линий в сетке
  • рисование цветного прямоугольника: для рисования гистограммы

Создадим вспомогательную функцию для этих двух элементов. Мы добавим функцию в наш файл script.js.

1
function drawLine(ctx, startX, startY, endX, endY,color){
2
    ctx.save();
3
    ctx.strokeStyle = color;
4
    ctx.beginPath();
5
    ctx.moveTo(startX,startY);
6
    ctx.lineTo(endX,endY);
7
    ctx.stroke();
8
    ctx.restore();
9
}

Функция drawLine предлагает шесть параметров:

  1. ctx: ссылается на нарисованный контекст
  2. startX: координата X стартовой точки линии
  3. startY: координата Y стартовой точки линии
  4. endX: координата X конечной точки линии
  5. endY: координата Y конечной точки линии
  6. color: цвет линии

Мы модифицируем настройки цвета для strokeStyle. Это определит цвета, которые будут использоваться в прорисовке линии. Мы используем ctx.save() и ctx.restore(), поэтому мы не затронем цвета, использующиеся за пределами этой функции.

Мы нарисуем линию с названием beginPath(). Это проинформирует нарисованному контексту, что мы начали рисовать что-то новое на странице. Мы используем moveTo() для выбора стартовой точки, с названием lineTo() для указания конечной точки и тогда сделать актуальную прорисовку под названием stroke().

Другая дополнительная функция нужна нам для прорисовки диаграммы, которая является цветным прямоугольником. Добавим его в script.js:

1
function drawBar(ctx, upperLeftCornerX, upperLeftCornerY, width, height,color){
2
    ctx.save();
3
    ctx.fillStyle=color;
4
    ctx.fillRect(upperLeftCornerX,upperLeftCornerY,width,height);
5
    ctx.restore();
6
}

Функция drawBar предлагает шесть параметров:

  1. ctx: ссылается на нарисованный контекст
  2. upperLeftCornerX: координата X диаграммы верхнего левого угла
  3. upperLeftCornerY: координата X диаграммы верхнего левого угла
  4. width: ширина диаграммы
  5. height: высота диаграммы
  6. color: цвет диаграммы

Информационная модель гистограммы

Теперь у нас есть дополнительные функции, давайте перенесём в информационную модель гистограммы. Все типы диаграмм имеют информационную модель за ними. Информационная модель построена на числовых данных. Для этого урока мы будем использовать серию данных категорий и их связанные числовые значения представляющих количество виниловых записей из моей коллекции записей, сгруппированных по музыкальным жанрам:

  • Классическая музыка: 10
  • Альтернативный рок: 14
  • Поп: 2
  • Джаз: 12

Мы можем изобразить это в JavaScript в форме объекта. Давайте добавим это в файл script.js:

1
var myVinyls = {
2
    "Classical music": 10,
3
    "Alternative rock": 14,
4
    "Pop": 2,
5
    "Jazz": 12
6
};

Реализуем компонент гистограммы

Давайте реализуем компонент, который делает актуальную прорисовку нашей гистограммы. Мы сделаем это через добавление объекта JavaScript в наш script.js:

1
var Barchart = function(options){
2
    this.options = options;
3
    this.canvas = options.canvas;
4
    this.ctx = this.canvas.getContext("2d");
5
    this.colors = options.colors;
6
 
7
    this.draw = function(){
8
        var maxValue = 0;
9
        for (var categ in this.options.data){
10
            maxValue = Math.max(maxValue,this.options.data[categ]);
11
        }
12
        var canvasActualHeight = this.canvas.height - this.options.padding * 2;
13
        var canvasActualWidth = this.canvas.width - this.options.padding * 2;
14
15
        //drawing the grid lines

16
        var gridValue = 0;
17
        while (gridValue <= maxValue){
18
            var gridY = canvasActualHeight * (1 - gridValue/maxValue) + this.options.padding;
19
            drawLine(
20
                this.ctx,
21
                0,
22
                gridY,
23
                this.canvas.width,
24
                gridY,
25
                this.options.gridColor
26
            );
27
            
28
            //writing grid markers

29
            this.ctx.save();
30
            this.ctx.fillStyle = this.options.gridColor;
31
            this.ctx.font = "bold 10px Arial";
32
            this.ctx.fillText(gridValue, 10,gridY - 2);
33
            this.ctx.restore();
34
35
            gridValue+=this.options.gridScale;
36
        }
37
 
38
        //drawing the bars

39
        var barIndex = 0;
40
        var numberOfBars = Object.keys(this.options.data).length;
41
        var barSize = (canvasActualWidth)/numberOfBars;
42
43
        for (categ in this.options.data){
44
            var val = this.options.data[categ];
45
            var barHeight = Math.round( canvasActualHeight * val/maxValue) ;
46
            drawBar(
47
                this.ctx,
48
                this.options.padding + barIndex * barSize,
49
                this.canvas.height - barHeight - this.options.padding,
50
                barSize,
51
                barHeight,
52
                this.colors[barIndex%this.colors.length]
53
            );
54
55
            barIndex++;
56
        }
57
 
58
    }
59
}

Классы начала были сохранены в настройках как параметры. Это сохраняет canvas и создаёт рисованный контекст и сохраняет как класс участника. Тогда это хранит цвета массива как варианты.

Следующая часть является самой последовательной функцией draw(). Это потянет диаграмму первым рисунком линии сетки, маркеры сетки, и затем бары, используя параметры передали через объект вариантов.

Смотря на функцию draw(), мы можем видеть, что сначала мы вычисляем максимальное значение для всей числовой модели. Нам требуется данное число для того, что бы определить размер диаграммы и уже от этого числа будет отталкиваться размер canvas. Иначе наша диаграмма могла бы выйти за пределы области дисплея, а мы не хотим этого.

Переменные canvasActualHeight и canvasActualWidth хранят значения высоты и ширины используя значения отступов переданные в настройки. Переменная padding указывает число пикселей между страницей и границей графика внутри.

Мы тогда тянем линии сетки диаграммы. Переменная options.gridScale устанавливает шаг, используемый для рисования линий. Таким образом, значение 10 для gridScale будет означать тянуть линии сетки каждые 10 единиц.

Для расивания линии сетки, мы используем вспомогательную функцию drawLine(); что касается цвета линий сетки, мы берем его из переменной options.gridColor. Обратите внимание на то, что холст берёт начало координат из 0,0 в верхнем левом углу и уходит вправо и вниз, в то время как значение нашей сетки увеличивается снизу вверх. Вот почему мы использовали 1 - gridValue/maxValue в расчётах формулы значения gridY.

Для каждой линии сетки мы также прорисовали значение линии 2 пикселя выше линии (вот почему у нас gridY - 2 для координаты Y в тексте).

Следующим шагом мы рисуем график при помощи вспомогательной функции drawBar(). Математика для вычисления высоты и ширины каждого бара довольно прямая. Она включает во внимание отступы и значение и цвет для каждой категории в модели данных диаграммы.

Используем компонент гистограммы

Давайте теперь посмотрим как реализовано использование класса Barchart ниже. Нам нужно идентифицировать класс и вызвать функцию draw(). добавьте следующий код в script.js.

1
var myBarchart = new Barchart(
2
    {
3
        canvas:myCanvas,
4
        padding:10,
5
        gridScale:5,
6
        gridColor:"#eeeeee",
7
        data:myVinyls,
8
        colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"]
9
    }
10
);
11
myBarchart.draw();

Код создаёт экземпляр класса Barchart с нужными опциями. Загружаем index.html в браузер чтобы получить результат вроде этого:

Simple bar chart using html5 canvasSimple bar chart using html5 canvasSimple bar chart using html5 canvas

Добавляем серийное название данных и описание диаграммы

Что бы добавить серийное название данных нам надо добавить следующий код в файл script.js после for-loop, который рисует диаграмму:

1
        ...
2
        //drawing series name

3
        this.ctx.save();
4
        this.ctx.textBaseline="bottom";
5
        this.ctx.textAlign="center";
6
        this.ctx.fillStyle = "#000000";
7
        this.ctx.font = "bold 14px Arial";
8
        this.ctx.fillText(this.options.seriesName, this.canvas.width/2,this.canvas.height);
9
        this.ctx.restore();  
10
        ...

Также нам надо изменить путь вызова компонента Barchart как описано ниже:

1
var myBarchart = new Barchart(
2
    {
3
        canvas:myCanvas,
4
        seriesName:"Vinyl records",
5
        padding:20,
6
        gridScale:5,
7
        gridColor:"#eeeeee",
8
        data:myVinyls,
9
        colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"]
10
    }
11
);
12
myBarchart.draw();

Теперь наш результат выглядит так:

Bar chart with data series titleBar chart with data series titleBar chart with data series title

Для добавления описания, нам надо модифицировать index.html, чтобы он выглядел так:

1
<html>
2
<body>
3
    <canvas id="myCanvas" style="background: white;"></canvas>
4
    <legend for="myCanvas"></legend>
5
    <script type="text/javascript" src="script.js"></script>
6
</body>
7
</html>

Тег legend может быть использован как заполнитель для описания диаграммы. Атрибут for ссылается на canvas в диаграмме. Теперь нам надо добавить код, что создаёт описание. Мы будет делать это в файле script.js после кода, что прорисовывает серийное название данных. Ко идентифицирует тег legend передавая в диаграмму и это добавит список категорий из модели данных диаграммы вместе с передаваемым цветом. В конце концов наш script.js будет выглядеть так:

1
var myCanvas = document.getElementById("myCanvas");
2
myCanvas.width = 300;
3
myCanvas.height = 300;
4
  
5
var ctx = myCanvas.getContext("2d");
6
7
function drawLine(ctx, startX, startY, endX, endY,color){
8
    ctx.save();
9
    ctx.strokeStyle = color;
10
    ctx.beginPath();
11
    ctx.moveTo(startX,startY);
12
    ctx.lineTo(endX,endY);
13
    ctx.stroke();
14
    ctx.restore();
15
}
16
17
function drawBar(ctx, upperLeftCornerX, upperLeftCornerY, width, height,color){
18
    ctx.save();
19
    ctx.fillStyle=color;
20
    ctx.fillRect(upperLeftCornerX,upperLeftCornerY,width,height);
21
    ctx.restore();
22
}
23
24
var myVinyls = {
25
    "Classical music": 10,
26
    "Alternative rock": 14,
27
    "Pop": 2,
28
    "Jazz": 12
29
};
30
31
var Barchart = function(options){
32
    this.options = options;
33
    this.canvas = options.canvas;
34
    this.ctx = this.canvas.getContext("2d");
35
    this.colors = options.colors;
36
 
37
    this.draw = function(){
38
        var maxValue = 0;
39
        for (var categ in this.options.data){
40
            maxValue = Math.max(maxValue,this.options.data[categ]);
41
        }
42
        var canvasActualHeight = this.canvas.height - this.options.padding * 2;
43
        var canvasActualWidth = this.canvas.width - this.options.padding * 2;
44
45
        //drawing the grid lines

46
        var gridValue = 0;
47
        while (gridValue <= maxValue){
48
            var gridY = canvasActualHeight * (1 - gridValue/maxValue) + this.options.padding;
49
            drawLine(
50
                this.ctx,
51
                0,
52
                gridY,
53
                this.canvas.width,
54
                gridY,
55
                this.options.gridColor
56
            );
57
            
58
            //writing grid markers

59
            this.ctx.save();
60
            this.ctx.fillStyle = this.options.gridColor;
61
            this.ctx.textBaseline="bottom"; 
62
            this.ctx.font = "bold 10px Arial";
63
            this.ctx.fillText(gridValue, 10,gridY - 2);
64
            this.ctx.restore();
65
66
            gridValue+=this.options.gridScale;
67
        }      
68
 
69
        //drawing the bars

70
        var barIndex = 0;
71
        var numberOfBars = Object.keys(this.options.data).length;
72
        var barSize = (canvasActualWidth)/numberOfBars;
73
74
        for (categ in this.options.data){
75
            var val = this.options.data[categ];
76
            var barHeight = Math.round( canvasActualHeight * val/maxValue) ;
77
            drawBar(
78
                this.ctx,
79
                this.options.padding + barIndex * barSize,
80
                this.canvas.height - barHeight - this.options.padding,
81
                barSize,
82
                barHeight,
83
                this.colors[barIndex%this.colors.length]
84
            );
85
86
            barIndex++;
87
        }
88
89
        //drawing series name

90
        this.ctx.save();
91
        this.ctx.textBaseline="bottom";
92
        this.ctx.textAlign="center";
93
        this.ctx.fillStyle = "#000000";
94
        this.ctx.font = "bold 14px Arial";
95
        this.ctx.fillText(this.options.seriesName, this.canvas.width/2,this.canvas.height);
96
        this.ctx.restore();  
97
        
98
        //draw legend

99
        barIndex = 0;
100
        var legend = document.querySelector("legend[for='myCanvas']");
101
        var ul = document.createElement("ul");
102
        legend.append(ul);
103
        for (categ in this.options.data){
104
            var li = document.createElement("li");
105
            li.style.listStyle = "none";
106
            li.style.borderLeft = "20px solid "+this.colors[barIndex%this.colors.length];
107
            li.style.padding = "5px";
108
            li.textContent = categ;
109
            ul.append(li);
110
            barIndex++;
111
        }
112
    }
113
}
114
115
116
var myBarchart = new Barchart(
117
    {
118
        canvas:myCanvas,
119
        seriesName:"Vinyl records",
120
        padding:20,
121
        gridScale:5,
122
        gridColor:"#eeeeee",
123
        data:myVinyls,
124
        colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"]
125
    }
126
);

Финальный результат в браузере:

HTML5 canvas bar chart final resultHTML5 canvas bar chart final resultHTML5 canvas bar chart final result

Мои поздравления

Мы увидели, что гистограммы с использованием HTML5 не так уж и сложны. Требуется небольшие знания математики и JavaScript. Теперь вы имеете всё что надо для создания собственных гистограмм.

Если вы хотите быстрое и просто е решение для создания не только гистограмм, но и загрузки прочих видов диагорамм, вы можете загрузить библиотеку Диаграмм и Инфографик (Infographic Charts and Graphics HTML Tags Library) или плагин для Wordpress Charts and Graphs WordPress Visual Designer.

Infographic charts and graphics HTML tags libraryInfographic charts and graphics HTML tags libraryInfographic charts and graphics HTML tags library
Infographic Charts Library из CodeCanyon