Search code examples
javascripthtmlcssd3.jscss-grid

Add Rows to grid layout via d3


I am fairly new to d3, so I consider this a newbie question, b/c I still could not wrap my head around data joins. I am trying to add rows to a grid layout. Each row is represented as an object with several slots and the rows are stored in an array.

In my .join I want to add several elements to the selection (content determined by the slots of the object, here simply the .text). I have difficulties to specify the .selectAll call before the .data call. I understand why this strange behaviour is occuring (basically) it tries to match the data to all divs in the selection (which are all cells).

How would I need to change m code, that each click on the button simply adds a new row?

Bonus question: as you cna see the cells are all mixed up. How would I add the data by row and not by column?

const data = [
  {cell1: '1/1', cell2: '1/2', cell3: '1/3', id: 1},
  {cell1: '2/1', cell2: '2/2', cell3: '2/3', id: 2}
];


function update(data) {
  d3.select('#grid')
    .selectAll('div')
    .data(data, (d) => d.id)
    .join((enter) => {
      enter.append('div')
        .classed('cell1', true)
        .text((d) => d.cell1);
      enter.append('div')
        .classed('cell2', true)
        .text((d) => d.cell2)
      enter.append('div')
        .classed('cell3', true)
        .text((d) => d.cell3);
  })
}

update(data)

function addRow() {
  const n = data.length + 1;
  const newRow = {cell1: n + '/1', cell2: n + '/2', cell3: n + '/3', id: n};
  data.push(newRow);
  update(data);
}
#grid {
  display: inline-grid;
  grid-template-columns: repeat(3, 200px);
}

#grid > div:nth-of-type(3n+2) {
  background-color: orange;
}

#grid > div:nth-of-type(3n+1) {
  background-color: purple;
}


#grid > div:nth-of-type(3n+0) {
  background-color: forestgreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<div id="grid">
</div>
<button id="add" onclick="addRow()">Add Row</button>


Solution

  • Ok first problem solved. I must not call .selectAll with 'div' as this will select all divs in the selection and then the join tries to match n rows with n x 3 divs-

    Easy remedy is to select only the first div (for instance) via .selectAll('.cell1'). This guarantees that there is always a match between rows in the data and rows in the grid (given that each row contains a single cell1 classed div.

    Only problem remaining is that the order is all messed up, but I will ask a new question for that.