Чи можете мені хтось пояснити різницю між даними () та даними () у D3.js? Я бачу, як вони використовуються, і я не впевнений, чому слід вибирати одне над іншим?
Чи можете мені хтось пояснити різницю між даними () та даними () у D3.js? Я бачу, як вони використовуються, і я не впевнений, чому слід вибирати одне над іншим?
Відповіді:
Тут я знайшов правильну відповідь від самого Майка:
D3 - як поводитися зі структурами даних JSON?
Якщо ви хочете прив’язати свої дані до одного SVG-елемента, використовуйте
(...).data([data])
або
(...).datum(data)
Якщо ви хочете прив’язати свої дані до декількох елементів SVG
(...).data(data).enter().append("svg")
.....
enter()
d3, d3 зв’яже решту елементів масиву з новоствореними SVG-елементами.
Трохи ознайомившись з цим, я виявив, що відповіді тут на SO не є повними, оскільки вони охоплюють випадок лише тоді, коли ви викликаєте selection.data
і selection.datum
із вхідним data
параметром. Навіть у такому сценарії обидва поводяться по-різному, якщо вибір є одним елементом проти того, коли він містить кілька елементів. Більше того, обидва ці способи можна також викликати без будь-яких вхідних аргументів для того, щоб запитувати пов'язані дані / дані у виборі, і в цьому випадку вони знову поводяться по-різному і повертають різні речі.
Редагувати - я розмістив дещо детальнішу відповідь на це питання тут , але внизу публікація в значній мірі відображає всі ключові моменти щодо двох методів та те, чим вони відрізняються один від одного.
При подачі data
як вхідний аргумент
selection.data(data)
спробує виконати з'єднання даних між елементами data
масиву з виділенням, що призведе до створення enter()
, exit()
і update()
вибору, над яким ви згодом можете працювати. Кінцевий результат цього полягає в тому, що якщо ви переходите в масив data = [1,2,3]
, робиться спроба приєднати кожен окремий елемент даних (тобто дату) до вибору. Кожен елемент виділення матиме лише один data
прив'язаний до нього елемент дат .
selection.datum(data)
взагалі обходить процес з’єднання даних. Це просто присвоює цілість data
всім елементам відбору в цілому, не розбиваючи його, як у випадку з'єднання даних. Тож якщо ви хочете прив’язати цілий масив data = [1, 2, 3]
до кожного елемента DOM у вашому selection
, то selection.datum(data)
досягнете цього.
Попередження: Багато людей вважають, що
selection.datum(data)
це рівнозначно,selection.data([data])
але це справедливо лише в тому випадку, якщо вінselection
містить один елемент . Якщоselection
містить декілька елементів DOM, тоselection.datum(data)
прив'язує цілістьdata
до кожного окремого елемента у виборі. На відміну від цього,selection.data([data])
лише пов'язує всю цілістьdata
до першого елемента вselection
. Це відповідає поведінці приєднання данихselection.data
.
При наданні data
аргументу введення немає
selection.data()
візьме зв'язану дату для кожного елемента у виділенні та об'єднає їх у масив, який повертається. Отже, якщо ваш selection
включає 3 DOM-елементи з даними "a"
, "b"
і "c"
прив’язаний до кожного відповідно, selection.data()
повертається ["a", "b", "c"]
. Важливо зауважити, що якщо selection
один елемент із (на прикладі) "a"
прив’язаним до нього датою , то selection.data()
він повернеться, ["a"]
а не так, "a"
як деякі можуть очікувати.
selection.datum()
має сенс для одного вибору, оскільки він визначається як повернення даної, прив'язаної до першого елемента виділення. Так у наведеному вище прикладі з виділенням, що складається з елементів DOM із зв'язаною датою "a"
, "b"
і "c"
, selection.datum()
просто повернеться "a"
.
Зауважте, що навіть якщо
selection
є один елемент,selection.datum()
іselection.data()
повертайте різні значення. Перший повертає зв'язану дату для вибору ("a"
у прикладі вище), тоді як другий повертає зв'язану дату в масиві (["a"]
у прикладі вище).
Сподіваємось, це допомагає з’ясувати, як selection.data
і чим selection.datum()
відрізняються один від одного як при наданні даних у якості вхідного аргументу, так і при запиті на зв'язану дату, не надаючи жодних вхідних аргументів.
PS - Найкращий спосіб зрозуміти, як це працює - це почати з чистого HTML-документа в Chrome і відкрити консоль і спробувати додати в документ кілька елементів, а потім почати прив'язування даних за допомогою selection.data
та selection.datum
. Іноді набагато простіше "обмацувати" щось, роблячи, ніж читаючи.
Ось кілька хороших посилань:
Гарне обговорення D3 "data ()": розуміння того, як D3.js пов'язує дані з вузлами
За останнім:
# selection.data([values[, key]])
Поєднує вказаний масив даних із поточним виділенням. Зазначені значення - це масив значень даних, наприклад масив чисел чи об'єктів, або функція, яка повертає масив значень.
...
# selection.datum([value])
Отримує або встановлює зв'язані дані для кожного вибраного елемента. На відміну від методу select.data, цей метод не обчислює з'єднання (і, таким чином, не обчислює вибір входу та виходу).
Я думаю, що пояснення, які дав HamsterHuey, є найкращим до цих пір. Щоб розширити його і надати наочне зображення відмінностей, я створив зразок документа, який ілюструє принаймні частину відмінностей між data
і datum
.
Нижченаведена відповідь - це більше думка, отримана завдяки використанню цих методів, але я рада, що мене виправлять, якщо я помиляюся.
Цей приклад можна запустити нижче або в цій скрипці .
const data = [1,2,3,4,5];
const el = d3.select('#root');
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node => data: ${d}`);
const join= el
.selectAll('div.b')
.data(data);
join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
Я думаю, що datum
це простіше зрозуміти, оскільки він не робить з'єднання, але, звичайно, це також означає, що у нього є різні випадки використання.
Для мене одна велика різниця - хоча є і більше - це той факт, що data
це лише природний спосіб робити (в прямому ефірі) оновлення діаграми d3, оскільки вся схема введення / оновлення / виходу робить її простою, як тільки ви її отримаєте.
datum
з іншого боку, мені здається, більше підходить для статичних зображень. У наведеному нижче прикладі, наприклад, я міг досягти такого ж результату, коли я переходив до оригінального масиву та отримував доступ до даних за таким індексом:
data.map((n, i) => {
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node-${n} => data: ${d[i]}`);
});
Спробуйте тут: https://jsfiddle.net/gleezer/e4m6j2d8/6/
Знову ж таки, я вважаю, що це легше зрозуміти, оскільки ви позбавитесь від психічного тягаря, що випливає з шаблону введення / оновлення / виходу, але як тільки вам доведеться оновити або змінити вибір, вам, безумовно, буде краще вдаватися .data()
.
const data = [1,2,3,4,5];
const el = d3.select('#root');
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node => data: ${d}`);
const join= el
.selectAll('div.b')
.data(data);
join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
/* Ignore all the css */
html {
font-family: arial;
}
.l {
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
margin: 10px 0;
}
.l-a {
background: #cf58e4;
}
.l-b {
background: #42e4e4;
}
.a {
border-bottom: 2px solid #cf58e4;
}
.b {
border-bottom: 2px solid #42e4e4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>
<div style="margin-bottom: 20px;">
<span class="l l-a"></span> .datum() <br />
<span class="l l-b"></span> .data()
</div>
<div id="root"></div>