Skip to content

Instantly share code, notes, and snippets.

@enjalot
Last active October 18, 2015 21:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save enjalot/ab6e41a267eb16370ab8 to your computer and use it in GitHub Desktop.
Save enjalot/ab6e41a267eb16370ab8 to your computer and use it in GitHub Desktop.
hilbert grid layout

Working towards a Hilbert Curve based grid layout. The idea would be to quickly layout a 1-dimensional array of data in a compact 2D area.

It has the added benefit that the sorting of the 1D array impacts the 2D distance, namely that items close together in 1D will be close together in 2D

LSystem code lifted from this block by nitaku who has many fascinating d3 experiments

Built with blockbuilder.org

forked from enjalot's block: hilbert grid

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="lsystem.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width: 100%; height: 100%; }
.curve {
fill: none;
stroke: #b5b5b5;
}
</style>
</head>
<body>
<svg></svg>
<script>
var exampleData = d3.range(1000).map(function(d) { return Math.random() });
var layout = new hilbert()
.sideLength(13)
console.log("NODES", layout.nodes(exampleData))
var color = d3.scale.linear()
.domain([0, 1000])
.range(["#a8ff60", "#0600cc"])
.interpolate(d3.interpolateHcl)
var svg = d3.select("svg")
var g = svg.append("g")
.attr("transform", "translate(270, 40)")
function drawCells() {
var cells = g.selectAll("rect")
.data(layout.nodes(exampleData)) // everything is recalculated when nodes is called
cells.enter().append("rect")
cells.exit().remove()
cells
.attr({
x: function(d) { return d.x },
y: function(d) { return d.y },
width: layout.sideLength() - 2,
height: layout.sideLength() - 2,
fill: function(d,i) { return color(d.index) }
})
}
drawCells();
function hilbert() {
var angle = 270 * Math.PI / 180;
var nodes = [];
var grid = [];
var data = [];
var sideLength = 20;
var steps, hilbertConfig, hilbertFractal;
function calculate() {
steps = Math.ceil(Math.log2(data.length || 1) / 2)
hilbertConfig = {
steps: steps,
axiom: 'A',
rules: {
A: '-BF+AFA+FB-',
B: '+AF-BFB-FA+'
}
}
hilbertFractal = LSystem.fractalize(hilbertConfig);
}
function newNodes() {
calculate();
nodes = [];
grid = LSystem.grid({
fractal: hilbertFractal,
side: sideLength,
angle: angle
})
console.log(data, grid)
data.forEach(function(d,i) {
var node = {
x: grid[i].x,
y: grid[i].y,
data: d,
index: i
}
nodes.push(node);
})
}
this.nodes = function(val) {
if(val) {
data = val
}
newNodes();
return nodes;
}
this.sideLength = function(val) {
if(val) {
sideLength = val;
return this;
}
return sideLength;
}
}
</script>
</body>
// from http://bl.ocks.org/nitaku/8947871
var LSystem = window.LSystem = {}
LSystem.fractalize = function(config) {
var char, i, input, output, _i, _len, _ref;
input = config.axiom;
for (i = 0, _ref = config.steps; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
output = '';
for (_i = 0, _len = input.length; _i < _len; _i++) {
char = input[_i];
if (char in config.rules) {
output += config.rules[char];
} else {
output += char;
}
}
input = output;
}
return output;
};
/* convert a Lindenmayer string into an SVG path string
*/
LSystem.path = function(config) {
var angle, char, path, _i, _len, _ref;
angle = 0.0;
path = 'M0 0';
_ref = config.fractal;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
char = _ref[_i];
if (char === '+') {
angle += config.angle;
} else if (char === '-') {
angle -= config.angle;
} else if (char === 'F') {
path += "l" + (config.side * Math.cos(angle)) + " " + (config.side * Math.sin(angle));
}
}
return path;
};
LSystem.grid = function(config) {
var angle, char, i, j, len, ref, x, y;
angle = 0.0;
j = 1;
var grid = [{x: 0, y: 0, j: 0}];
ref = config.fractal;
for (i = 0, len = ref.length; i < len; i++) {
//if(j >= config.data.length) return grid;
char = ref[i];
if (char === '+') {
angle += config.angle;
} else if (char === '-') {
angle -= config.angle;
} else if (char === 'F') {
x = config.side * Math.cos(angle);
y = config.side * Math.sin(angle);
x += grid[j-1].x;
y += grid[j-1].y;
grid.push({
x: x,
y: y,
//data: config.data[j],
j: j
});
j++
}
}
return grid;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment