{
const svg = d3.create("svg")
.attr("width", 256)
.attr("height", 256);
const gridSize = 17;
const circleRadius = 6;
const circleSpacing = 5;
function interpolateColor(x, y, gridSize) {
const topLeft = { r: 80, g: 80, b: 255 };
const topRight = { r: 255, g: 0, b: 0 };
const bottomLeft = { r: 80, g: 255, b: 80 };
const bottomRight = { r: 255, g: 255, b: 0 };
const ratioX = x / (gridSize - 1);
const ratioY = y / (gridSize - 1);
const top = {
r: topLeft.r + (topRight.r - topLeft.r) * ratioX,
g: topLeft.g + (topRight.g - topLeft.g) * ratioX,
b: topLeft.b + (topRight.b - topLeft.b) * ratioX
};
const bottom = {
r: bottomLeft.r + (bottomRight.r - bottomLeft.r) * ratioX,
g: bottomLeft.g + (bottomRight.g - bottomLeft.g) * ratioX,
b: bottomLeft.b + (bottomRight.b - bottomLeft.b) * ratioX
};
const final = {
r: top.r + (bottom.r - top.r) * ratioY,
g: top.g + (bottom.g - top.g) * ratioY,
b: top.b + (bottom.b - top.b) * ratioY
};
return `rgb(${Math.round(final.r)}, ${Math.round(final.g)}, ${Math.round(final.b)})`;
}
const data = Array.from({ length: gridSize * gridSize }, (_, i) => ({
x: (i % gridSize) * (circleRadius * 2 + circleSpacing) + circleRadius + circleSpacing / 2,
y: Math.floor(i / gridSize) * (circleRadius * 2 + circleSpacing) + circleRadius + circleSpacing / 2,
color: interpolateColor(i % gridSize, Math.floor(i / gridSize), gridSize),
}));
svg.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", circleRadius)
.attr("fill", d => d.color);
return svg.node();
}