Skip to content

Instantly share code, notes, and snippets.

@vasturiano
Last active July 19, 2018 00:23
Show Gist options
  • Save vasturiano/aee11f57aaa6b1ec96f1df386166a396 to your computer and use it in GitHub Desktop.
Save vasturiano/aee11f57aaa6b1ec96f1df386166a396 to your computer and use it in GitHub Desktop.
Hilbert Curve
license: mit

A simple representation of the Hilbert curve, using d3-hilbert layout. Use the slider to modify the curve order (number of iterations). On mouse hover, XY coordinates are reversely converted to curve distance. Zoom/pan the canvas using mouse-wheel/drag events.

See also Morton (Z-order) curve.

function hilbertDemo() {
var svg = d3.select('svg#hilbert-chart'),
canvasWidth = Math.min(window.innerWidth, window.innerHeight - 100),
hilbert,
order = 3;
function d3Digest() {
var hilbertData = {
start: 0,
length: Math.pow(4, order)
};
hilbert.order(order).layout(hilbertData);
svg.selectAll('path')
.datum(hilbertData)
.attr('d', function(d) { return getHilbertPath(d.pathVertices); })
.attr('transform', function(d) {
return 'scale('+ d.cellWidth + ') '
+ 'translate(' + (d.startCell[0] +.5) + ',' + (d.startCell[1] +.5) + ')';
});
svg.select('path:not(.skeleton)')
.transition().duration(order * 1000).ease(d3.easePoly)
.attrTween('stroke-dasharray', tweenDash);
function getHilbertPath(vertices) {
var path = 'M0 0L0 0';
vertices.forEach(function(vert) {
switch(vert) {
case 'U': path += 'v-1'; break;
case 'D': path += 'v1'; break;
case 'L': path += 'h-1'; break;
case 'R': path += 'h1'; break;
}
});
return path;
}
function tweenDash() {
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) { return i(t); };
}
}
function orderChange(newOrder) {
order = newOrder;
d3Digest();
}
function init() {
hilbert = d3.hilbert()
.order(order)
.canvasWidth(canvasWidth)
.simplifyCurves(false);
svg.attr("width", canvasWidth).attr("height", canvasWidth);
var canvas = svg.append('g');
canvas.append('path').attr('class', 'skeleton');
canvas.append('path');
// Canvas zoom/pan
svg.call(d3.zoom()
.translateExtent([[0, 0], [canvasWidth, canvasWidth]])
.scaleExtent([1, Infinity])
.on("zoom", function() {
canvas.attr("transform", d3.event.transform);
})
);
// Value Tooltip
var valTooltip = d3.select('#val-tooltip');
svg.on('mouseover', function() { valTooltip.style("display", "inline"); })
.on('mouseout', function() { valTooltip.style("display", "none"); })
.on('mousemove', function () {
var coords = d3.mouse(canvas.node());
valTooltip.text(hilbert.getValAtXY(coords[0], coords[1]))
.style('left', d3.event.pageX)
.style('top', d3.event.pageY);
});
// Order slider
$('input#hilbert-order').slider({
step: 1,
max: 9,
min: 0,
value: order,
tooltip: 'always',
tooltip_position: 'bottom',
formatter: function(d) {
return 'Order: ' + d;
}
}).on('change', function(e) {
orderChange(e.value.newValue);
});
d3Digest();
}
init();
}
<head>
<script src="//code.jquery.com/jquery-3.1.0.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.2.6/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.1.3/bootstrap-slider.min.js"></script>
<script src="//unpkg.com/d3-hilbert"></script>
<script src="hilbert-demo.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.1.3/css/bootstrap-slider.min.css">
<style>
body {
text-align: center;
}
svg {
margin: 10px;
}
svg path {
fill: none;
stroke: #3A5894;
stroke-width: 0.3;
stroke-linecap: square;
}
svg path.skeleton {
stroke: #EEE;
stroke-width: 0.1;
}
#val-tooltip {
display: none;
position: absolute;
margin-top: 22px;
margin-left: -1px;
padding: 5px;
border-radius: 3px;
font: 11px sans-serif;
color: #eee;
background: rgba(0,0,140,0.9);
text-align: center;
pointer-events: none;
}
</style>
</head>
<body>
<svg id="hilbert-chart"></svg>
<div id="hilbert-controls">
<input id="hilbert-order"/>
</div>
<div id="val-tooltip"></div>
<script>
hilbertDemo();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment