Commit 88609fbe by Zachary Tong

Cleaning up misconceptions with d3

parent d3debd1f
function displayBinning(scope, dimensions, projection, path) { function displayBinning(scope, dimensions, projection, path) {
/** /**
* Hexbin-specific setup * Hexbin-specific setup
*/ */
...@@ -9,40 +10,51 @@ function displayBinning(scope, dimensions, projection, path) { ...@@ -9,40 +10,51 @@ function displayBinning(scope, dimensions, projection, path) {
.radius(scope.panel.display.binning.hexagonSize); .radius(scope.panel.display.binning.hexagonSize);
var binPoints = []; var binPoints = [],
binnedPoints = [],
binRange = 0;
//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;
_.map(scope.data, function (k, v) { if (scope.panel.display.binning.enabled) {
var decoded = geohash.decode(v); //primary field is just binning raw counts
return _.map(_.range(0, k*scale), function(a,b) { //secondary field is binning some metric like mean/median/total. Hexbins doesn't support that,
binPoints.push(projection([decoded.longitude, decoded.latitude])); //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;
} else { _.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;
}
binPoints = scope.projectedPoints; //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;
} }
//bin and sort the points, so we can set the various ranges appropriately
var binnedPoints = hexbin(binPoints).sort(function(a, b) { return b.length - a.length; });;
//clean up some memory
binPoints = [];
var radius = d3.scale.sqrt() var radius = d3.scale.sqrt()
.domain([0, binnedPoints[0].length]) .domain([0, binRange])
.range([0, scope.panel.display.binning.hexagonSize]); .range([0, scope.panel.display.binning.hexagonSize]);
var color = d3.scale.linear() var color = d3.scale.linear()
.domain([0,binnedPoints[0].length]) .domain([0,binRange])
.range(["white", "steelblue"]) .range(["white", "steelblue"])
.interpolate(d3.interpolateLab); .interpolate(d3.interpolateLab);
...@@ -51,10 +63,10 @@ function displayBinning(scope, dimensions, projection, path) { ...@@ -51,10 +63,10 @@ function displayBinning(scope, dimensions, projection, path) {
* D3 Drawing * D3 Drawing
*/ */
var hex = scope.g.selectAll(".hexagon")
.data(binnedPoints);
scope.g.selectAll("hexagon") hex.enter().append("path")
.data(binnedPoints)
.enter().append("path")
.attr("d", function (d) { .attr("d", function (d) {
if (scope.panel.display.binning.areaEncoding === false) { if (scope.panel.display.binning.areaEncoding === false) {
return hexbin.hexagon(); return hexbin.hexagon();
...@@ -74,4 +86,6 @@ function displayBinning(scope, dimensions, projection, path) { ...@@ -74,4 +86,6 @@ function displayBinning(scope, dimensions, projection, path) {
} }
}) })
.attr("opacity", scope.panel.display.binning.hexagonAlpha); .attr("opacity", scope.panel.display.binning.hexagonAlpha);
}
\ No newline at end of file hex.exit().remove();
}
...@@ -5,30 +5,27 @@ function displayBullseye(scope, projection, path) { ...@@ -5,30 +5,27 @@ function displayBullseye(scope, projection, path) {
var circle = d3.geo.circle(); var circle = d3.geo.circle();
var data = [ var data = [];
{lat: parseFloat(scope.panel.display.bullseye.coord.lat), lon: parseFloat(scope.panel.display.bullseye.coord.lon)}
];
scope.g.selectAll("arc") if (scope.panel.display.bullseye.enabled) {
.data(data) data = [
.enter().append("path") {lat: parseFloat(scope.panel.display.bullseye.coord.lat), lon: parseFloat(scope.panel.display.bullseye.coord.lon)}
];
}
var arcs = scope.g.selectAll(".arc")
.data(data);
arcs.enter().append("path")
.datum(function(d) { .datum(function(d) {
return circle.origin([d.lon, d.lat]).angle(1000 / 6371 * degrees)(); return circle.origin([d.lon, d.lat]).angle(1000 / 6371 * degrees)();
}) })
.attr("d", path) .attr("d", path)
.attr("class", "arc"); .attr("class", "arc");
arcs.exit().remove();
/*
scope.g.append("path")
.attr("d", arc)
.attr("transform", "translate(" + coords[0] + "," + coords[1] + ")");
scope.g
.append("circle")
.attr("r", 1)
.attr("opacity", 1)
.attr("transform", "translate(" + coords[0] + "," + coords[1] + ")");
*/
} }
\ No newline at end of file
function displayGeopoints(scope, path) { function displayGeopoints(scope, path) {
/* /*
scope.g.selectAll("circles.points") var points = {};
.data(points) var circle = d3.geo.circle();
.enter() var degrees = 180 / Math.PI;
.append("circle")
.attr("r", scope.panel.display.geopoints.pointSize)
.attr("opacity", scope.panel.display.geopoints.pointAlpha)
.attr("transform", function (d) {
return "translate(" + d[0] + "," + d[1] + ")";
});
*/ if (scope.panel.display.geopoints.enabled) {
//points = scope.points;
var features = _.map(scope.points, function(coords) {
return {
feature: circle.origin(scope.projection([coords[0], coords[1]]))
.angle(scope.panel.display.geopoints.pointSize / 6371 * degrees)()
};
});
console.log("features", features);
points = {
type: "FeatureCollection",
features: features
};
console.log("points", points);
}
console.log("points2", points);
scope.svg.append("path")
.datum(points)
.attr("d", d3.geo.path());
*/
var points = [] var points = []
if (scope.panel.display.bullseye.enabled) { if (scope.panel.display.geopoints.enabled) {
points = scope.points; points = scope.points;
} }
var circle = d3.geo.circle(); var circle = d3.geo.circle();
var degrees = 180 / Math.PI var degrees = 180 / Math.PI
var geopoints = scope.g.selectAll("geopoints") var geopoints = scope.g.selectAll(".geopoint")
.data(points); .data(points);
geopoints.enter().append("path") geopoints.enter().append("path")
......
...@@ -122,6 +122,7 @@ angular.module('kibana.map2', []) ...@@ -122,6 +122,7 @@ angular.module('kibana.map2', [])
_.each(results.facets.map.terms, function (v) { _.each(results.facets.map.terms, function (v) {
var metric = 'count'; var metric = 'count';
//If it is a Term facet, use count, otherwise use Total //If it is a Term facet, use count, otherwise use Total
...@@ -190,7 +191,7 @@ angular.module('kibana.map2', []) ...@@ -190,7 +191,7 @@ angular.module('kibana.map2', [])
//elem.html('') //elem.html('')
scope.initializing = false;
scope.worldData = null; scope.worldData = null;
scope.worldNames = null; scope.worldNames = null;
...@@ -228,39 +229,38 @@ angular.module('kibana.map2', []) ...@@ -228,39 +229,38 @@ angular.module('kibana.map2', [])
scope.init_or_render = function() {
// Receive render events
scope.$on('render', function () {
console.log("$on render");
if (typeof scope.svg === 'undefined') { if (typeof scope.svg === 'undefined') {
console.log("init"); console.log("init");
init_panel();
//prevent duplicate initialization steps, if render is called again
//before the svg is setup
if (!scope.initializing) {
init_panel();
}
} else { } else {
console.log("render"); console.log("render");
render_panel(); render_panel();
} }
};
// Receive render events
scope.$on('render', function () {
console.log("$on render");
scope.init_or_render();
}); });
// Or if the window is resized // Or if the window is resized
angular.element(window).bind('resize', function () { angular.element(window).bind('resize', function () {
console.log("resize render"); console.log("resize render");
scope.init_or_render();
if (typeof scope.svg === 'undefined') {
console.log("init");
init_panel();
} else {
console.log("render");
render_panel();
}
}); });
function init_panel() { function init_panel() {
scope.initializing = true;
// Using LABjs, wait until all scripts are loaded before rendering panel // Using LABjs, wait until all scripts are loaded before rendering panel
var scripts = $LAB.script("panels/map2/lib/d3.v3.min.js?rand="+Math.floor(Math.random()*10000)) var scripts = $LAB.script("panels/map2/lib/d3.v3.min.js?rand="+Math.floor(Math.random()*10000))
.script("panels/map2/lib/topojson.v1.min.js?rand="+Math.floor(Math.random()*10000)) .script("panels/map2/lib/topojson.v1.min.js?rand="+Math.floor(Math.random()*10000))
...@@ -334,16 +334,11 @@ angular.module('kibana.map2', []) ...@@ -334,16 +334,11 @@ angular.module('kibana.map2', [])
scope.g = scope.svg.append("g"); scope.g = scope.svg.append("g");
//Overlay is used so that the entire map is draggable, not just the locations
//where countries are
scope.svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
console.log("finished initing"); console.log("finished initing");
scope.initializing = false;
render_panel(); render_panel();
}); });
...@@ -399,8 +394,8 @@ angular.module('kibana.map2', []) ...@@ -399,8 +394,8 @@ angular.module('kibana.map2', [])
var decoded = geohash.decode(v); var decoded = geohash.decode(v);
return [decoded.longitude, decoded.latitude]; return [decoded.longitude, decoded.latitude];
}); });
scope.projectedPoints = _.map(scope.points, function (k, v) { scope.projectedPoints = _.map(scope.points, function (coords) {
return scope.projection(v); return scope.projection(coords);
}); });
...@@ -410,14 +405,29 @@ angular.module('kibana.map2', []) ...@@ -410,14 +405,29 @@ angular.module('kibana.map2', [])
//set up listener for ctrl key //set up listener for ctrl key
//scope.svg //scope.svg
//Overlay is used so that the entire map is draggable, not just the locations
//where countries are
scope.svg.select(".overlay").remove();
scope.svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Draw the countries, if this is a choropleth, draw with fancy colors //Draw the countries, if this is a choropleth, draw with fancy colors
scope.g.selectAll("countries") var countryPath = scope.g.selectAll(".land")
.data(scope.countries) .data(scope.countries);
.enter().append("path")
countryPath.enter().append("path")
.attr("class", function(d) { .attr("class", function(d) {
if (scope.panel.display.choropleth.enabled) { if (scope.panel.display.choropleth.enabled) {
return 'land ' + scope.quantize(scope.data[d.short]); return 'land ' + scope.quantize(scope.data[d.short]);
...@@ -427,11 +437,16 @@ angular.module('kibana.map2', []) ...@@ -427,11 +437,16 @@ angular.module('kibana.map2', [])
}) })
.attr("d", path); .attr("d", path);
countryPath.exit().remove();
/*
//draw boundaries //draw boundaries
scope.g.selectAll("land").append("path") scope.g.selectAll("land").append("path")
.datum(topojson.mesh(scope.worldData, scope.worldData.objects.land, function(a, b) { return a !== b; })) .datum(topojson.mesh(scope.worldData, scope.worldData.objects.land, function(a, b) { return a !== b; }))
.attr("class", "land boundary") .attr("class", "land boundary")
.attr("d", path); .attr("d", path);
*/
...@@ -465,20 +480,13 @@ angular.module('kibana.map2', []) ...@@ -465,20 +480,13 @@ angular.module('kibana.map2', [])
*/ */
//Hexagonal Binning //Hexagonal Binning
if (scope.panel.display.binning.enabled) {
//@todo fix this
var dimensions = [width, height];
displayBinning(scope, dimensions, scope.projection, path);
}
//Raw geopoints //@todo fix this
//if (scope.panel.display.geopoints.enabled) { var dimensions = [width, height];
displayGeopoints(scope, path); displayBinning(scope, dimensions, scope.projection, path);
//} displayGeopoints(scope, path);
displayBullseye(scope, scope.projection, path);
//if (scope.panel.display.bullseye.enabled) {
displayBullseye(scope, scope.projection, path);
//}
//d3.select(elem[0]).select(".loading").remove(); //d3.select(elem[0]).select(".loading").remove();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment