Статьи

Создание многострочной диаграммы с использованием D3.js: часть 2

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

Давайте начнем с клонирования первой части урока от GitHub .

1
git clone https://github.com/jay3dec/MultiLineChart_D3.git

Перейдите к MultiLineChart_D3 и просмотрите index.html , и у вас должен быть многострочный график, основанный на данных примера.

В предыдущем уроке , когда мы создавали xScale и yScale используя Range и Domain , мы жестко запрограммировали минимум и максимум для домена. Чтобы сделать наш график более гибким, нам нужно динамически считывать минимальные и максимальные значения для домена из источника данных.

D3.js предоставляет методы d3.min и d3.max для получения минимального и максимального значений из массива соответственно. Мы будем использовать эти функции, чтобы получить минимальные и максимальные значения для домена.

Мы можем получить минимальное значение из массива, как показано:

1
2
3
d3.min(data, function(d) {
    return d.value;
})

Аналогично, чтобы получить максимальное значение:

1
2
3
d3.max(data, function(d) {
    return d.value;
})

Просто замените минимальное и максимальное значения в домене xScale как показано:

1
2
3
4
5
xScale = d3.scale.linear().range([MARGINS.left, WIDTH — MARGINS.right]).domain([d3.min(data, function(d) {
    return d.year;
}), d3.max(data, function(d) {
    return d.year;
})]),

Аналогично замените домен yScale :

1
2
3
4
5
yScale = d3.scale.linear().range([HEIGHT — MARGINS.top, MARGINS.bottom]).domain([d3.min(data, function(d) {
    return d.sale;
}), d3.max(data, function(d) {
    return d.sale;
})]),

Сохраните все изменения и просмотрите index.html . Теперь вы должны иметь график, работающий хорошо, как это было раньше. Разница лишь в том, что он подбирает максимальные и минимальные значения домена динамически.

Хранение одного объекта JSON для образца облегчит анализ данных и нанесение их на график. Поэтому объедините две части данных примера в одну строку данных JSON, как показано ниже:

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 data = [{
    «Client»: «ABC»,
    «sale»: «202»,
    «year»: «2000»
}, {
    «Client»: «ABC»,
    «sale»: «215»,
    «year»: «2002»
}, {
    «Client»: «ABC»,
    «sale»: «179»,
    «year»: «2004»
}, {
    «Client»: «ABC»,
    «sale»: «199»,
    «year»: «2006»
}, {
    «Client»: «ABC»,
    «sale»: «134»,
    «year»: «2008»
}, {
    «Client»: «ABC»,
    «sale»: «176»,
    «year»: «2010»
}, {
    «Client»: «XYZ»,
    «sale»: «100»,
    «year»: «2000»
}, {
    «Client»: «XYZ»,
    «sale»: «215»,
    «year»: «2002»
}, {
    «Client»: «XYZ»,
    «sale»: «179»,
    «year»: «2004»
}, {
    «Client»: «XYZ»,
    «sale»: «199»,
    «year»: «2006»
}, {
    «Client»: «XYZ»,
    «sale»: «134»,
    «year»: «2008»
}, {
    «Client»: «XYZ»,
    «sale»: «176»,
    «year»: «2013»
}];

Теперь мы изменим наш код, чтобы динамически масштабировать график в соответствии с примером набора данных и его значениями.

Далее мы разделим и организуем данные на основе Client чтобы мы могли нарисовать линейный график для каждого Client в данных. D3 предоставляет метод с именем d3.nest который помогает упорядочить данные на основе определенного key поля. Мы будем использовать d3.nest для сортировки данных на основе Client как показано ниже:

1
2
3
4
5
var dataGroup = d3.nest()
   .key(function(d) {
       return d.Client;
   })
   .entries(data);

Вот как будет выглядеть dataGroup :

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
[{
    «key»: «ABC»,
    «values»: [{
        «Client»: «ABC»,
        «sale»: «202»,
        «year»: «2000»
    }, {
        «Client»: «ABC»,
        «sale»: «215»,
        «year»: «2002»
    }, {
        «Client»: «ABC»,
        «sale»: «179»,
        «year»: «2004»
    }, {
        «Client»: «ABC»,
        «sale»: «199»,
        «year»: «2006»
    }, {
        «Client»: «ABC»,
        «sale»: «134»,
        «year»: «2008»
    }, {
        «Client»: «ABC»,
        «sale»: «176»,
        «year»: «2010»
    }]
}, {
    «key»: «XYZ»,
    «values»: [{
        «Client»: «XYZ»,
        «sale»: «100»,
        «year»: «2000»
    }, {
        «Client»: «XYZ»,
        «sale»: «215»,
        «year»: «2002»
    }, {
        «Client»: «XYZ»,
        «sale»: «179»,
        «year»: «2004»
    }, {
        «Client»: «XYZ»,
        «sale»: «199»,
        «year»: «2006»
    }, {
        «Client»: «XYZ»,
        «sale»: «134»,
        «year»: «2008»
    }, {
        «Client»: «XYZ»,
        «sale»: «176»,
        «year»: «2013»
    }]
}]

Затем удалите код пути строки svg для создания строки, который мы жестко запрограммировали ранее.

01
02
03
04
05
06
07
08
09
10
vis.append(‘svg:path’)
    .attr(‘d’, lineGen(data))
    .attr(‘stroke’, ‘green’)
    .attr(‘stroke-width’, 2)
    .attr(‘fill’, ‘none’);
vis.append(‘svg:path’)
    .attr(‘d’, lineGen(data2))
    .attr(‘stroke’, ‘blue’)
    .attr(‘stroke-width’, 2)
    .attr(‘fill’, ‘none’);

Вместо этого мы dataGroup группу dataGroup и создадим линейный график для каждого Client как показано ниже:

1
2
3
4
5
6
7
dataGroup.forEach(function(d, i) {
    vis.append(‘svg:path’)
        .attr(‘d’, lineGen(d.values))
        .attr(‘stroke’, ‘blue’)
        .attr(‘stroke-width’, 2)
        .attr(‘fill’, ‘none’);
});

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

Многострочный график

Давайте также добавим несколько случайных цветов в линии графика. Чтобы добавить случайные цвета, мы будем использовать метод d3.hsl . Измените атрибут stroke линейного графика, как показано ниже, чтобы получить случайные цвета для линий.

1
2
3
4
5
6
7
8
9
dataGroup.forEach(function(d, i) {
    vis.append(‘svg:path’)
        .attr(‘d’, lineGen(d.values))
        .attr(‘stroke’, function(d, j) {
            return «hsl(» + Math.random() * 360 + «,100%,50%)»;
        })
        .attr(‘stroke-width’, 2)
        .attr(‘fill’, ‘none’);
});

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

Многолинейный график с цветными линиями

Далее мы добавим legends для Clients в пример данных. Как только легенды будут добавлены, мы добавим к легендам событие щелчка, которое переключит отображение соответствующих линейных графиков.

Во-первых, чтобы добавить легенду, нам нужно изменить margin bottom margin top до 50 чтобы приспособить легенды.

1
2
3
4
5
6
7
8
9
var vis = d3.select(«#visualisation»),
   WIDTH = 1000,
   HEIGHT = 500,
   MARGINS = {
       top: 50,
       right: 20,
       bottom: 50,
       left: 50
   },

dataGroup группу dataGroup , мы добавим легенды для соответствующих линейных графиков. Добавить легенды довольно просто. Во-первых, определите пространство легенды на основе количества клиентов или линейных графиков, которые мы будем рисовать:

1
lSpace = WIDTH/dataGroup.length;

Добавьте текст в элемент svg с координатами x и y, повторяя итерацию dataGroup после создания строки, как показано:

1
2
3
4
5
vis.append(«text»)
   .attr(«x», (lSpace / 2) + i * lSpace)
   .attr(«y», HEIGHT)
   .style(«fill», «black»)
   .text(d.key);

Мы отрегулировали расстояние между легендами ( lSpace ) на основе количества легенд, которые мы должны показать, чтобы все легенды были одинаково удалены друг от друга. Мы разделили легенду на 2, чтобы ее центр был выровнен по пространству и чтобы она развивалась по мере продвижения вперед, поскольку мы добавляем ( i * lSpace ) к предстоящим легендам.

Сохраните все изменения и попробуйте просмотреть index.html и вы должны увидеть легенды под осью X.

Многолинейный график с легендой

Давайте добавим немного стиля к легендам, чтобы они выглядели смелыми. Добавьте следующий CSS в index.html :

1
2
3
4
.legend {
    font-size: 14px;
    font-weight: bold;
}

Добавьте legend класса к созданной легенде.

1
2
3
4
5
6
vis.append(«text»)
   .attr(«x», (lSpace / 2) + i * lSpace)
   .attr(«y», HEIGHT)
   .style(«fill», «black»)
   .attr(«class», «legend»)
   .text(d.key);
Линейная диаграмма с легендой

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

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

1
.attr(‘id’, ‘line_’+d.key)

Вот как выглядит код создания строки:

1
2
3
4
5
6
7
8
vis.append(‘svg:path’)
   .attr(‘d’, lineGen(d.values, xScale, yScale))
   .attr(‘stroke’, function(d, j) {
       return «hsl(» + Math.random() * 360 + «,100%,50%)»;
   })
   .attr(‘stroke-width’, 2)
   .attr(‘id’, ‘line_’ + d.key)
   .attr(‘fill’, ‘none’);

Затем, в части создания легенды, добавьте атрибут click :

1
2
3
.on(‘click’, function() {
    alert(d.key);
})

Сохраните изменения и просмотрите index.html . Нажмите на легенды, и вы должны увидеть имена легенд в качестве предупреждений.

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

1
2
3
4
5
6
7
8
.on(‘click’, function() {
    var active = d.active ?
    var opacity = active ?
 
    d3.select(«#line_» + d.key).style(«opacity», opacity);
 
    d.active = active;
})

Сохраните изменения и попробуйте просмотреть index.html . Попробуйте нажать на легенды, и отображение соответствующего линейного графика должно переключиться.

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

Исходный код из этого урока доступен на GitHub .

Дайте нам знать ваши мысли в комментариях ниже!