
В этом уроке я покажу вам, как использовать JavaScript и холст в качестве средства отображения числовой информации в виде круговых диаграмм и кольцевых диаграмм.
Существуют более простые способы создания диаграмм, чем программирование с нуля, например, эта полная библиотека диаграмм из 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 принимает пять параметров:
-
ctx: ссылка на контекст рисования -
startX: координата X начальной точки линии -
startY: координата Y начальной точки линии -
endX: координата X конечной точки линии -
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 принимает шесть параметров:
-
ctx: ссылка на контекст рисования -
centerX: координата X центра круга -
centerY: координата Y центра круга -
radius: координата X конечной точки линии -
startAngle: начальный угол в радианах, где начинается часть круга -
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 принимает семь параметров:
-
ctx: ссылка на контекст рисования -
centerX: координата X центра круга -
centerY: координата Y центра круга -
radius: координата X конечной точки линии -
startAngle: начальный угол в радианах, где начинается часть круга -
endAngle: конечный угол в радианах, где заканчивается часть круга -
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();
|
И результат выглядит так

Рисование кольцевой диаграммы
Мы видели, как нарисовать круговую диаграмму. Мы также знаем, что кольцевая диаграмма отличается только наличием отверстия в середине диаграммы. Как мы рисуем дыру? Мы можем нарисовать белый круг над круговой диаграммой.
Давайте 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();
|
И вот результат:

Добавление меток и условных обозначений диаграммы
Наша круговая диаграмма и кольцевая диаграмма выглядят довольно хорошо, но мы можем сделать их еще лучше, добавив две вещи:
- метки значений: показывает процент, соответствующий каждому срезу
- легенда диаграммы: отображение категорий и соответствующих цветов на диаграмме
Обычно значения, связанные с срезами, представляются в виде процентных значений, рассчитанных как 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++]+»;’>
}
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 .