Skip to content

Instantly share code, notes, and snippets.

@dankronstal
Last active February 5, 2016 22:04
Show Gist options
  • Save dankronstal/7b5ed757e115de68ca57 to your computer and use it in GitHub Desktop.
Save dankronstal/7b5ed757e115de68ca57 to your computer and use it in GitHub Desktop.
playing with hexes

learning about hexagonal layouts in d3. nothing here but creating a grid, and simple neighbor detection.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.hexagon {
fill: none;
stroke: #000;
stroke-width: .5px;
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://d3js.org/d3.hexbin.v0.min.js?5c6e4f0"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var points = [];
var hexRadius = 30;
MapRows = 8, MapColumns = 16;
var selectedPoint = null;
for (var i = 0; i < MapRows; i++) {
for (var j = 0; j < MapColumns; j++) {
points.push([hexRadius * j * 1.75, hexRadius * i * 1.5, j, i, "id-"+j+"-"+i]);
}//for j
}//for i
var color = d3.scale.linear()
.domain([0, 20])
.range(["white", "steelblue"])
.interpolate(d3.interpolateLab);
var hexbin = d3.hexbin()
.size([width, height])
.radius(30);
var x = d3.scale.identity()
.domain([0, width]);
var y = d3.scale.linear()
.domain([0, height])
.range([height, 0]);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("class", "mesh")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("clip-path", "url(#clip)")
.selectAll(".hexagon")
.data(hexbin(points))
.enter().append("path")
.attr("class", "hexagon")
.attr("d", hexbin.hexagon())
.attr("transform", function(d) { return "translate(" + (margin.left + d.x) + "," + (margin.left + d.y) + ")"; })
.style("fill", function(d) { return color(d.length); })
.attr("id",function(d){
return "id-"+d.j+"-"+d.i;
})
.on("mouseover", function(d){
if(selectedPoint != null && isNeighbor(d)){
d3.select("#id-"+d.j+"-"+d.i).style("fill","yellow");
}
})
.on("mouseout", function(d){
if(selectedPoint != null && isNeighbor(d)){
d3.select("#id-"+d.j+"-"+d.i).style("fill","#FF8A8A");
}
})
.on("click", function(d){
if(selectedPoint != d){
selectedPoint = d;
d3.selectAll(".hexagon").transition().duration(500).style("fill", function(d) { return color(d.length); });
d3.select("#id-"+d.j+"-"+d.i).transition().duration(500).style("fill","red");
changeNeighbors(d.j, d.i, "#FF8A8A", 500);
}else{
selectedPoint = null;
d3.selectAll(".hexagon").transition().duration(500).style("fill", function(d) { return color(d.length); });
}
});
function changeNeighbors(j, i, color, transDuration){
d3.select("#id-"+(j+0)+"-"+(i+1)).transition().duration(transDuration).style("fill",color);
d3.select("#id-"+(j+1)+"-"+(i+0)).transition().duration(transDuration).style("fill",color);
d3.select("#id-"+(j-1)+"-"+(i+0)).transition().duration(transDuration).style("fill",color);
d3.select("#id-"+(j+0)+"-"+(i-1)).transition().duration(transDuration).style("fill",color);
if(j % 2 > 0){
d3.select("#id-"+(j-1)+"-"+(i+1)).transition().duration(transDuration).style("fill",color);
d3.select("#id-"+(j+1)+"-"+(i+1)).transition().duration(transDuration).style("fill",color);
}else{
d3.select("#id-"+(j+1)+"-"+(i-1)).transition().duration(transDuration).style("fill",color);
d3.select("#id-"+(j-1)+"-"+(i-1)).transition().duration(transDuration).style("fill",color);
}
}
function isNeighbor(p){
if(p.j == selectedPoint.j && p.i == selectedPoint.i+1) return true;
if(p.j == selectedPoint.j+1 && p.i == selectedPoint.i) return true;
if(p.j == selectedPoint.j-1 && p.i == selectedPoint.i) return true;
if(p.j == selectedPoint.j && p.i == selectedPoint.i-1) return true;
if(p.j == selectedPoint.j-1 && p.i == selectedPoint.i+1 && !(p.j % 2 > 0)) return true;
if(p.j == selectedPoint.j+1 && p.i == selectedPoint.i+1 && !(p.j % 2 > 0)) return true;
if(p.j == selectedPoint.j-1 && p.i == selectedPoint.i-1 && (p.j % 2 > 0)) return true;
if(p.j == selectedPoint.j+1 && p.i == selectedPoint.i-1 && (p.j % 2 > 0)) return true;
return false;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment