Работа с данными

Привязка данных

Последнее обновление: 1.11.2015

Ключевым аспектом библиотеки D3.js является работа с данными. Для добавления данных в элемент применяется метод data(). В качестве аргумента в этот метод передается массив объектов.

Например, у нас есть список ul, который мы заполняем с помощью метода data():

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"> </script>
<body>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
<script type="text/javascript">
var phones = ['iPhone 6', 'Samsung Galaxy S5', 'LG G4'];
d3.selectAll('li').data(phones).text( function(d){
return d;
});
</script>
</body>
</html>

В результате мы получим наполненнный из массива список:

Функция data в d2.js

Метод data() устанавливает связи между элементами html и элементами массива, однако чтобы выполнить привязку между элементом массива и текстом элемента html, надо использовать функцию динамической модификации (dynamic modifier function). Она принимает два параметра: d - элемент массива, и i - индекс элемента. В данном случае нам индексы не существенны, поэтому здесь используется один параметр d.

Элементы массива выполняют роль данных, а элементы li, да и любые другие элементы html, являются визуальным представлением этих данных.

И хотя данный способ работает, но он очень ограничен. Например, что если мы получаем данные с сервера и заведомо не знаем, сколько будет элементов в списке. И если список ul будет содержать только один элемент li, а массив данных - больше одного, то в результате заполнится только один единственный элемент списка. Например:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"> </script>
<body>
<ul>
<li></li>
</ul>
<script type="text/javascript">
var phones = ['iPhone 6', 'Samsung Galaxy S5', 'LG G4', 'MiPad 5'];
var phonesList=d3.select('ul').selectAll('li').data(phones).text( function(d){ return d; });
phonesList.enter().append('li').text( function(d){ return d; })
</script>
</body>
</html>

Список ul здесь содержит только один элемент li, в то время как в массиве четыре элемента. Строка

var phonesList=d3.select('ul').selectAll('li')
							.data(phones).text( function(d){ return d; });

Хотя и ассоциирует массив с элементом списка ul, но заполняет только первый и единственный элемент li. Чтобы ввести дополнительные элементы, нам надо использовать метод enter(). После этого метода мы можем добавить недостающие элементы с помощью метода append и также установить их содержимое.

Но на методе enter мы не остановимся, и перейдем к полноценному использованию паттерна enter-update-exit. Этот паттерн позволит нам избежать другой крайности, которая остается у выше приведенного решения. Так, если у нас в списке ul элементов li больше, чем элементов в массиве данных, то на странице мы увидим незаполненные элементы, хотя хотелось бы их вообще удалить.

Используем паттерн enter-update-exit:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"> </script>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script type="text/javascript">
var phones = ['iPhone 6', 'Samsung Galaxy S5', 'LG G4', 'MiPad 5'];
// Enter
d3.select('ul').selectAll('li').data(phones).enter().append('li');
// Update
d3.select('ul').selectAll('li').data(phones).text( function(d){ return d; });
// Exit
d3.select('ul').selectAll('li').data(phones).exit().remove();
</script>
</body>
</html>
enter and exit in d3.js

Итак, в массиве у нас четыре элемента, а в списке ul - шесть, то есть два лишних. Вначале применяем блок Enter, где используется метод enter(). После этого метода определяется добавление недостающих элементов li: .enter().append('li'). Но когда выполнение скрипта дойдет ло этой строчки, то добавление не будет работать, так как у нас нет недостающих элементов li, а, наоборот, есть только лишние.

Далее срабатывает блок Update. В нем производится обновление элементов li - установки их текста с помощью элементов из массива и функции function(d){ return d; }. Так как в массиве 4 элемента, то для первых четырех элементов из списка ul будет установлено текстовое содержимое. При этом два последних элемента окажутся пустыми.

Далее срабатывает блок Exit, суть которого в отсечении лишних элементов. Для этого используется метод .exit(), который определяет те элементы, которые не связаны с данными из массива. Затем идет удаление этих элементов с помощью метода remove()

Таким образом, если данных в массиве больше, чем визуальных элементов в коде html, то срабатывает вызовы после метода enter(). Если же наоборот, данных в массиве меньше, чем элементов html, то срабатывают методы после вызова exit(). И вне зависимости от количества элементов будет работать обновление.

Разберем еще один более сложный пример:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"> </script>
<style>
.item{
    margin-bottom: 7px;
    font-size: 15px;
    margin-right: 2px;
    min-height: 25px;
    min-width: 20px;
}
.data {
    background-color: steelblue;
    text-align: right;
    color: #f0f8ff;
	display:inline-block;
}
.name{
	display:inline-block;
	margin-left:5px;
}
</style>
<body>

<div class="diagram"></div>

<script type="text/javascript">
var phones = [ {name: 'iPhone 6', price: 64},
{name: 'Samsung Galaxy S5', price: 48},
{name: 'LG G4', price: 36},
{name : 'MiPad 5', price: 25}];

// Enter
d3.select('div.diagram').selectAll('div').data(phones).enter().append('div').attr('class', 'item')
.append('div').attr('class', 'data').append('span');

// Update
d3.select('div.diagram').selectAll('div.item').data(phones)
.select('div').style('width', function (d) { return (d.price * 3) + 'px';})
.select('span').text(function (d) { return d.price;});

d3.select('div.diagram').selectAll('div.item').data(phones).append('div').attr('class', 'name')
.text(function (d) {return d.name;});

// Exit
d3.select('div.diagram').selectAll('div.item').data(phones).exit().remove();
</script>
</body>
</html>

Здесь данные уже представлены сложными объектами с двумя свойствами.

В блоке Enter к добавляемым блокам div также добавляются классы и вложенный элемент span.

В блоке Update с помощью функции function(d){} устанавливается как ширина блоков div, так и текстовое содержимое добавленного элемента span.

Также добавляется новый вложенный блок с текстом в виде названия модели телефона.

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

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850