Commit 9cf6a524 by Rashid Khan

removed map2panel

parent 569df6c8
/**
* Hexagonal binning
* Rendered as normally projected svg paths, which mean they *do not*
* clip on spheres appropriately. To fix this, we would need to translate
* the svg path into a geo-path
*/
function displayBinning(scope, dr, dimensions) {
var hexbin = d3.hexbin()
.size(dimensions)
.radius(scope.panel.display.binning.hexagonSize);
var binPoints = [],
binnedPoints = [],
binRange = 0;
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;
_.map(scope.data, function (k, v) {
var decoded = geohash.decode(v);
return _.map(_.range(0, k*scale), function(a,b) {
binPoints.push(dr.projection([decoded.longitude, decoded.latitude]));
})
});
} else {
binPoints = dr.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 {
//not enabled, so just set an empty array. D3.exit will take care of the rest
binnedPoints = [];
binRange = 0;
}
var radius = d3.scale.sqrt()
.domain([0, binRange])
.range([0, scope.panel.display.binning.hexagonSize]);
var color = d3.scale.linear()
.domain([0,binRange])
.range(["white", "steelblue"])
.interpolate(d3.interpolateLab);
var hex = dr.g.selectAll(".hexagon")
.data(binnedPoints);
hex.enter().append("path")
.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);
hex.exit().remove();
}
/**
* Renders bullseyes as geo-json poly gon entities
* Allows for them to clip on spheres correctly
*/
function displayBullseye(scope, dr) {
var degrees = 180 / Math.PI
var circle = d3.geo.circle();
var data = [];
if (scope.panel.display.bullseye.enabled) {
data = [
circle.origin(parseFloat(scope.panel.display.bullseye.coord.lat), parseFloat(scope.panel.display.bullseye.coord.lon)).angle(1000 / 6371 * degrees)()
];
}
var arcs = dr.g.selectAll(".arc")
.data(data);
arcs.enter().append("path")
.attr("d", dr.path)
.attr("class", "arc");
arcs.exit().remove();
}
\ No newline at end of file
/**
* Renders geopoints as geo-json poly gon entities
* Allows for them to clip on spheres correctly
*/
function displayGeopoints(scope, dr) {
var points = [];
var circle = d3.geo.circle();
var degrees = 180 / Math.PI
if (scope.panel.display.geopoints.enabled) {
//points = dr.points;
points = _.map(dr.points, function(v) {
return {
type: "Point",
coordinates: [v[0], v[1]]
};
});
}
dr.geopoints = dr.g.selectAll("path.geopoint")
.data(points);
dr.geopoints.enter().append("path")
/*
.datum(function(d) {
return circle.origin([d[0], d[1]]).angle(scope.panel.display.geopoints.pointSize / 6371 * degrees)();
})
*/
.attr("class", "geopoint")
.attr("d", dr.path);
dr.geopoints.exit().remove();
}
\ No newline at end of file
<style>
.tabDetails {
border-bottom: 1px solid #ddd;
padding-bottom:20px;
}
.tabDetails td {
padding-right: 10px;
padding-bottom:10px;
}
</style>
<div ng-controller="map2">
<div class="row-fluid" style="margin-bottom:20px">
<div class="span11">
The map panel is compatible with either Geopoints or two-letter country codes, depending on the graphing options. Left click to drag/pan map, scroll wheel (or double click) to zoom. Globes can be spun using ctrl-key + drag.
</div>
</div>
<div class="row-fluid">
<div class="span10">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="panelfield">Primary Field</label>
<div class="controls">
<input type="text" id="panelfield" class="input"
ng-model="panel.field"
ng-change="get_data()" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="panelsecondaryfield">Secondary Field</label>
<div class="controls">
<input type="text" id="panelsecondaryfield" class="input"
ng-model="panel.secondaryfield"
ng-change="get_data()"
data-placement="right"
placeholder="Optional"
bs-tooltip="'Allows aggregating on Primary field, while counting stats on a secondary (e.g. Group By user_id, Sum(purchase_price)).'" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="panelquery">Query</label>
<div class="controls">
<input type="text" id="panelquery" class="input" ng-model="panel.query">
</div>
</div>
</form>
</div>
</div>
<div class="row-fluid">
<div class="span11">
<h4>Display Options</h4>
</div>
<!--
Rolling our own tab control here because the Angular-Strap Tab directive doesn't allow
updates to components inside, which is quite bizarre. Or I just can't figure it out...
-->
<div class="span11">
<ul class="nav nav-tabs" ng-cloak="">
<li ng-repeat="tab in ['Geopoints', 'Binning', 'Choropleth', 'Bullseye', 'Data']" ng-class="{active:isActive(tab)}">
<a ng-click="tabClick(tab)">{{tab}}</a>
</li>
</ul>
</div>
</div>
<div class="row-fluid tabDetails" ng-show="isActive('geopoints')">
<div class="span8 offset1">
<table>
<tbody >
<tr>
<td>Geopoints</td>
<td>
<button type="button" class="btn" bs-button
data-placement="right"
bs-tooltip="'Compatible with Geopoint Type'"
ng-change="$emit('render')"
ng-class="{'btn-success': panel.display.geopoints.enabled}"
ng-model="panel.display.geopoints.enabled">{{panel.display.geopoints.enabled|enabledText}}</button>
</td>
</tr>
<tr>
<td>Point size</td>
<td>
<input type="text" style="width:100px"
ng-change="$emit('render')"
data-placement="right"
bs-tooltip="'Controls the size of the geopoints on the map.'"
ng-model="panel.display.geopoints.pointSize"
value="{{panel.display.geopoints.pointSize}}" />
</td>
</tr>
<tr>
<td>Point Transparency</td>
<td>
<input type="text" style="width:100px"
ng-change="$emit('render')"
data-placement="right"
bs-tooltip="'Controls the transparency of geopoints. Valid numbers are between 0.0 and 1.0'"
ng-model="panel.display.geopoints.pointAlpha"
value="{{panel.display.geopoints.pointAlpha}}" />
</td>
</tr>
<tr>
<td>Autosizing</td>
<td>
<input type="checkbox"
ng-change="$emit('render')"
data-placement="right"
ng-model="panel.display.geopoints.autosize"
bs-tooltip="'Allows point sizes to scale as you zoom in and out of the map.'" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row-fluid tabDetails" ng-show="isActive('binning')">
<div class="span8 offset1">
<table>
<tbody >
<tr>
<td>Binning</td>
<td>
<button type="button" class="btn" bs-button
data-placement="right"
bs-tooltip="'Compatible with Geopoint Type'"
ng-change="$emit('render')"
ng-class="{'btn-success': panel.display.binning.enabled}"
ng-model="panel.display.binning.enabled">{{panel.display.binning.enabled|enabledText}}</button>
</td>
</tr>
<tr>
<td>Hexagon size</td>
<td>
<input type="text" style="width:100px"
ng-change="$emit('render')"
data-placement="right"
bs-tooltip="'Controls the size of the hexagonal binning'"
ng-model="panel.display.binning.hexagonSize"
value="{{panel.display.binning.hexagonSize}}" />
</td>
</tr>
<tr>
<td>Hexagon Transparency</td>
<td>
<input type="text" style="width:100px"
ng-change="$emit('render')"
data-placement="right"
bs-tooltip="'Controls the transparency of hexagonal bins. Valid numbers are between 0.0 and 1.0'"
ng-model="panel.display.binning.hexagonAlpha"
value="{{panel.display.binning.hexagonAlpha}}" />
</td>
</tr>
<tr>
<td>
<button type="button" class="btn" bs-button
ng-change="$emit('render')"
ng-class="{'btn-success': panel.display.binning.areaEncoding}"
ng-model="panel.display.binning.areaEncoding">Area</button>
</td>
<td>
<div class="btn-group" ng-model="panel.display.binning.areaEncodingField" bs-buttons-radio ng-change="$emit('render')">
<button type="button" class="btn" value="primary">Primary Field</button>
<button type="button" class="btn" value="secondary">Secondary Field</button>
</div>
</td>
</tr>
<tr>
<td>
<button type="button" class="btn" bs-button
ng-change="$emit('render')"
ng-class="{'btn-success': panel.display.binning.colorEncoding}"
ng-model="panel.display.binning.colorEncoding">Color</button>
</td>
<td>
<div class="btn-group" ng-model="panel.display.binning.colorEncodingField" bs-buttons-radio ng-change="$emit('render')">
<button type="button" class="btn" value="primary">Primary Field</button>
<button type="button" class="btn" value="secondary">Secondary Field</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row-fluid tabDetails" ng-show="isActive('choropleth')">
<div class="span8 offset1">
<table>
<tbody >
<tr>
<td>Choropleth</td>
<td>
<button type="button" class="btn" bs-button
data-placement="right"
bs-tooltip="'Choropleths color country regions according to your selected field. Compatible with Country-Coded fields'"
ng-change="$emit('render')"
ng-class="{'btn-success': panel.display.choropleth.enabled}"
ng-model="panel.display.choropleth.enabled">{{panel.display.choropleth.enabled|enabledText}}</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row-fluid tabDetails" ng-show="isActive('bullseye')">
<div class="span8 offset1">
<table>
<tbody >
<tr>
<td>Bullseye</td>
<td>
<button type="button" class="btn" bs-button
ng-change="$emit('render')"
ng-class="{'btn-success': panel.display.bullseye.enabled}"
ng-model="panel.display.bullseye.enabled">{{panel.display.bullseye.enabled|enabledText}}</button>
</td>
</tr>
<tr>
<td>Bullseye Coordinates</td>
<td>
<input type="text" style="width:100px"
ng-change="$emit('render')"
placeholder="Latitude"
data-placement="right"
bs-tooltip="'Latitude of Bullseye'"
ng-model="panel.display.bullseye.coord.lat"
value="{{panel.display.bullseye.coord.lat}}" />
<input type="text" style="width:100px"
placeholder="Longitude"
ng-change="$emit('render')"
data-placement="right"
bs-tooltip="'Longitude of Bullseye'"
ng-model="panel.display.bullseye.coord.lon"
value="{{panel.display.bullseye.coord.lon}}" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row-fluid tabDetails" ng-show="isActive('data')">
<div class="span8 offset1">
<table>
<tbody >
<tr>
<td>Data Points</td>
<td>
<input type="text" style="width:100px"
ng-change="get_data()"
data-placement="right"
bs-tooltip="'Controls the number of samples used in the map. Be careful with this value!'"
ng-model="panel.display.data.samples"
value="{{panel.display.data.samples}}" />
</td>
</tr>
<tr>
<td>Map Projection</td>
<td>
<select ng-model="panel.display.data.type" ng-options="option.id as option.text for option in panel.display.data.dropdown"></select>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h5>Panel Spy</h5>
<div class="row-fluid">
<div class="span2">
<label class="small">Spyable</label> <input type="checkbox" ng-model=
"panel.spyable" ng-checked="panel.spyable">
</div>
<div class="span9 small">
The panel spy shows 'behind the scenes' information about a panel. It can be
accessed by clicking the in the top right of the panel.
</div>
</div>
</div>
\ No newline at end of file
(function(){d3.hexbin=function(){function u(n){var r={};return n.forEach(function(n,t){var a=s.call(u,n,t)/o,e=Math.round(a),h=f.call(u,n,t)/i-(1&e?.5:0),c=Math.round(h),l=a-e;if(3*Math.abs(l)>1){var g=h-c,v=c+(c>h?-1:1)/2,M=e+(e>a?-1:1),m=h-v,d=a-M;g*g+l*l>m*m+d*d&&(c=v+(1&e?1:-1)/2,e=M)}var x=c+"-"+e,j=r[x];j?j.push(n):(j=r[x]=[n],j.x=(c+(1&e?.5:0))*i,j.y=e*o)}),d3.values(r)}function a(r){var t=0,u=0;return n.map(function(n){var a=Math.sin(n)*r,e=-Math.cos(n)*r,i=a-t,o=e-u;return t=a,u=e,[i,o]})}var e,i,o,h=1,c=1,f=r,s=t;return u.x=function(n){return arguments.length?(f=n,u):f},u.y=function(n){return arguments.length?(s=n,u):s},u.hexagon=function(n){return 1>arguments.length&&(n=e),"m"+a(n).join("l")+"z"},u.mesh=function(){for(var n=[],r=a(e).slice(0,4).join("l"),t=0,u=!1;c+e>t;t+=o,u=!u)for(var f=u?i/2:0;h>f;f+=i)n.push("M",f,",",t,"m",r);return n.join("")},u.size=function(n){return arguments.length?(h=+n[0],c=+n[1],u):[h,c]},u.radius=function(n){return arguments.length?(e=+n,i=2*e*Math.sin(Math.PI/3),o=1.5*e,u):e},u.radius(1)};var n=d3.range(0,2*Math.PI,Math.PI/3),r=function(n){return n[0]},t=function(n){return n[1]}})();
\ No newline at end of file
/**
* Copyright (c) 2011, Sun Ning.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
var BASE32_CODES = "0123456789bcdefghjkmnpqrstuvwxyz";
var BASE32_CODES_DICT = {};
for(var i=0; i<BASE32_CODES.length; i++) {
BASE32_CODES_DICT[BASE32_CODES.charAt(i)]=i;
}
var encode = function(latitude, longitude, numberOfChars){
numberOfChars = numberOfChars || 9;
var chars = [], bits = 0;
var hash_value = 0;
var maxlat = 90, minlat = -90;
var maxlon = 180, minlon = -180;
var mid;
var islon = true;
while(chars.length < numberOfChars) {
if (islon){
mid = (maxlon+minlon)/2;
if(longitude > mid){
hash_value = (hash_value << 1) + 1;
minlon=mid;
} else {
hash_value = (hash_value << 1) + 0;
maxlon=mid;
}
} else {
mid = (maxlat+minlat)/2;
if(latitude > mid ){
hash_value = (hash_value << 1) + 1;
minlat = mid;
} else {
hash_value = (hash_value << 1) + 0;
maxlat = mid;
}
}
islon = !islon;
bits++;
if (bits == 5) {
var code = BASE32_CODES[hash_value];
chars.push(code);
bits = 0;
hash_value = 0;
}
}
return chars.join('')
};
var decode_bbox = function(hash_string){
var islon = true;
var maxlat = 90, minlat = -90;
var maxlon = 180, minlon = -180;
var hash_value = 0;
for(var i=0,l=hash_string.length; i<l; i++) {
var code = hash_string[i].toLowerCase();
hash_value = BASE32_CODES_DICT[code];
for (var bits=4; bits>=0; bits--) {
var bit = (hash_value >> bits) & 1;
if (islon){
var mid = (maxlon+minlon)/2;
if(bit == 1){
minlon = mid;
} else {
maxlon = mid;
}
} else {
var mid = (maxlat+minlat)/2;
if(bit == 1){
minlat = mid;
} else {
maxlat = mid;
}
}
islon = !islon;
}
}
return [minlat, minlon, maxlat, maxlon];
}
var decode = function(hash_string){
var bbox = decode_bbox(hash_string);
var lat = (bbox[0]+bbox[2])/2;
var lon = (bbox[1]+bbox[3])/2;
var laterr = bbox[2]-lat;
var lonerr = bbox[3]-lon;
return {latitude:lat, longitude:lon,
error:{latitude:laterr, longitude:lonerr}};
};
/**
* direction [lat, lon], i.e.
* [1,0] - north
* [1,1] - northeast
* ...
*/
var neighbor = function(hashstring, direction) {
var lonlat = decode(hashstring);
var neighbor_lat = lonlat.latitude
+ direction[0] * lonlat.error.latitude * 2;
var neighbor_lon = lonlat.longitude
+ direction[1] * lonlat.error.longitude * 2;
return encode(neighbor_lat, neighbor_lon, hashstring.length);
}
var geohash = {
'encode': encode,
'decode': decode,
'decode_bbox': decode_bbox,
'neighbor': neighbor,
}
module.exports = geohash;
(function(){function n(n){function t(){for(;f=a<c.length&&n>p;){var u=a++,t=c[u],r=l.call(t,1);r.push(e(u)),++p,t[0].apply(null,r)}}function e(n){return function(u,l){--p,null==d&&(null!=u?(d=u,a=s=0/0,r()):(c[n]=l,--s?f||t():r()))}}function r(){null!=d?v(d):i?v(d,c):v.apply(null,[d].concat(c))}var o,f,i,c=[],a=0,p=0,s=0,d=null,v=u;return n||(n=1/0),o={defer:function(){return d||(c.push(arguments),++s,t()),o},await:function(n){return v=n,i=!1,s||r(),o},awaitAll:function(n){return v=n,i=!0,s||r(),o}}}function u(){}"undefined"==typeof module?self.queue=n:module.exports=n,n.version="1.0.4";var l=[].slice})();
\ No newline at end of file
topojson=function(){function t(t,e){function n(e){var n=t.arcs[e],r=n[0],o=[0,0];return n.forEach(function(t){o[0]+=t[0],o[1]+=t[1]}),[r,o]}var r={},o={},a={};e.forEach(function(t){var e=n(t);(r[e[0]]||(r[e[0]]=[])).push(t),(r[e[1]]||(r[e[1]]=[])).push(~t)}),e.forEach(function(t){var e,r,i=n(t),u=i[0],c=i[1];if(e=a[u])if(delete a[e.end],e.push(t),e.end=c,r=o[c]){delete o[r.start];var s=r===e?e:e.concat(r);o[s.start=e.start]=a[s.end=r.end]=s}else if(r=a[c]){delete o[r.start],delete a[r.end];var s=e.concat(r.map(function(t){return~t}).reverse());o[s.start=e.start]=a[s.end=r.start]=s}else o[e.start]=a[e.end]=e;else if(e=o[c])if(delete o[e.start],e.unshift(t),e.start=u,r=a[u]){delete a[r.end];var f=r===e?e:r.concat(e);o[f.start=r.start]=a[f.end=e.end]=f}else if(r=o[u]){delete o[r.start],delete a[r.end];var f=r.map(function(t){return~t}).reverse().concat(e);o[f.start=r.end]=a[f.end=e.end]=f}else o[e.start]=a[e.end]=e;else if(e=o[u])if(delete o[e.start],e.unshift(~t),e.start=c,r=a[c]){delete a[r.end];var f=r===e?e:r.concat(e);o[f.start=r.start]=a[f.end=e.end]=f}else if(r=o[c]){delete o[r.start],delete a[r.end];var f=r.map(function(t){return~t}).reverse().concat(e);o[f.start=r.end]=a[f.end=e.end]=f}else o[e.start]=a[e.end]=e;else if(e=a[c])if(delete a[e.end],e.push(~t),e.end=u,r=a[u]){delete o[r.start];var s=r===e?e:e.concat(r);o[s.start=e.start]=a[s.end=r.end]=s}else if(r=o[u]){delete o[r.start],delete a[r.end];var s=e.concat(r.map(function(t){return~t}).reverse());o[s.start=e.start]=a[s.end=r.start]=s}else o[e.start]=a[e.end]=e;else e=[t],o[e.start=u]=a[e.end=c]=e});var i=[];for(var u in a)i.push(a[u]);return i}function e(e,n,r){function a(t){0>t&&(t=~t),(l[t]||(l[t]=[])).push(f)}function i(t){t.forEach(a)}function u(t){t.forEach(i)}function c(t){t.type==="GeometryCollection"?t.geometries.forEach(c):t.type in d&&(f=t,d[t.type](t.arcs))}var s=[];if(arguments.length>1){var f,l=[],d={LineString:i,MultiLineString:u,Polygon:u,MultiPolygon:function(t){t.forEach(u)}};c(n),l.forEach(arguments.length<3?function(t,e){s.push([e])}:function(t,e){r(t[0],t[t.length-1])&&s.push([e])})}else for(var p=0,h=e.arcs.length;h>p;++p)s.push([p]);return o(e,{type:"MultiLineString",arcs:t(e,s)})}function n(t,e){return e.type==="GeometryCollection"?{type:"FeatureCollection",features:e.geometries.map(function(e){return r(t,e)})}:r(t,e)}function r(t,e){var n={type:"Feature",id:e.id,properties:e.properties||{},geometry:o(t,e)};return e.id==null&&delete n.id,n}function o(t,e){function n(t,e){e.length&&e.pop();for(var n,r=h[0>t?~t:t],o=0,i=r.length,u=0,c=0;i>o;++o)e.push([(u+=(n=r[o])[0])*f+d,(c+=n[1])*l+p]);0>t&&a(e,i)}function r(t){return[t[0]*f+d,t[1]*l+p]}function o(t){for(var e=[],r=0,o=t.length;o>r;++r)n(t[r],e);return e.length<2&&e.push(e[0]),e}function i(t){for(var e=o(t);e.length<4;)e.push(e[0]);return e}function u(t){return t.map(i)}function c(t){var e=t.type;return"GeometryCollection"===e?{type:e,geometries:t.geometries.map(c)}:e in v?{type:e,coordinates:v[e](t)}:null}var s=t.transform,f=s.scale[0],l=s.scale[1],d=s.translate[0],p=s.translate[1],h=t.arcs,v={Point:function(t){return r(t.coordinates)},MultiPoint:function(t){return t.coordinates.map(r)},LineString:function(t){return o(t.arcs)},MultiLineString:function(t){return t.arcs.map(o)},Polygon:function(t){return u(t.arcs)},MultiPolygon:function(t){return t.arcs.map(u)}};return c(e)}function a(t,e){for(var n,r=t.length,o=r-e;o<--r;)n=t[o],t[o++]=t[r],t[r]=n}function i(t,e){for(var n=0,r=t.length;r>n;){var o=n+r>>>1;t[o]<e?n=o+1:r=o}return n}function u(t){function e(t,e){t.forEach(function(t){0>t&&(t=~t);var n=o[t]||(o[t]=[]);n[e]||(n.forEach(function(t){var n,r;r=i(n=a[e],t),n[r]!==t&&n.splice(r,0,t),r=i(n=a[t],e),n[r]!==e&&n.splice(r,0,e)}),n[e]=e)})}function n(t,n){t.forEach(function(t){e(t,n)})}function r(t,e){t.type==="GeometryCollection"?t.geometries.forEach(function(t){r(t,e)}):t.type in u&&u[t.type](t.arcs,e)}var o=[],a=t.map(function(){return[]}),u={LineString:e,MultiLineString:n,Polygon:n,MultiPolygon:function(t,e){t.forEach(function(t){n(t,e)})}};return t.forEach(r),a}return{version:"1.0.0pre",mesh:e,feature:n,neighbors:u}}();
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
id short name
4 AF Afghanistan
8 AL Albania
10 AQ Antarctica
12 DZ Algeria
16 AS American Samoa
20 AD Andorra
24 AO Angola
28 AG Antigua and Barbuda
31 AZ Azerbaijan
32 AR Argentina
36 AU Australia
40 AT Austria
44 BS Bahamas
48 BH Bahrain
50 BD Bangladesh
51 AM Armenia
52 BB Barbados
56 BE Belgium
60 BM Bermuda
64 BT Bhutan
68 BO Bolivia, Plurinational State of
70 BA Bosnia and Herzegovina
72 BW Botswana
74 BV Bouvet Island
76 BR Brazil
84 BZ Belize
86 IO British Indian Ocean Territory
90 SB Solomon Islands
92 VG Virgin Islands, British
96 BN Brunei Darussalam
100 BG Bulgaria
104 MM Myanmar
108 BI Burundi
112 BY Belarus
116 KH Cambodia
120 CM Cameroon
124 CA Canada
132 CV Cape Verde
136 KY Cayman Islands
140 CF Central African Republic
144 LK Sri Lanka
148 TD Chad
152 CL Chile
156 CN China
158 TW Taiwan, Province of China
162 CX Christmas Island
166 CC Cocos (Keeling) Islands
170 CO Colombia
174 KM Comoros
175 YT Mayotte
178 CG Congo
180 CD Congo, the Democratic Republic of the
184 CK Cook Islands
188 CR Costa Rica
191 HR Croatia
192 CU Cuba
196 CY Cyprus
203 CZ Czech Republic
204 BJ Benin
208 DK Denmark
212 DM Dominica
214 DO Dominican Republic
218 EC Ecuador
222 SV El Salvador
226 GQ Equatorial Guinea
231 ET Ethiopia
232 ER Eritrea
233 EE Estonia
234 FO Faroe Islands
238 FK Falkland Islands (Malvinas)
239 GS South Georgia and the South Sandwich Islands
242 FJ Fiji
246 FI Finland
248 AX Åland Islands
250 FR France
254 GF French Guiana
258 PF French Polynesia
260 TF French Southern Territories
262 DJ Djibouti
266 GA Gabon
268 GE Georgia
270 GM Gambia
275 Palestinian Territory, Occupied
276 DE Germany
288 GH Ghana
292 GI Gibraltar
296 KI Kiribati
300 GR Greece
304 GL Greenland
308 GD Grenada
312 GP Guadeloupe
316 GU Guam
320 GT Guatemala
324 GN Guinea
328 GY Guyana
332 HT Haiti
334 HM Heard Island and McDonald Islands
336 VA Holy See (Vatican City State)
340 HN Honduras
344 HK Hong Kong
348 HU Hungary
352 IS Iceland
356 IN India
360 ID Indonesia
364 IR Iran, Islamic Republic of
368 IQ Iraq
372 IE Ireland
376 IL Israel
380 IT Italy
384 Côte d'Ivoire
388 JM Jamaica
392 JP Japan
398 KZ Kazakhstan
400 JO Jordan
404 KE Kenya
408 KP Korea, Democratic People's Republic of
410 KR Korea, Republic of
414 KW Kuwait
417 KG Kyrgyzstan
418 LA Lao People's Democratic Republic
422 LB Lebanon
426 LS Lesotho
428 LV Latvia
430 LR Liberia
434 LY Libya
438 LI Liechtenstein
440 LT Lithuania
442 LU Luxembourg
446 MO Macao
450 MG Madagascar
454 MW Malawi
458 MY Malaysia
462 MV Maldives
466 ML Mali
470 MT Malta
474 MQ Martinique
478 MR Mauritania
480 MU Mauritius
484 MX Mexico
492 MC Monaco
496 MN Mongolia
498 MD Moldova, Republic of
499 ME Montenegro
500 MS Montserrat
504 MA Morocco
508 MZ Mozambique
512 OM Oman
516 NA Namibia
520 NR Nauru
524 NP Nepal
528 NL Netherlands
531 Curaçao
533 AW Aruba
534 SX Sint Maarten (Dutch part)
535 BQ Bonaire, Sint Eustatius and Saba
540 NC New Caledonia
548 VU Vanuatu
554 NZ New Zealand
558 NI Nicaragua
562 NE Niger
566 NG Nigeria
570 NU Niue
574 NF Norfolk Island
578 NO Norway
580 MP Northern Mariana Islands
581 UM United States Minor Outlying Islands
583 FM Micronesia, Federated States of
584 MH Marshall Islands
585 PW Palau
586 PK Pakistan
591 PA Panama
598 PG Papua New Guinea
600 PY Paraguay
604 PE Peru
608 PH Philippines
612 PN Pitcairn
616 PL Poland
620 PT Portugal
624 GW Guinea-Bissau
626 TL Timor-Leste
630 PR Puerto Rico
634 QA Qatar
638 Réunion
642 RO Romania
643 RU Russian Federation
646 RW Rwanda
652 Saint Barthélemy
654 SH Saint Helena, Ascension and Tristan da Cunha
659 KN Saint Kitts and Nevis
660 AI Anguilla
662 LC Saint Lucia
663 MF Saint Martin (French part)
666 PM Saint Pierre and Miquelon
670 VC Saint Vincent and the Grenadines
674 SM San Marino
678 ST Sao Tome and Principe
682 SA Saudi Arabia
686 SN Senegal
688 RS Serbia
690 SC Seychelles
694 SL Sierra Leone
702 SG Singapore
703 SK Slovakia
704 VN Viet Nam
705 SI Slovenia
706 SO Somalia
710 ZA South Africa
716 ZW Zimbabwe
724 ES Spain
728 SS South Sudan
729 SD Sudan
732 EH Western Sahara
740 SR Suriname
744 SJ Svalbard and Jan Mayen
748 SZ Swaziland
752 SE Sweden
756 CH Switzerland
760 SY Syrian Arab Republic
762 TJ Tajikistan
764 TH Thailand
768 TG Togo
772 TK Tokelau
776 TO Tonga
780 TT Trinidad and Tobago
784 AE United Arab Emirates
788 TN Tunisia
792 TR Turkey
795 TM Turkmenistan
796 TC Turks and Caicos Islands
798 TV Tuvalu
800 UG Uganda
804 UA Ukraine
807 MK Macedonia, the former Yugoslav Republic of
818 EG Egypt
826 GB United Kingdom
831 GG Guernsey
832 JE Jersey
833 IM Isle of Man
834 TZ Tanzania, United Republic of
840 US United States
850 VI Virgin Islands, U.S.
854 BF Burkina Faso
858 UY Uruguay
860 UZ Uzbekistan
862 VE Venezuela, Bolivarian Republic of
876 WF Wallis and Futuna
882 WS Samoa
887 YE Yemen
894 ZM Zambia
<kibana-panel ng-controller='map2' ng-init="init()">
<style>
.overlay {
fill: none;
pointer-events: all;
}
.land {
fill: #D1D1D1;
stroke: #595959;
stroke-linejoin: round;
stroke-linecap: round;
stroke-width: .1px;
}
.boundary {
fill: none;
stroke: #000;
stroke-linejoin: round;
stroke-linecap: round;
}
.hexagon {
fill: none;
stroke: #000;
stroke-width: .1px;
}
.q1 { fill:rgb(247,251,255); }
.q2 { fill:rgb(222,235,247); }
.q3 { fill:rgb(198,219,239); }
.q4 { fill:rgb(158,202,225); }
.q5 { fill:rgb(107,174,214); }
.q6 { fill:rgb(66,146,198); }
.q7 { fill:rgb(33,113,181); }
.q8 { fill:rgb(8,81,156); }
.q9 { fill:rgb(8,48,107); }
.arc {
stroke: #f00;
stroke-width: .5px;
fill: none;
}
.geopoint {
stroke: #000;
stroke-width: .5px;
fill: #000;
}
.dropdown-menu{position:absolute;top:auto;left:auto;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}
</style>
<span ng-show="panel.spyable" style="position:absolute;right:0px;top:0px" class='panelextra pointer'>
<i bs-modal="'partials/modal.html'" class="icon-eye-open"></i>
</span>
<div map2 params="{{panel}}" style="height:{{panel.height || row.height}}"></div>
</kibana-panel>
\ No newline at end of file
angular.module('kibana.map2', [])
.controller('map2', function ($scope, eventBus, keylistener) {
// Set and populate defaults
var _d = {
status : "Broken",
query: "*",
map: "world",
colors: ['#C8EEFF', '#0071A4'],
size: 100,
exclude: [],
spyable: true,
group: "default",
index_limit: 0,
display: {
translate:[0, 0],
scale:-1,
data: {
samples: 1000,
type: "mercator",
dropdown:[
{
"text": "Mercator (Flat)",
id: "mercator"
},
{
text: "Orthographic (Sphere)",
id: "orthographic"
}
]
},
geopoints: {
enabled: false,
enabledText: "Enabled",
pointSize: 0.3,
pointAlpha: 0.6
},
binning: {
enabled: false,
hexagonSize: 2,
hexagonAlpha: 1.0,
areaEncoding: true,
areaEncodingField: "primary",
colorEncoding: true,
colorEncodingField: "primary"
},
choropleth: {
enabled: false
},
bullseye: {
enabled: false,
coord: {
lat: 0,
lon: 0
}
}
},
activeDisplayTab:"Geopoints"
};
_.defaults($scope.panel, _d)
$scope.init = function () {
eventBus.register($scope, 'time', function (event, time) {
set_time(time)
});
eventBus.register($scope, 'query', function (event, query) {
$scope.panel.query = _.isArray(query) ? query[0] : query;
$scope.get_data();
});
// Now that we're all setup, request the time from our group
eventBus.broadcast($scope.$id, $scope.panel.group, 'get_time');
$scope.keylistener = keylistener;
};
$scope.get_data = function () {
// Make sure we have everything for the request to complete
if (_.isUndefined($scope.index) || _.isUndefined($scope.time))
return
$scope.panel.loading = true;
var request = $scope.ejs.Request().indices($scope.index);
var metric = 'count';
//Use a regular term facet if there is no secondary field
if (typeof $scope.panel.secondaryfield === "undefined") {
var facet = $scope.ejs.TermsFacet('map')
.field($scope.panel.field)
.size($scope.panel.display.data.samples)
.exclude($scope.panel.exclude)
.facetFilter(ejs.QueryFilter(
ejs.FilteredQuery(
ejs.QueryStringQuery($scope.panel.query || '*'),
ejs.RangeFilter($scope.time.field)
.from($scope.time.from)
.to($scope.time.to))));
metric = 'count';
} else {
//otherwise, use term stats
//NOTE: this will break if valueField is a geo_point
// need to put in checks for that
var facet = $scope.ejs.TermStatsFacet('map')
.keyField($scope.panel.field)
.valueField($scope.panel.secondaryfield)
.size($scope.panel.display.data.samples)
.facetFilter(ejs.QueryFilter(
ejs.FilteredQuery(
ejs.QueryStringQuery($scope.panel.query || '*'),
ejs.RangeFilter($scope.time.field)
.from($scope.time.from)
.to($scope.time.to))));
metric = 'total';
}
// Then the insert into facet and make the request
var request = request.facet(facet).size(0);
$scope.populate_modal(request);
var results = request.doSearch();
// Populate scope when we have results
results.then(function (results) {
$scope.panel.loading = false;
$scope.hits = results.hits.total;
$scope.data = {};
_.each(results.facets.map.terms, function (v) {
if (!_.isNumber(v.term)) {
$scope.data[v.term.toUpperCase()] = v[metric];
} else {
$scope.data[v.term] = v[metric];
}
});
$scope.$emit('render')
});
};
// I really don't like this function, too much dom manip. Break out into directive?
$scope.populate_modal = function (request) {
$scope.modal = {
title: "Inspector",
body: "<h5>Last Elasticsearch Query</h5><pre>" + 'curl -XGET ' + config.elasticsearch + '/' + $scope.index + "/_search?pretty -d'\n" + angular.toJson(JSON.parse(request.toString()), true) + "'</pre>"
}
};
function set_time(time) {
$scope.time = time;
$scope.index = _.isUndefined(time.index) ? $scope.index : time.index
$scope.get_data();
}
$scope.build_search = function (field, value) {
$scope.panel.query = add_to_query($scope.panel.query, field, value, false)
$scope.get_data();
eventBus.broadcast($scope.$id, $scope.panel.group, 'query', $scope.panel.query);
};
$scope.isActive = function(tab) {
return (tab.toLowerCase() === $scope.panel.activeDisplayTab.toLowerCase());
}
$scope.tabClick = function(tab) {
$scope.panel.activeDisplayTab = tab;
}
})
.filter('enabledText', function() {
return function (value) {
if (value === true) {
return "Enabled";
} else {
return "Disabled";
}
}
})
.directive('map2', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
//directive level variables related to d3
var dr = {};
scope.initializing = false;
dr.worldData = null;
dr.worldNames = null;
/**
* Initialize the panels if new, or render existing panels
*/
scope.init_or_render = function() {
if (typeof dr.svg === 'undefined') {
console.log("init");
//prevent duplicate initialization steps, if render is called again
//before the svg is setup
if (!scope.initializing) {
init_panel();
}
} else {
console.log("render");
render_panel();
}
};
/**
* Receive render events
*/
scope.$on('render', function () {
scope.init_or_render();
});
/**
* On window resize, re-render the panel
*/
angular.element(window).bind('resize', function () {
scope.init_or_render();
});
/**
* Load the various panel-specific scripts, map data, then initialize
* the svg and set appropriate D3 settings
*/
function init_panel() {
scope.initializing = true;
// Using LABjs, wait until all scripts are loaded before rendering panel
var scripts = $LAB.script("common/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/node-geohash.js?rand="+Math.floor(Math.random()*10000))
.script("panels/map2/lib/d3.hexbin.v0.min.js?rand="+Math.floor(Math.random()*10000))
.script("panels/map2/lib/queue.v1.min.js?rand="+Math.floor(Math.random()*10000))
.script("panels/map2/display/binning.js?rand="+Math.floor(Math.random()*10000))
.script("panels/map2/display/geopoints.js?rand="+Math.floor(Math.random()*10000))
.script("panels/map2/display/bullseye.js?rand="+Math.floor(Math.random()*10000));
// Populate element. Note that jvectormap appends, does not replace.
scripts.wait(function () {
queue()
.defer(d3.json, "panels/map2/lib/world-110m.json")
.defer(d3.tsv, "panels/map2/lib/world-country-names.tsv")
.await(function(error, world, names) {
dr.worldData = world;
dr.worldNames = names;
//Better way to get these values? Seems kludgy to use jQuery on the div...
var width = $(elem[0]).width(),
height = $(elem[0]).height();
//scale to whichever dimension is smaller, helps to ensure the whole map is displayed
dr.scale = (width > height) ? (height/5) : (width/5);
dr.zoom = d3.behavior.zoom()
.scaleExtent([1, 20])
.on("zoom", translate_map);
//used by choropleth
//@todo change domain so that it reflects the domain of the data
dr.quantize = d3.scale.quantize()
.domain([0, 1000])
.range(d3.range(9).map(function(i) { return "q" + (i+1); }));
//Extract name and two-letter codes for our countries
dr.countries = topojson.feature(dr.worldData, dr.worldData.objects.countries).features;
dr.countries = dr.countries.filter(function(d) {
return dr.worldNames.some(function(n) {
if (d.id == n.id) {
d.name = n.name;
return d.short = n.short;
}
});
}).sort(function(a, b) {
return a.name.localeCompare(b.name);
});
//create the new svg
dr.svg = d3.select(elem[0]).append("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 " + width + " " + height)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.call(dr.zoom);
dr.g = dr.svg.append("g");
scope.initializing = false;
render_panel();
});
});
}
/**
* Render updates to the SVG. Typically happens when the data changes (time, query)
* or when new options are selected
*/
function render_panel() {
var width = $(elem[0]).width(),
height = $(elem[0]).height();
//Projection is dependant on the map-type
if (scope.panel.display.data.type === 'mercator') {
dr.projection = d3.geo.mercator()
.translate([width/2, height/2])
.scale(dr.scale);
} else if (scope.panel.display.data.type === 'orthographic') {
dr.projection = d3.geo.orthographic()
.translate([width/2, height/2])
.scale(100)
.clipAngle(90);
//recenters the sphere more towards the US...not really necessary
dr.projection.rotate([100 / 2, 20 / 2, dr.projection.rotate()[2]]);
}
dr.path = d3.geo.path()
.projection(dr.projection).pointRadius(0.2);
console.log(scope.data);
//Geocoded points are decoded into lonlat
dr.points = _.map(scope.data, function (k, v) {
//console.log(k,v);
var decoded = geohash.decode(v);
return [decoded.longitude, decoded.latitude];
});
//And also projected projected to x/y. Both sets of points are used
//by different functions
dr.projectedPoints = _.map(dr.points, function (coords) {
return dr.projection(coords);
});
dr.svg.select(".overlay").remove();
dr.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
var countryPath = dr.g.selectAll(".land")
.data(dr.countries);
countryPath.enter().append("path")
.attr("class", function(d) {
if (scope.panel.display.choropleth.enabled) {
return 'land ' + dr.quantize(scope.data[d.short]);
} else {
return 'land';
}
})
.attr("d", dr.path);
countryPath.exit().remove();
//If this is a sphere, set up drag and keypress listeners
if (scope.panel.display.data.type === 'orthographic') {
dr.svg.style("cursor", "move")
.call(d3.behavior.drag()
.origin(function() { var rotate = dr.projection.rotate(); return {x: 2 * rotate[0], y: -2 * rotate[1]}; })
.on("drag", function() {
if (scope.keylistener.keyActive(17)) {
dr.projection.rotate([d3.event.x / 2, -d3.event.y / 2, dr.projection.rotate()[2]]);
//dr.svg.selectAll("path").attr("d", dr.path);
dr.g.selectAll("path").attr("d", dr.path);
}
}));
}
//Special fix for when the user changes from mercator -> orthographic
//The globe won't redraw automatically, we need to force it
if (scope.panel.display.data.type === 'orthographic') {
dr.svg.selectAll("path").attr("d", dr.path);
}
/**
* Display option rendering
* Order is important to render order here!
*/
//@todo fix this
var dimensions = [width, height];
displayBinning(scope, dr, dimensions);
displayGeopoints(scope, dr);
displayBullseye(scope, dr);
//If the panel scale is not default (e.g. the user has moved the maps around)
//set the scale and position to the last saved config
if (scope.panel.display.scale != -1) {
dr.zoom.scale(scope.panel.display.scale).translate(scope.panel.display.translate);
dr.g.style("stroke-width", 1 / scope.panel.display.scale).attr("transform", "translate(" + scope.panel.display.translate + ") scale(" + scope.panel.display.scale + ")");
}
}
/**
* On D3 zoom events, pan/zoom the map
* Only applies if the ctrl-key is not pressed, so it doesn't clobber
* sphere dragging
*/
function translate_map() {
var width = $(elem[0]).width(),
height = $(elem[0]).height();
if (! scope.keylistener.keyActive(17)) {
var t = d3.event.translate,
s = d3.event.scale;
t[0] = Math.min(width / 2 * (s - 1), Math.max(width / 2 * (1 - s), t[0]));
t[1] = Math.min(height / 2 * (s - 1) + 230 * s, Math.max(height / 2 * (1 - s) - 230 * s, t[1]));
dr.zoom.translate(t);
scope.panel.display.translate = t;
scope.panel.display.scale = s;
dr.g.style("stroke-width", 1 / s).attr("transform", "translate(" + t + ") scale(" + s + ")");
}
}
}
};
});
\ No newline at end of file
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