{
const svg = d3.create('svg').attr('viewBox', [0, 0, width, 400]);
const gridSize = 25;
const gridDotSize = 3;
const gridColor = '#a4a4a4';
svg.append('pattern')
.attr('id', 'dot-pattern')
.attr('patternUnits', 'userSpaceOnUse')
.attr('x', 0)
.attr('y', 0)
.attr('width', gridSize)
.attr('height', gridSize)
.append('rect')
.attr('width', gridDotSize)
.attr('height', gridDotSize)
.attr('fill', gridColor)
.attr('x', (gridSize / 2) - (gridDotSize / 2))
.attr('y', (gridSize / 2) - (gridDotSize / 2));
svg.append('rect')
.attr('fill', 'url(#dot-pattern)')
.attr('width', '100%')
.attr('height', '100%');
function updateGrid(zoomEvent) {
svg.select('#dot-pattern')
.attr('x', zoomEvent.transform.x)
.attr('y', zoomEvent.transform.y)
.attr('width', gridSize * zoomEvent.transform.k)
.attr('height', gridSize * zoomEvent.transform.k)
.selectAll('rect')
.attr('x', (gridSize * zoomEvent.transform.k / 2) - (gridDotSize / 2))
.attr('y', (gridSize * zoomEvent.transform.k / 2) - (gridDotSize / 2))
.attr('opacity', Math.min(zoomEvent.transform.k, 1));
}
var content = svg.append('g').attr('id', 'content');
content.append('rect').attr('fill', '#65D097').attr('rx', 10).attr('width', 100).attr('height', 100).attr('x', width / 2 - 75).attr('y', 125);
content.append('rect').attr('fill', '#75E6CF').attr('rx', 5).attr('width', 50).attr('height', 50).attr('x', width / 2 + 35).attr('y', 175);
content.append('rect').attr('fill', '#5CC4FF').attr('rx', 3).attr('width', 25).attr('height', 25).attr('x', width / 2 + 35).attr('y', 235);
svg.call(d3.zoom()
.scaleExtent([0.25, 2])
.on("zoom", (event)=> {
content.attr('transform', event.transform);
updateGrid(event);
}));
return svg.node();
}