Статьи

Как рисовать гистограммы с использованием JavaScript и HTML5 Canvas

Конечный продукт
Что вы будете создавать

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

Существуют более простые способы создания диаграмм, чем программирование с нуля, например, эта полная библиотека диаграмм из CodeCanyon.

Библиотека инфографики и графики HTML-теги
Библиотека диаграмм инфографики от CodeCanyon

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

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

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

Существует много типов гистограмм:

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

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

Компоненты гистограммы
  • Данные диаграммы: это наборы чисел и связанных категорий, которые представлены диаграммой.
  • Название ряда данных (1).
  • Сетка диаграммы (2): дает справочную систему, чтобы визуальное представление было легко понять.
  • Столбцы (3): заполненные цветом прямоугольники с размерами, пропорциональными представленным данным.
  • Легенда диаграммы (4): показывает соответствие между используемыми цветами и данными, которые они представляют.

Теперь, когда мы знаем компоненты гистограммы, давайте посмотрим, как мы можем написать код JavaScript, чтобы нарисовать такую ​​диаграмму.

Чтобы начать рисовать с использованием JavaScript и HTML5 canvas, нам нужно настроить наш проект следующим образом:

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

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

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

У нас есть элемент <canvas> с идентификатором myCanvas чтобы мы могли ссылаться на него в нашем коде JS. Затем мы загружаем код JS через <script> .

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

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

Это получает ссылку на элемент canvas, а затем устанавливает ширину и высоту 300px . Чтобы рисовать на холсте, нам нужна только ссылка на его 2D-контекст, который содержит все методы рисования.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
var Barchart = function(options){
    this.options = options;
    this.canvas = options.canvas;
    this.ctx = this.canvas.getContext(«2d»);
    this.colors = options.colors;
  
    this.draw = function(){
        var maxValue = 0;
        for (var categ in this.options.data){
            maxValue = Math.max(maxValue,this.options.data[categ]);
        }
        var canvasActualHeight = this.canvas.height — this.options.padding * 2;
        var canvasActualWidth = this.canvas.width — this.options.padding * 2;
 
        //drawing the grid lines
        var gridValue = 0;
        while (gridValue <= maxValue){
            var gridY = canvasActualHeight * (1 — gridValue/maxValue) + this.options.padding;
            drawLine(
                this.ctx,
                0,
                gridY,
                this.canvas.width,
                gridY,
                this.options.gridColor
            );
             
            //writing grid markers
            this.ctx.save();
            this.ctx.fillStyle = this.options.gridColor;
            this.ctx.font = «bold 10px Arial»;
            this.ctx.fillText(gridValue, 10,gridY — 2);
            this.ctx.restore();
 
            gridValue+=this.options.gridScale;
        }
  
        //drawing the bars
        var barIndex = 0;
        var numberOfBars = Object.keys(this.options.data).length;
        var barSize = (canvasActualWidth)/numberOfBars;
 
        for (categ in this.options.data){
            var val = this.options.data[categ];
            var barHeight = Math.round( canvasActualHeight * val/maxValue) ;
            drawBar(
                this.ctx,
                this.options.padding + barIndex * barSize,
                this.canvas.height — barHeight — this.options.padding,
                barSize,
                barHeight,
                this.colors[barIndex%this.colors.length]
            );
 
            barIndex++;
        }
  
    }
}

Класс начинается с хранения options переданных в качестве параметров. Он хранит ссылку на canvas и создает контекст рисования, также сохраненный как член класса. Затем он сохраняет массив colors переданный в качестве параметров.

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

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

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

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

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
var myBarchart = new Barchart(
    {
        canvas:myCanvas,
        padding:10,
        gridScale:5,
        gridColor:»#eeeeee»,
        data:myVinyls,
        colors:[«#a55ca5″,»#67b6c7», «#bccd7a»,»#eb9743″]
    }
);
myBarchart.draw();

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

Простая гистограмма с использованием холста html5

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

01
02
03
04
05
06
07
08
09
10
       //drawing series name
       this.ctx.save();
       this.ctx.textBaseline=»bottom»;
       this.ctx.textAlign=»center»;
       this.ctx.fillStyle = «#000000»;
       this.ctx.font = «bold 14px Arial»;
       this.ctx.fillText(this.options.seriesName, this.canvas.width/2,this.canvas.height);
       this.ctx.restore();
       …

Нам также нужно изменить способ вызова компонента Barchart следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
var myBarchart = new Barchart(
    {
        canvas:myCanvas,
        seriesName:»Vinyl records»,
        padding:20,
        gridScale:5,
        gridColor:»#eeeeee»,
        data:myVinyls,
        colors:[«#a55ca5″,»#67b6c7», «#bccd7a»,»#eb9743″]
    }
);
myBarchart.draw();

И вот как выглядит результат:

Гистограмма с названием ряда данных

Чтобы добавить легенду, сначала нужно изменить index.html чтобы он выглядел так:

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

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

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
var myCanvas = document.getElementById(«myCanvas»);
myCanvas.width = 300;
myCanvas.height = 300;
   
var ctx = myCanvas.getContext(«2d»);
 
function drawLine(ctx, startX, startY, endX, endY,color){
    ctx.save();
    ctx.strokeStyle = color;
    ctx.beginPath();
    ctx.moveTo(startX,startY);
    ctx.lineTo(endX,endY);
    ctx.stroke();
    ctx.restore();
}
 
function drawBar(ctx, upperLeftCornerX, upperLeftCornerY, width, height,color){
    ctx.save();
    ctx.fillStyle=color;
    ctx.fillRect(upperLeftCornerX,upperLeftCornerY,width,height);
    ctx.restore();
}
 
var myVinyls = {
    «Classical music»: 10,
    «Alternative rock»: 14,
    «Pop»: 2,
    «Jazz»: 12
};
 
var Barchart = function(options){
    this.options = options;
    this.canvas = options.canvas;
    this.ctx = this.canvas.getContext(«2d»);
    this.colors = options.colors;
  
    this.draw = function(){
        var maxValue = 0;
        for (var categ in this.options.data){
            maxValue = Math.max(maxValue,this.options.data[categ]);
        }
        var canvasActualHeight = this.canvas.height — this.options.padding * 2;
        var canvasActualWidth = this.canvas.width — this.options.padding * 2;
 
        //drawing the grid lines
        var gridValue = 0;
        while (gridValue <= maxValue){
            var gridY = canvasActualHeight * (1 — gridValue/maxValue) + this.options.padding;
            drawLine(
                this.ctx,
                0,
                gridY,
                this.canvas.width,
                gridY,
                this.options.gridColor
            );
             
            //writing grid markers
            this.ctx.save();
            this.ctx.fillStyle = this.options.gridColor;
            this.ctx.textBaseline=»bottom»;
            this.ctx.font = «bold 10px Arial»;
            this.ctx.fillText(gridValue, 10,gridY — 2);
            this.ctx.restore();
 
            gridValue+=this.options.gridScale;
        }
  
        //drawing the bars
        var barIndex = 0;
        var numberOfBars = Object.keys(this.options.data).length;
        var barSize = (canvasActualWidth)/numberOfBars;
 
        for (categ in this.options.data){
            var val = this.options.data[categ];
            var barHeight = Math.round( canvasActualHeight * val/maxValue) ;
            drawBar(
                this.ctx,
                this.options.padding + barIndex * barSize,
                this.canvas.height — barHeight — this.options.padding,
                barSize,
                barHeight,
                this.colors[barIndex%this.colors.length]
            );
 
            barIndex++;
        }
 
        //drawing series name
        this.ctx.save();
        this.ctx.textBaseline=»bottom»;
        this.ctx.textAlign=»center»;
        this.ctx.fillStyle = «#000000»;
        this.ctx.font = «bold 14px Arial»;
        this.ctx.fillText(this.options.seriesName, this.canvas.width/2,this.canvas.height);
        this.ctx.restore();
         
        //draw legend
        barIndex = 0;
        var legend = document.querySelector(«legend[for=’myCanvas’]»);
        var ul = document.createElement(«ul»);
        legend.append(ul);
        for (categ in this.options.data){
            var li = document.createElement(«li»);
            li.style.listStyle = «none»;
            li.style.borderLeft = «20px solid «+this.colors[barIndex%this.colors.length];
            li.style.padding = «5px»;
            li.textContent = categ;
            ul.append(li);
            barIndex++;
        }
    }
}
 
 
var myBarchart = new Barchart(
    {
        canvas:myCanvas,
        seriesName:»Vinyl records»,
        padding:20,
        gridScale:5,
        gridColor:»#eeeeee»,
        data:myVinyls,
        colors:[«#a55ca5″,»#67b6c7», «#bccd7a»,»#eb9743″]
    }
);

Который даст конечный результат, похожий на этот:

HTML5 холст гистограмма конечный результат

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

Если вам нужно быстрое и простое решение для создания не только гистограмм, но и множества других типов диаграмм, вы можете загрузить библиотеку HTML-графиков и графиков для инфографики или ее плагин WordPress для диаграмм и графиков WordPress Visual Designer .

Библиотека инфографики и графики HTML-теги
Библиотека диаграмм инфографики от CodeCanyon