Статьи

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

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

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

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

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

Но если вы хотите знать, что происходит за кулисами в такой библиотеке, читайте дальше.

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

Проще говоря, кольцевая диаграмма — это разновидность круговой диаграммы. Разница в том, что ломтики нарезаются по направлению к центру пирога, так что виден только край Таким образом, диаграмма выглядит как пончик и, следовательно, название.

Перед тем, как нарисовать круговую диаграмму, мы рассмотрим рисование ее частей. Мы увидим, как мы можем использовать компонент canvas и JavaScript для рисования:

  • линия
  • дуга (часть круга)
  • цветная форма

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

  • Одна папка для хранения файлов проекта; давайте назовем эту папку piechart-tutorial .
  • Один HTML-файл index.html внутри piechart-tutorial . Этот файл будет содержать код HTML.
  • Один файл JS script.js внутри piechart-tutorial . Этот файл будет содержать наш код 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 JS-код сначала получает ссылку на холст, а затем устанавливает его ширину и высоту. Чтобы рисовать на холсте, нам нужна только ссылка на его 2D-контекст, который содержит все методы рисования.

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

Теперь, когда у нас есть настроенный холст, а также ссылка на холст для рисования, давайте определим несколько функций JavaScript, которые мы сможем использовать при рисовании круговой диаграммы. Мы добавим функции в наш файл script.js.

1
2
3
4
5
6
function drawLine(ctx, startX, startY, endX, endY){
    ctx.beginPath();
    ctx.moveTo(startX,startY);
    ctx.lineTo(endX,endY);
    ctx.stroke();
}

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

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

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

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

1
2
3
4
5
function drawArc(ctx, centerX, centerY, radius, startAngle, endAngle){
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, startAngle, endAngle);
    ctx.stroke();
}

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

  1. ctx : ссылка на контекст рисования
  2. centerX : координата X центра круга
  3. centerY : координата Y центра круга
  4. radius : координата X конечной точки линии
  5. startAngle : начальный угол в радианах, где начинается часть круга
  6. endAngle : конечный угол в радианах, где заканчивается часть круга

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

1
2
3
4
5
6
7
8
function drawPieSlice(ctx,centerX, centerY, radius, startAngle, endAngle, color ){
    ctx.fillStyle = color;
    ctx.beginPath();
    ctx.moveTo(centerX,centerY);
    ctx.arc(centerX, centerY, radius, startAngle, endAngle);
    ctx.closePath();
    ctx.fill();
}

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

  1. ctx : ссылка на контекст рисования
  2. centerX : координата X центра круга
  3. centerY : координата Y центра круга
  4. radius : координата X конечной точки линии
  5. startAngle : начальный угол в радианах, где начинается часть круга
  6. endAngle : конечный угол в радианах, где заканчивается часть круга
  7. color : цвет, используемый для заполнения ломтика

Вот пример для вызова трех функций:

1
2
3
drawLine(_ctx,100,100,200,200);
drawArc(_ctx, 150,150,150, 0, Math.PI/3);
drawPieSlice(_ctx, 150,150,150, Math.PI/2, Math.PI/2 + Math.PI/4, ‘#ff0000’);

Это даст такой результат:

Холст дуги и кусок пирога

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

Концептуально любой график состоит из двух основных частей:

  • Модель данных содержит числовые данные, которые будут представлены. Это структурировано в формате, определенном для типа диаграммы.
  • Графическое представление — это то, как числовые данные в модели данных представляются визуальными элементами в соответствии с некоторыми правилами в форме математических формул.

Наиболее распространенный способ структурирования модели данных для круговых диаграмм — это серия категорий и соответствующих значений, где каждая из категорий и значений связана с фрагментом круговой диаграммы.

Например, модель данных круговой диаграммы, отображающей количество винилов, сгруппированных по жанрам, будет выглядеть примерно так:

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

Мы можем добавить объект JS в файл script.js для хранения модели данных следующим образом:

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

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

Моя небольшая коллекция из 38 винилов имеет четыре категории. Каждая категория получит кусок круговой диаграммы, пропорциональный количеству винилов в этой категории.

Но как мы можем измерить размер среза? Это легко — мы делаем это по углу на кончике среза. Все, что нам нужно знать, это то, что полный круг соответствует углу 360 degrees или 2 * PI . Таким образом, полукруг будет 180 deg или PI , четверть 90 deg или PI/2 и так далее.

Для определения угла для каждого среза категории мы используем формулу:

slice angle = 2 * PI * category value / total value

Согласно этой формуле, десять винилов классической музыки получат угол среза ок. 0,526 * PI или 94 град.

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

  • canvas: ссылка на холст, на котором мы хотим нарисовать круговую диаграмму
  • данные: ссылка на объект, содержащий модель данных
  • colors: массив, содержащий цвета, которые мы хотим использовать для каждого среза

Класс Piechart также содержит один метод draw() который выполняет фактическое рисование диаграммы.

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
var Piechart = function(options){
    this.options = options;
    this.canvas = options.canvas;
    this.ctx = this.canvas.getContext(«2d»);
    this.colors = options.colors;
 
    this.draw = function(){
        var total_value = 0;
        var color_index = 0;
        for (var categ in this.options.data){
            var val = this.options.data[categ];
            total_value += val;
        }
 
        var start_angle = 0;
        for (categ in this.options.data){
            val = this.options.data[categ];
            var slice_angle = 2 * Math.PI * val / total_value;
 
            drawPieSlice(
                this.ctx,
                this.canvas.width/2,
                this.canvas.height/2,
                Math.min(this.canvas.width/2,this.canvas.height/2),
                start_angle,
                start_angle+slice_angle,
                this.colors[color_index%this.colors.length]
            );
 
            start_angle += slice_angle;
            color_index++;
        }
 
    }
}

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

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

Мы также смещаем начальный и конечный угол срезов при каждом рисовании категории, иначе срезы будут перекрываться.

Чтобы использовать класс, мы должны создать экземпляр и затем вызвать метод draw() для созданного объекта.

1
2
3
4
5
6
7
8
var myPiechart = new Piechart(
    {
        canvas:myCanvas,
        data:myVinyls,
        colors:[«#fde23e»,»#f16e23″, «#57d9ff»,»#937e88″]
    }
);
myPiechart.draw();

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

Рисование круговой диаграммы с использованием HTML5 canvas

Мы видели, как нарисовать круговую диаграмму. Мы также знаем, что кольцевая диаграмма отличается только наличием отверстия в середине диаграммы. Как мы рисуем дыру? Мы можем нарисовать белый круг над круговой диаграммой.

Давайте Piechart класса Piechart чтобы сделать это.

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
var Piechart = function(options){
    this.options = options;
    this.canvas = options.canvas;
    this.ctx = this.canvas.getContext(«2d»);
    this.colors = options.colors;
 
    this.draw = function(){
        var total_value = 0;
        var color_index = 0;
        for (var categ in this.options.data){
            var val = this.options.data[categ];
            total_value += val;
        }
 
        var start_angle = 0;
        for (categ in this.options.data){
            val = this.options.data[categ];
            var slice_angle = 2 * Math.PI * val / total_value;
 
            drawPieSlice(
                this.ctx,
                this.canvas.width/2,
                this.canvas.height/2,
                Math.min(this.canvas.width/2,this.canvas.height/2),
                start_angle,
                start_angle+slice_angle,
                this.colors[color_index%this.colors.length]
            );
 
            start_angle += slice_angle;
            color_index++;
        }
 
        //drawing a white circle over the chart
        //to create the doughnut chart
        if (this.options.doughnutHoleSize){
            drawPieSlice(
                this.ctx,
                this.canvas.width/2,
                this.canvas.height/2,
                this.options.doughnutHoleSize * Math.min(this.canvas.width/2,this.canvas.height/2),
                0,
                2 * Math.PI,
                «#ff0000»
            );
        }
 
    }
}

Добавленный код просматривает options параметров для переменной-члена doughnutHoleSize . Если этого не существует в параметрах, тогда код будет рисовать круговую диаграмму, как и раньше, но если она существует, то белый круг рисуется с тем же центром, что и круговая диаграмма.

Радиус круга определяется путем умножения радиуса круговой диаграммы и значения doughnutHoleSize . Это должно быть число от 0 до 1, где 0 приведет к круговой диаграмме, а любые значения выше 0 приведут к пончику с дыркой больше и больше, 1 делая диаграмму невидимой.

Чтобы нарисовать кольцевую диаграмму с отверстием, doughnutHoleSize половине размера диаграммы, нам нужно использовать doughnutHoleSize 0,5, и выполнить следующие вызовы:

1
2
3
4
5
6
7
8
9
var myDougnutChart = new Piechart(
    {
        canvas:myCanvas,
        data:myVinyls,
        colors:[«#fde23e»,»#f16e23″, «#57d9ff»,»#937e88″],
        doughnutHoleSize:0.5
    }
);
myDougnutChart.draw();

И вот результат:

рисование кольцевой диаграммы с помощью HTML5 canvas

Наша круговая диаграмма и кольцевая диаграмма выглядят довольно хорошо, но мы можем сделать их еще лучше, добавив две вещи:

  • метки значений: показывает процент, соответствующий каждому срезу
  • легенда диаграммы: отображение категорий и соответствующих цветов на диаграмме

Обычно значения, связанные с срезами, представляются в виде процентных значений, рассчитанных как 100 * value associated to a slice / total value , связанное с срезами 100 * value associated to a slice / total value , при этом весь круг представляет 100% .

Например, в случае с нашими образцами данных винилы с классической музыкой составляют примерно 26% . Было бы неплохо иметь возможность записать это значение прямо в соответствующий фрагмент. Для этого мы будем использовать fillText(text,x,y) контекста рисования. Эта функция принимает три параметра: текст и координаты x и y .

Как мы вычисляем координаты x и y в которые нужно поместить текст? Мы должны использовать некоторые знания геометрии и то, что называется полярными координатами . В основном, полярные координаты используют радиус и угол, чтобы определить положение точки. Мы будем использовать две формулы:

x = R * cos(angle)

y = R * sin(angle)

Мы применим эти две формулы, чтобы поместить текст наполовину вдоль радиуса круговой диаграммы и наполовину вокруг угла для каждого фрагмента круговой диаграммы. Для этого нам нужно изменить наш класс Piechart и добавить следующий код сразу после блока if (this.options.doughnutHoleSize){...} :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
       start_angle = 0;
       for (categ in this.options.data){
           val = this.options.data[categ];
           slice_angle = 2 * Math.PI * val / total_value;
           var pieRadius = Math.min(this.canvas.width/2,this.canvas.height/2);
           var labelX = this.canvas.width/2 + (pieRadius / 2) * Math.cos(start_angle + slice_angle/2);
           var labelY = this.canvas.height/2 + (pieRadius / 2) * Math.sin(start_angle + slice_angle/2);
 
           if (this.options.doughnutHoleSize){
               var offset = (pieRadius * this.options.doughnutHoleSize ) / 2;
               labelX = this.canvas.width/2 + (offset + pieRadius / 2) * Math.cos(start_angle + slice_angle/2);
               labelY = this.canvas.height/2 + (offset + pieRadius / 2) * Math.sin(start_angle + slice_angle/2);
           }
 
           var labelText = Math.round(100 * val / total_value);
           this.ctx.fillStyle = «white»;
           this.ctx.font = «bold 20px Arial»;
           this.ctx.fillText(labelText+»%», labelX,labelY);
           start_angle += slice_angle;
       }
       …

Код проходит по каждому срезу, вычисляет процент, вычисляет позицию и использует метод fillText() чтобы нарисовать его на графике. Мы использовали свойство fillStyle чтобы установить цвет текста на белый, и свойство font чтобы установить размер, стиль и семейство шрифтов надписи. Также важно отметить, что если диаграмма является doughnutHoleSize диаграммой, а doughnutHoleSize установлен, то метка будет doughnutHoleSize к краю диаграммы, чтобы центрировать ее на срезе пончика.

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

Круговая диаграмма и кольцевая диаграмма с метками значений

Чтобы завершить наш график, последнее, что мы добавим, — это легенда графика. Наша легенда диаграммы будет отображать категории нашей модели данных и цвет, используемый для соответствующего среза. Сначала мы должны внести некоторые изменения в наш файл index.html , добавив <div> котором будет храниться наш элемент легенды.

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

Затем в script.js мы добавляем код, который создает содержимое элемента легенды. Мы добавим этот код в конец функции draw() класса Piechart :

01
02
03
04
05
06
07
08
09
10
        if (this.options.legend){
            color_index = 0;
            var legendHTML = «»;
            for (categ in this.options.data){
                legendHTML += «<div><span style=’display:inline-block;width:20px;background-color:»+this.colors[color_index++]+»;’>&nbsp;
            }
            this.options.legend.innerHTML = legendHTML;
        }

Код ищет элемент legend переданный через параметр options . Если он указан, этот элемент заполняется кодом HTML, содержащим цветное поле и название категории модели данных.

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

01
02
03
04
05
06
07
08
09
10
11
var myLegend = document.getElementById(«myLegend»);
 
var myDougnutChart = new Piechart(
    {
        canvas:myCanvas,
        data:myVinyls,
        colors:[«#fde23e»,»#f16e23″, «#57d9ff»,»#937e88″],
        legend:myLegend
    }
);
myDougnutChart.draw();

А вот итоговая диаграмма и легенда диаграммы:

Круговая диаграмма с метками значений и условными обозначениями

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

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