Чи можете мені хтось пояснити різницю між даними () та даними () у 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>