简体   繁体   中英

D3.js and nested data - Why is my exit() set empty

I'm having an issue when dealing with manipulating nested data with D3.js

Data consists of array of objects which represent categories . Each category has multiple checkin s. I want a section for every category , and within that, a div for each checkin . I manipulate data over time and rely on update, enter and exit mechanisms of D3.js to properly output the data to DOM.

What I don't understand:

  • Why when second update is invoked, the old data doesn't show up in the exit() set , and therefore is not deleted?
  • Why when update() is invoked third time with data1 again, entries are again appended again despite the key function in data being provided ? By my understanding at this point D3 should recognise that this is actually an update and that data with the same key already exist in this section.

The second problem is probably related to the first one, but now I'm not sure.

Here's an interactive bl.ocks.org: https://bl.ocks.org/mattleonowicz/fd975a6d914f90c9934464df57e498c9

Same code below:

 <html> <body> <div id="app" /> <script src="https://d3js.org/d3.v5.min.js"></script> <script> const data1 = [ { category: { id: 1 }, checkins: [ { lat: 1, lon: 1 }, { lat: 2, lon: 2 } // ... more objects like this would normally be here ] } // ... more objects like this would normally be here ]; const data2 = [ { category: { id: 1 }, checkins: [ { lat: 3, lon: 3 }, { lat: 4, lon: 4 } // ... more objects like this would normally be here ] } // ... more objects like this would normally be here ]; update(data1); setTimeout(() => update(data2), 2000); setTimeout(() => update(data1), 4000); function update(data) { const categoriesData = d3.select('#app') .selectAll('section') .data(data, d => d.category.id); // CATEGORIES EXIT categoriesData.exit() .remove(); // CATEGORIES UPDATE + ENTER - bind all categories with their checkins const checkinsData = categoriesData.enter() .append('section') .merge(categoriesData) .selectAll('section') .data(d => d.checkins, d => `${d.lon},${d.lat}`); // CHECKINS UPDATE : nothing, because checkins will only come and go // CHECKINS EXIT checkinsData.exit() .remove(); // CHECKINS ENTER checkinsData.enter() .append('div') .html(d => `${d.lon},${d.lat}`); } </script> </body> </html> 

You have a typo here:

  // CATEGORIES UPDATE + ENTER - bind all categories with their checkins
  const checkinsData = categoriesData.enter()
    .append('section')
    .merge(categoriesData)
->  .selectAll('section')
    .data(d => d.checkins, d => `${d.lon},${d.lat}`);

You wanted to write .selectAll('div') in the second selection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM