{
const squareSize = 6;
const numberOfSquaresRow = 5;
const total = d3.sum(grain.filter(d => d.year == 2021), (d) => d.production);
const gap = 0;
const projection = d3.geoMercator()
.scale(2200)
.center([2,49.5])
.rotate([-30,0,0])
const path = d3.geoPath().projection(projection);
const svg = d3.create("svg")
.attr("width", 975)
.attr("height", 610)
.attr("viewBox", [0, 0, 975, 610])
.attr("style", "width: 100%; height: auto; height: intrinsic;");
const regions = svg.append("g")
.selectAll('path')
.data(ukraine.features)
.join('path')
regions
.attr("fill", "#ddd")
.attr("stroke", "#eeeeee")
.attr("stroke-width", 1)
.attr("d", path);
const waffles = svg.selectAll(".waffle")
.append("g")
.data(grain_nested)
.enter().append("g")
.attr('class', 'waffle')
.attr("transform", d => `translate(${projection([d.lon, d.lat])})`)
// Append waffles by region
waffles
.selectAll("rect")
.data(d => waffleData(d.children))
.join("rect")
.attr("width", squareSize)
.attr("height", squareSize)
.attr("fill", (d) => color(d.crop))
.attr("stroke", "white")
.attr("stroke-width", 0.7)
.attr("y", (d, i, arr) => {
// Arrange squares by row
const numberOfSquaresCol = Math.ceil(arr.length / numberOfSquaresRow);
const waffleHeight = squareSize * numberOfSquaresCol + numberOfSquaresCol * gap + squareSize;
const row = Math.floor(i / numberOfSquaresRow);
return waffleHeight - 2 * squareSize - (row * squareSize + row * gap);
})
.attr("x", function (d, i) {
const col = i % numberOfSquaresRow;
return col * squareSize + col * gap;
})
.attr("transform", (d, i, arr) => {
const numberOfSquaresCol = Math.ceil(arr.length / numberOfSquaresRow);
const waffleHeight = squareSize * numberOfSquaresCol + numberOfSquaresCol * gap + squareSize;
const waffleWidth = squareSize * numberOfSquaresRow + numberOfSquaresRow * gap + squareSize;
return `translate(${d.region === "Kirovohrad" ? 0 : -waffleWidth/2 }, ${-waffleHeight * 0.7})`
})
// Add interactive tooltips
waffles
.on('touchmove mousemove', function(e,d) {
d3.select(this)
.raise()
.call(g => g
.selectAll('rect')
.transition()
.duration(100)
.style('stroke', 'black'))
.call(g => g
.append('g')
.attr('class', 'tooltip')
.call(callout, `${d.region} region \n ${arrayJoin(d.children, "crop", "production")}`)) // callout is an external function
})
.on('touchend mouseleave', function(e,d) {
d3.select(this)
.call(g => g
.selectAll('rect')
.transition()
.duration(100)
.style('stroke', 'white'))
.call(g => g.selectAll(".tooltip")
.remove())
})
return svg.node()
}