Skip to content

Instantly share code, notes, and snippets.

@fabiovalse
Last active August 29, 2015 14:16
Show Gist options
  • Save fabiovalse/dca8ad12204c6db9d588 to your computer and use it in GitHub Desktop.
Save fabiovalse/dca8ad12204c6db9d588 to your computer and use it in GitHub Desktop.
Hexagonal Grid: how do you find which hexagon a point is in?
svg {
background: #fff;
}
.hexagon path {
fill: #ddd;
stroke: #000;
stroke-width: .5px;
}
.label {
pointer-events: none;
font-family: sans-serif;
text-anchor: middle;
}
.cursor {
fill: none;
stroke: red;
stroke-width: 3px;
pointer-events: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.hexbin.v0.min.js?5c6e4f0"></script>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
var width = 960;
height = 500;
var points = [], radius = 30;
var cos30 = Math.sqrt(3)/2;
var sin30 = 1/2;
var rows = Math.ceil(height/(3/2*radius));
var columns = Math.ceil(width/(cos30*radius*2));
var gridHeight = sin30*radius*3;
var gridWidth = cos30*radius*2;
var c = sin30 * radius;
var m = c / (gridWidth/2);
for (i = 0; i < rows; i++) {
for (j = 0; j < columns; j++) {
points.push({"i": i, "j": j});
}
}
var getHexagon = function (point) {
point[0] = point[0] + cos30*radius;
point[1] = point[1] + radius;
var row = Math.floor(point[1] / gridHeight);
var column;
var rowIsOdd = (row % 2 == 1);
if (rowIsOdd)
column = Math.floor((point[0] - gridWidth/2) / gridWidth);
else
column = Math.floor(point[0] / gridWidth);
var relY = point[1] - (row * gridHeight);
var relX;
if (rowIsOdd)
relX = (point[0] - (column * gridWidth)) - gridWidth/2;
else
relX = point[0] - (column * gridWidth);
// Work out if the point is above either of the hexagon's top edges
if (relY < (-m * relX) + c) {// LEFT edge
row--;
if (!rowIsOdd)
column--;
}
else if (relY < (m * relX) - c) {// RIGHT edge
row--;
if (rowIsOdd)
column++;
}
return [row, column];
};
var vis = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var cursor = vis.append("path")
.attr("class", "cursor")
.attr("d", function(r) {return "M0,"+radius+" L"+(cos30*radius)+","+(sin30*radius)+" L"+(cos30*radius)+","+(-sin30*radius)+" L0,"+(-radius)+" L"+(-cos30*radius)+","+(-sin30*radius)+" L"+(-cos30*radius)+","+(sin30*radius)+" Z";});
var get_coordinates = function(d, i) {
h = getHexagon(d3.mouse(this));
if (h[0] % 2 === 0)
cursor.attr("transform", "translate(" + (h[1]*cos30*radius*2) + "," + (h[0]*3/2*radius) + ")");
else
cursor.attr("transform", "translate(" + (h[1]*(cos30*radius*2)+(cos30*radius)) + "," + (h[0]*3/2*radius) + ")");
};
var hexagon_layer = vis.insert("g", ":last-child").on('mouseover', get_coordinates);
var hexagon = hexagon_layer.selectAll(".hexagon")
.data(points);
var enter_hexagon = hexagon.enter().append("g")
.attr("class", "hexagon")
.attr("transform", function(d) {
if (d.i % 2 === 0)
return "translate(" + (d.j*cos30*radius*2) + "," + (d.i*3/2*radius) + ")";
else
return "translate(" + (d.j*(cos30*radius*2)+(cos30*radius)) + "," + (d.i*3/2*radius) + ")";
});
enter_hexagon.append("path")
.attr("d", function(r) {return "M0,"+radius+" L"+(cos30*radius)+","+(sin30*radius)+" L"+(cos30*radius)+","+(-sin30*radius)+" L0,"+(-radius)+" L"+(-cos30*radius)+","+(-sin30*radius)+" L"+(-cos30*radius)+","+(sin30*radius)+" Z";});
enter_hexagon.append("text")
.attr("class", "label")
.attr("dy", "0.35em")
.text(function(d) {return d.i + "," + d.j;});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment