2013-04-08 15:22:42 -04:00
|
|
|
|
2013-04-09 17:18:44 -04:00
|
|
|
function displayBinning(scope, dimensions, projection, path) {
|
|
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
|
2013-04-08 15:22:42 -04:00
|
|
|
/**
|
|
|
|
|
* Hexbin-specific setup
|
|
|
|
|
*/
|
|
|
|
|
var hexbin = d3.hexbin()
|
2013-04-08 16:54:57 -04:00
|
|
|
.size(dimensions)
|
2013-04-08 15:22:42 -04:00
|
|
|
.radius(scope.panel.display.binning.hexagonSize);
|
|
|
|
|
|
|
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
var binPoints = [],
|
|
|
|
|
binnedPoints = [],
|
|
|
|
|
binRange = 0;
|
2013-04-08 15:22:42 -04:00
|
|
|
|
|
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
if (scope.panel.display.binning.enabled) {
|
|
|
|
|
//primary field is just binning raw counts
|
|
|
|
|
//secondary field is binning some metric like mean/median/total. Hexbins doesn't support that,
|
|
|
|
|
//so we cheat a little and just add more points to compensate.
|
|
|
|
|
//However, we don't want to add a million points, so normalize against the largest value
|
|
|
|
|
if (scope.panel.display.binning.areaEncodingField === 'secondary') {
|
|
|
|
|
var max = Math.max.apply(Math, _.map(scope.data, function(k,v){return k;})),
|
|
|
|
|
scale = 50/max;
|
2013-04-08 15:22:42 -04:00
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
_.map(scope.data, function (k, v) {
|
|
|
|
|
var decoded = geohash.decode(v);
|
|
|
|
|
return _.map(_.range(0, k*scale), function(a,b) {
|
|
|
|
|
binPoints.push(projection([decoded.longitude, decoded.latitude]));
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
binPoints = scope.projectedPoints;
|
|
|
|
|
}
|
2013-04-09 17:18:44 -04:00
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
//bin and sort the points, so we can set the various ranges appropriately
|
|
|
|
|
binnedPoints = hexbin(binPoints).sort(function(a, b) { return b.length - a.length; });
|
|
|
|
|
binRange = binnedPoints[0].length;
|
|
|
|
|
|
|
|
|
|
//clean up some memory
|
|
|
|
|
binPoints = [];
|
|
|
|
|
} else {
|
|
|
|
|
binnedPoints = [];
|
|
|
|
|
binRange = 0;
|
2013-04-08 15:22:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var radius = d3.scale.sqrt()
|
2013-04-10 15:05:31 -04:00
|
|
|
.domain([0, binRange])
|
2013-04-08 15:22:42 -04:00
|
|
|
.range([0, scope.panel.display.binning.hexagonSize]);
|
|
|
|
|
|
|
|
|
|
var color = d3.scale.linear()
|
2013-04-10 15:05:31 -04:00
|
|
|
.domain([0,binRange])
|
2013-04-08 15:22:42 -04:00
|
|
|
.range(["white", "steelblue"])
|
|
|
|
|
.interpolate(d3.interpolateLab);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* D3 Drawing
|
|
|
|
|
*/
|
|
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
var hex = scope.g.selectAll(".hexagon")
|
|
|
|
|
.data(binnedPoints);
|
2013-04-08 15:22:42 -04:00
|
|
|
|
2013-04-10 15:05:31 -04:00
|
|
|
hex.enter().append("path")
|
2013-04-08 15:22:42 -04:00
|
|
|
.attr("d", function (d) {
|
|
|
|
|
if (scope.panel.display.binning.areaEncoding === false) {
|
|
|
|
|
return hexbin.hexagon();
|
|
|
|
|
} else {
|
|
|
|
|
return hexbin.hexagon(radius(d.length));
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.attr("class", "hexagon")
|
|
|
|
|
.attr("transform", function (d) {
|
|
|
|
|
return "translate(" + d.x + "," + d.y + ")";
|
|
|
|
|
})
|
|
|
|
|
.style("fill", function (d) {
|
|
|
|
|
if (scope.panel.display.binning.colorEncoding === false) {
|
|
|
|
|
return color(binnedPoints[0].length / 2);
|
|
|
|
|
} else {
|
|
|
|
|
return color(d.length);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.attr("opacity", scope.panel.display.binning.hexagonAlpha);
|
2013-04-10 15:05:31 -04:00
|
|
|
|
|
|
|
|
hex.exit().remove();
|
|
|
|
|
}
|