Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
.bg{fill:#fff1e0}
.grid{fill:#dedede}
.highlight{fill:#bb6d82}
</style>
</head>
<body>
<script>
//canvas size
const w = 960;
const h = 500;
const margin = {left:10,right:10,top:10,bottom:10};
/*=For 'type', use 'rect', 'ellipse', or a custom shape defined in the defs section. The geometry of a custom icon will over-ride the width/height settings here*/
const grid = {type:"ellipse",
width:15,
height:15 ,
cols:25,
rows:26,
direction:"across",
highlight:330,
padding:{top:1,left:1,bottom:1,right:1}}
const svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
const defs = svg.append("defs")
defs.append("g")
.attr("id","custom")
.append("polygon")
.attr("points","12.5,0.9 16.3,8.5 24.7,9.8 18.6,15.7 20.1,24.1 12.5,20.2 4.9,24.1 6.4,15.7 0.3,9.8 8.7,8.5");
defs.append("g")
.attr("id","custom2")
.append("path")
.attr("d","M10.2,12l13,3.1c-1.3,4.6-5.6,8-10.6,8c-6.1,0-11.1-5-11.1-11.1S6.4,1,12.5,1c5,0,9.3,3.4,10.6,8L10.2,12zM12.5,2.7c-1,0-1.9,0.8-1.9,1.9s0.8,1.9,1.9,1.9s1.9-0.8,1.9-1.9S13.5,2.7,12.5,2.7z")
const inner = {width:w-(margin.left+margin.right),height:h-(margin.top+margin.bottom)};
//background
svg.append("rect")
.attr("class","bg")
.attr("x",margin.left)
.attr("y",margin.right)
.attr("width",inner.width)
.attr("height",inner.height)
var icons = svg.append("g")
.attr("transform","translate("+margin.left+","+margin.top+")")
//call function
buildGrid(grid,icons);
function buildGrid(config,element){
//create a d3 range of the number of required elements
const gridIndex = d3.range(config.cols*config.rows);
let shape;
switch(config.type) {
case "rect":
shape = "rect";
break;
case "ellipse":
shape = "ellipse";
break;
default:
shape = "use";
}
const grid = element.append("g")
.attr("class","grid")
.selectAll(shape)
.data(gridIndex)
.enter()
.append(shape)
.attr("id",function(d,i){
return shape+i;
})
.attr("class",function(d){
if (d<config.highlight){
return "highlight"
} else {
return "grid"
}
})
switch(shape){
case "rect":
grid.attr("width",config.width-(config.padding.left+config.padding.right))
.attr("height",config.height-(config.padding.top+config.padding.bottom))
.attr("x",function(d,i){
var colIndex =d % config.cols;
return colIndex*config.width
})
.attr("y",function(d,i){
var rowIndex=Math.floor(d/config.cols)
return rowIndex*config.height;
});
break;
case "ellipse":
grid.attr("ry",(config.height-(config.padding.top+config.padding.bottom))/2)
grid.attr("rx",(config.height-(config.padding.left+config.padding.right))/2)
.attr("cx",function(d,i){
var colIndex =d % config.cols;
return colIndex*config.width+(config.width/2)
})
.attr("cy",function(d,i){
var rowIndex=Math.floor(d/config.cols)
return rowIndex*config.height+(config.height/2);
})
break;
case "use":
grid.attr("xlink:href","#"+config.type)
.attr("x",function(d,i){
var colIndex =d % config.cols;
return colIndex*config.width
}).attr("y",function(d,i){
var rowIndex=Math.floor(d/config.cols)
return rowIndex*config.height;
})
.attr("width",config.width-(config.padding.left+config.padding.right))
.attr("height",config.height-(config.padding.top+config.padding.bottom))
}
}
</script>
</body>
https://d3js.org/d3.v4.min.js