|
(function() { |
|
var global, hexProjection, hexTopology, register; |
|
|
|
global = { |
|
registry: {} |
|
}; |
|
|
|
register = function(hexes) { |
|
return hexes.each(function(d) { |
|
if (!(d.x in global.registry)) global.registry[d.x] = {}; |
|
if (!(d.y in global.registry[d.x])) return global.registry[d.x][d.y] = this; |
|
}); |
|
}; |
|
|
|
window.main = function() { |
|
var coord_format, height, new_label, radius, svg, width; |
|
width = 960; |
|
height = 500; |
|
radius = 40; |
|
coord_format = d3.format(' 03d'); |
|
global.hex_topology = hexTopology(radius, width, height); |
|
global.path_generator = d3.geo.path().projection(hexProjection(radius)); |
|
svg = d3.select('body').append('svg').attr('width', width).attr('height', height); |
|
/* draw the axes |
|
*/ |
|
svg.append('line').attr('class', 'x axis').attr('x1', 450).attr('y1', 300).attr('x2', 570).attr('y2', 300); |
|
svg.append('line').attr('class', 'y axis').attr('x1', 450).attr('y1', 300).attr('x2', 450).attr('y2', 180); |
|
/* draw the hexagons |
|
*/ |
|
svg.append('g').attr('class', 'hexagon').selectAll('path').data(global.hex_topology.objects.hexagons.geometries).enter().append('path').attr('d', function(d) { |
|
return global.path_generator(topojson.feature(global.hex_topology, d)); |
|
}).style('stroke', function(d) { |
|
if (d.x === 0 && d.y === 0) { |
|
return 'black'; |
|
} else { |
|
return 'none'; |
|
} |
|
}).call(register); |
|
/* draw the coordinates |
|
*/ |
|
new_label = svg.append('g').attr('class', 'label').selectAll('text').data(global.hex_topology.objects.hexagons.geometries).enter().append('text').attr('transform', function(d) { |
|
return "translate(" + (global.path_generator.centroid(topojson.feature(global.hex_topology, d))) + ")"; |
|
}); |
|
new_label.append('tspan').text(function(d) { |
|
return coord_format(d.x); |
|
}).attr('x', '0.6em').attr('y', '-0.5em'); |
|
new_label.append('tspan').text(function(d) { |
|
return coord_format(d.y); |
|
}).attr('x', '0.6em').attr('y', '1em'); |
|
svg.append('path').datum(topojson.mesh(global.hex_topology, global.hex_topology.objects.hexagons)).attr('class', 'mesh').attr('d', global.path_generator); |
|
/* select a few example hexagons by using their coordinates |
|
*/ |
|
d3.select(global.registry[-4][2]).attr('fill', 'yellow'); |
|
return d3.select(global.registry[1][-2]).attr('fill', 'yellow'); |
|
}; |
|
|
|
/* create the hex mesh TopoJSON |
|
*/ |
|
|
|
hexTopology = function(radius, width, height) { |
|
var arcs, dx, dy, geometries, i, j, m, n, q, x, y; |
|
dx = radius * 2 * Math.sin(Math.PI / 3); |
|
dy = radius * 1.5; |
|
m = Math.ceil((height + radius) / dy) + 1; |
|
n = Math.ceil(width / dx) + 1; |
|
geometries = []; |
|
arcs = []; |
|
for (j = -1; -1 <= m ? j <= m : j >= m; -1 <= m ? j++ : j--) { |
|
for (i = -1; -1 <= n ? i <= n : i >= n; -1 <= n ? i++ : i--) { |
|
y = j * 2; |
|
x = (i + (j & 1) / 2) * 2; |
|
arcs.push([[x, y - 1], [1, 1]], [[x + 1, y], [0, 1]], [[x + 1, y + 1], [-1, 1]]); |
|
} |
|
} |
|
q = 3; |
|
for (j = 0; 0 <= m ? j < m : j > m; 0 <= m ? j++ : j--) { |
|
for (i = 0; 0 <= n ? i < n : i > n; 0 <= n ? i++ : i--) { |
|
geometries.push({ |
|
type: 'Polygon', |
|
arcs: [[q, q + 1, q + 2, ~(q + (n + 2 - (j & 1)) * 3), ~(q - 2), ~(q - (n + 2 + (j & 1)) * 3 + 2)]], |
|
x: i - 6, |
|
y: -j + 6 |
|
}); |
|
q += 3; |
|
} |
|
q += 6; |
|
} |
|
return { |
|
transform: { |
|
translate: [0, 0], |
|
scale: [1, 1] |
|
}, |
|
objects: { |
|
hexagons: { |
|
type: 'GeometryCollection', |
|
geometries: geometries |
|
} |
|
}, |
|
arcs: arcs |
|
}; |
|
}; |
|
|
|
/* define a custom projection to make hexagons appear regular |
|
*/ |
|
|
|
hexProjection = function(radius) { |
|
var dx, dy; |
|
dx = radius * 2 * Math.sin(Math.PI / 3); |
|
dy = radius * 1.5; |
|
return { |
|
stream: function(stream) { |
|
return { |
|
point: (function(x, y) { |
|
return stream.point(x * dx / 2, (y - (2 - (y & 1)) / 3) * dy / 2); |
|
}), |
|
lineStart: (function() { |
|
return stream.lineStart(); |
|
}), |
|
lineEnd: (function() { |
|
return stream.lineEnd(); |
|
}), |
|
polygonStart: (function() { |
|
return stream.polygonStart(); |
|
}), |
|
polygonEnd: (function() { |
|
return stream.polygonEnd(); |
|
}) |
|
}; |
|
} |
|
}; |
|
}; |
|
|
|
}).call(this); |