Skip to content

Instantly share code, notes, and snippets.

@tonyhschu
Last active October 7, 2016 02:31
Show Gist options
  • Save tonyhschu/39b5de0c9a87cb20b07fb0f0ddfb12d6 to your computer and use it in GitHub Desktop.
Save tonyhschu/39b5de0c9a87cb20b07fb0f0ddfb12d6 to your computer and use it in GitHub Desktop.
Generating hex grid positions part 2
license: mit
<!DOCTYPE html>
<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; }
</style>
</head>
<body>
<script>
console.clear()
var SQRT_3_2 = Math.sqrt(3)/2
var SCALE = 10
var toScreen = function(cube) {
var q = cube[0]
var r = cube[1]
var s = cube[2]
return {
x: SCALE * (r-q) * SQRT_3_2,
y: SCALE * (0.5*(r+q) - s)
}
}
// Feel free to change or delete any of the code you see in this editor!
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500)
var g = svg.append('g')
.attr('transform', 'translate(480, 250)')
var constrainedHexPositionFactory = function() {
const SQRT_3_2 = Math.sqrt(3)/2
const SCALE = 10
let candidates = []
let occupied = {}
let beenCanned = {}
let directions = [
[+1, -1, 0], [+1, 0, -1], [0, +1, -1],
[-1, +1, 0], [-1, 0, +1], [0, -1, +1]
]
let move = function(cur, dir) {
return [cur[0] + dir[0], cur[1] + dir[1], cur[2] + dir[2]]
}
let positionDistance = function(cube) {
var q = cube[0]
var r = cube[1]
var s = cube[2]
var x = SCALE * (r-q) * SQRT_3_2
var y = SCALE * (0.5*(r+q) - s)
return Math.sqrt(x * x + y * y)
}
let computeNewCandidates = function(position) {
return directions.map((dir) => {
return move(position, dir)
})
.filter((c) => {
let isOccupied = checkHash(occupied, c)
let hasAlreadyBeenCandidate = checkHash(beenCanned, c)
return !isOccupied && !hasAlreadyBeenCandidate
})
.map((c) => {
addPositionToHash(beenCanned, c)
return {
distance: positionDistance(c),
position: c
}
})
}
let addPositionToHash = function(hash, position) {
let x = hash[position[0]]
if (!x) {
x = {}
hash[position[0]] = x
}
let y = x[position[1]]
if (!y) {
y = {}
x[position[1]] = y
}
let z = y[position[2]]
if (!z) {
y[position[2]] = position
}
}
let checkHash = function(hash, position) {
let x = hash[position[0]]
if (!x) { return false }
let y = hash[position[0]][position[1]]
if (!y) { return false}
let z = hash[position[0]][position[1]][position[2]]
return (z) ? true : false
}
return function() {
let newPosition
if (candidates.length <= 0) {
newPosition = [0, 0, 0]
} else {
let candidate = candidates.shift()
newPosition = candidate.position
}
let newCandidates = computeNewCandidates(newPosition)
candidates = candidates.concat(newCandidates)
.sort((a, b) => {
return a.distance - b.distance
})
addPositionToHash(occupied, newPosition)
candidates.forEach((c) => {
addPositionToHash(beenCanned, c)
})
return newPosition
}
}
let mouseDistance = 0
svg
.on("mousemove", function(e) {
let m = d3.mouse(this)
let dx = 480 - m[0]
let dy = 250 - m[1]
mouseDistance = Math.sqrt(dx * dx + dy * dy)
})
let paint = function() {
let hexPosition = constrainedHexPositionFactory()
let numberOfCircles = Math.floor(mouseDistance) * 4
let coordinates = d3.range(numberOfCircles).map((i) => {
return hexPosition()
}).map((cube, i) => {
return {
key: i,
cube: cube,
screen: toScreen(cube)
}
})
let points = g.selectAll('circle')
.data(coordinates, function(d) { return d.key })
points
.enter()
.append('circle')
.attr('r', 6)
.merge(points)
.attr('fill', function(d) {
let r = d.cube[0] * 5 + 150
let g = d.cube[1] * 5 + 150
let b = d.cube[2] * 5 + 150
return 'rgb(' + r + ', ' + g + ', ' + b + ')'
})
.attr('cx', function(d) {
return d.screen.x
})
.attr('cy', function(d) {
return d.screen.y
})
points.exit().remove()
window.requestAnimationFrame(paint)
}
paint()
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment