I'm trying to create a grid of squares using D3. My code works, but I'd like to add some padding around each of the squares so that the grid does not look so "tight".
Here is my code:
class Matrix {
constructor(parentElement, data1, data2, data3) {
this.parentElement = parentElement;
this.data1 = data1;
this.data2 = data2;
this.data3 = data3;
this.cellHeight = 40;
this.cellWidth = 40;
this.initializeVisual()
}
initializeVisual() {
let vis = this;
vis.margin = {top: 20, right: 20, bottom: 20, left: 40};
vis.width = document.getElementById(vis.parentElement).getBoundingClientRect().width - vis.margin.left - vis.margin.right;
vis.height = 800 - vis.margin.top - vis.margin.bottom;
// init drawing area
vis.svg = d3.select('#' vis.parentElement).append('svg')
.attr('width', vis.width vis.margin.left vis.margin.right)
.attr('height', vis.height vis.margin.top vis.margin.bottom)
.append('g')
.attr('transform', `translate (${vis.margin.left}, ${vis.margin.top})`);
// Draws the initial grid
let squaresPerRow = 16
let scale = d3.scaleLinear()
.domain([0, squaresPerRow -1])
.range([0, this.cellWidth * squaresPerRow])
vis.squares = vis.svg.selectAll('.squares')
.data(d3.range(256))
.enter()
.append('rect')
.attr('x', (d, i) => {
let n = i % squaresPerRow
return scale(n)
})
.attr('y', (d, i) => {
let n = Math.floor(i / 16)
return scale(n)
})
.attr('width', this.cellWidth)
.attr('height', this.cellHeight)
.attr('fill', 'lightgrey');
}
The resulting grid looks like this:
How can I add the padding?
Thanks!
CodePudding user response:
Personally I'd change the linear scale for a point scale, but here's a solution using most of your code as it is.
First, get rid of that minus one in the domain, that's a cumbersome way for creating the padding:
.domain([0, squaresPerRow -1])
Then, after you set the padding (here named padding), you can translate the x and y positions by half of it, and subtracting the rectangles' width and height by that padding.
Here's a demo, change the variable padding for different spaces:
const svg = d3.select("div")
.append('svg')
.attr('width', 400)
.attr('height', 400);
let squaresPerRow = 8,
cellWidth = 40,
cellHeight = 40,
padding = 14;
let scale = d3.scaleLinear()
.domain([0, squaresPerRow])
.range([0, cellWidth * squaresPerRow])
const squares = svg.selectAll('.squares')
.data(d3.range(squaresPerRow ** 2))
.enter()
.append('rect')
.attr('x', (d, i) => {
let n = i % squaresPerRow
return scale(n) padding / 2
})
.attr('y', (d, i) => {
let n = Math.floor(i / squaresPerRow)
return scale(n) padding / 2
})
.attr('width', cellWidth - padding)
.attr('height', cellHeight - padding)
.attr('fill', 'lightgrey');
<script src="https://d3js.org/d3.v7.min.js"></script>
<div></div>

