A geographic bounding box for each country from Natural Earth’s 1:110m Cultural Vectors (Admin 0 - Countries).
A minimum bounding box in geographic coordinates is an area defined by minimum and maximum longitudes and latitudes.
# d3.geo.bounds(feature) -- (source)
Returns the spherical bounding box for the specified feature. The bounding box is represented by a two-dimensional array: [[left, bottom], [right, top]], where left is the minimum longitude, bottom is the minimum latitude, right is maximum longitude, and top is the maximum latitude.
Data: see console of full windows view, with data such :
{"W":97.3717371737174; "S":5.688035433543348; "E":105.58055805580562; "N":20.414615115511538; "item":"Thailand"},
<!DOCTYPE html>
<meta charset="utf-8">
<title>Geographic Bounding Boxes</title>
<style>
/* #map svg {
cursor: move;
} */
path {
fill: none;
stroke: #000;
}
.frame, .land {
stroke-width: 1px;
}
.frame:hover {
stroke-width: 2px;
}
.example path.Polygon {
fill: url(#hatch);
}
.example text {
font-size: 11px;
font-family: sans-serif;
}
</style>
<p class="breadcrumbs">Forked from: <a href="//www.jasondavies.com/">Jason Davies</a> → <a href="//www.jasondavies.com/maps/">Maps</a> → <a href="//www.jasondavies.com/maps/bounds/">Bounds</a></p>
<h1>Geographic Bounding Boxes</h1>
<div id="map"></div>
<script src="//code.jquery.com/jquery-2.0.2.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="../js/jquery-2.0.1.min.js"></script>
<script src="../js/d3.v3.min.js"></script>
<script src="../js/topojson.v1.min.js"></script>
<script src="../js/wikiatlas.js"></script>
<script>
var width = 600,
height = width;
var projection = d3.geo.orthographic()
.translate([width / 2, height / 2])
.scale(300)
.clipAngle(90)
.precision(.1)
.rotate([0, -25]);
// There is a clipping bug, fixed in branch geo-clip-good
//.rotate([-103.5, -20, 0]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.drag()
.origin(function() { var rotate = projection.rotate(); return {x: 2 * rotate[0], y: -2 * rotate[1]}; })
.on("drag", function() {
projection.rotate([d3.event.x / 2, -d3.event.y / 2, projection.rotate()[2]]);
svg.selectAll("path").attr("d", path)
svg.selectAll("text")
.attr("x", function(d) { return -90<d3.geo.centroid(d)[0]<90?projection(d3.geo.centroid(d))[0]:null; })
.attr("y", function(d) { return -90<d3.geo.centroid(d)[1]<90?projection(d3.geo.centroid(d))[1]:null; });
}));
/* ************************************************* */
/* Death code? ************************************* */
var hatch = svg.append("defs").append("pattern")
.attr("id", "hatch")
.attr("patternUnits", "userSpaceOnUse")
.attr("width", 8)
.attr("height", 8)
.append("g");
hatch.append("path").attr("d", "M0,0L8,8");
hatch.append("path").attr("d", "M8,0L0,8");
/* ************************************************* */
// FUNCTION: Get data and process!
d3.json("world-110m-sp.06.json", function(error, json) {
var admin_0 = topojson.feature(json, json.objects.admin_0),
L0_border = topojson.mesh(json, json.objects.admin_0, function(a,b) { return a!==b;}),
admin_1 = topojson.feature(json, json.objects.admin_1),
L1_border = topojson.mesh(json, json.objects.admin_1, function(a,b) { return a!==b;}),
coast = topojson.mesh(json, json.objects.admin_0, function(a,b) { return a===b;});
/* **************************************************************** */
var water = svg.append("path")
.datum({type: "Sphere"})
.attr("class", "water")
.style({'fill':'#C6ECFF'})
.style({'stroke': '656565', 'stroke-width': 1.5})
.attr("d", path);
var earthGradient = svg.append("svg:defs")
.append("svg:linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("fx1", "30%")
.attr("fy1", "30%")
.attr("x2", "100%")
.attr("y2", "100%")
.attr("spreadMethod", "pad");
earthGradient.append("svg:stop")
.attr("offset", "50%")
.attr("stop-color", "#FFF")
.attr("stop-opacity", 0.3);
earthGradient.append("svg:stop")
.attr("offset", "100%")
.attr("stop-color", "#009")
.attr("stop-opacity", 0.2);
var earthShadow = svg.append('circle')
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', width/2 )
.attr('fill', 'url(#gradient)');
/* **************************************************************** */
/* **************************************************************** */
var L0 = svg.append("path")
.attr("class", "")
.datum(admin_0)
.style({'fill':'#FDFBEA','stroke':'none'})
.attr("d", path);
var L1_border = svg.append("path")
.datum(L1_border)
.attr("class", "")
.style({'fill':'none','stroke': '#999', 'stroke-width': .5})
.attr("d", path);
var L0_border = svg.append("path")
.datum(L0_border)
.attr("class", "")
.style({'fill':'none','stroke': '#666', 'stroke-width': 1})
.attr("d", path);
var grid = svg.append("path")
.datum(d3.geo.graticule().step([20,20]))
.attr("class", "")
.style({'fill':'none', 'stroke':'#777', 'stroke-width': 0.5, 'stroke-opacity': 0.5})
.attr("d", path);
var antimeridian = svg.append("path")
.datum({type: "LineString", coordinates: [[180, -90], [180, 0], [180, 90]]})
.attr("id", "")
.style({'fill':'none','stroke': '#777', 'stroke-width': 1, 'stroke-dasharray': '5 5'})
.attr("d", path);
var coast = svg.append("path")
.datum( coast )
.attr("d", path)
.attr("class", "")
.style({'fill': 'none', 'stroke': '#0978AB', 'stroke-linejoin': 'round'})
.style({'stroke-width': 0.5 })
var frames = svg.selectAll(".frame")
.data(admin_0.features)
.enter().append("g").attr('id','frame');
frames.append("path")
.datum(boundsPolygon())
.attr("class","frame")
.style({'fill': '#94BF8B', 'fill-opacity': 0.25})
.style({'stroke': '#94BF8B', 'stroke-width': 1, 'stroke-linejoin': 'round' })
.attr("d", path);
var centros = svg.selectAll(".centros")
.data(admin_0.features)
.enter().append("g").attr('id','centros');
centros
.append("text")
.attr("style", "stroke-width:3,stroke:#F00")
.attr("class","")
.attr("x", function(d) { return projection(d3.geo.centroid(d))[0] })
.attr("y", function(d) { return projection(d3.geo.centroid(d))[1] })
.text("⭑") // ⬤◉⍟☉⚪⚫●⚬◯★☆☆⭐ ⭑ ⭒
;
/*
centros.append("path")
.datum( {type: "Point",coordinates: [ d3.geo.centroid[0],d3.geo.centroid[1]]}})
.attr("d", path)
.style({'fill': '#94BF8B', 'fill-opacity': 0.25})
.style({'stroke': '#94BF8B', 'stroke-width': 1, 'stroke-linejoin': 'round' });
var centros = svg.append("g")
.selectAll("path")
.data(admin_0.features)
.enter().append("text")
.attr("x", function(d) { return path.centroid(d)[0] })
.attr("y", function(d) { return path.centroid(d)[1] })
.text("⭑") // ⬤◉⍟☉⚪⚫●⚬◯★☆☆⭐ ⭑ ⭒
.style({'fill':'#333;'});
*/
});
function boundsPolygon() {
return function(geometry) {
var bb = d3.geo.bounds(geometry);
// START WNES JSON GENERATOR ! #########################################################################################
var WNES = {}; // MUST declare object var ... = {};
WNES.iso2 = geometry.properties.L0,
WNES.iso3 = geometry.properties.L0_3,
WNES.name = geometry.properties.name,
WNES.area = d3.geo.area(geometry);
// fix NaturalEarth data
WNES.iso3==="CYN"?WNES.iso2="X1":"";
WNES.iso3==="KAZ"&&WNES.iso2==="-99"?WNES.iso2="X2":"";
WNES.iso3==="KAS"?WNES.iso2="X3":"";
WNES.iso3==="KOS"?WNES.iso2="X4":"";
WNES.iso3==="SOL"?WNES.iso2="X5":"";
WNES.iso2==="X2"?WNES.name="Baikonour":"";
WNES.iso2==="NC"?WNES.name="New_Caledonia":"";
WNES.iso2==="TF"?WNES.name="Kerguelen_Islands":"";
WNES.iso2==="GL"?WNES.name="Greenland":"";
WNES.iso2==="PR"?WNES.name="Puerto_Rico":"";
WNES.iso2==="FK"?WNES.name="Falkland_Islands":"";
WNES.iso2==="PS"?WNES.name="Palestine":"";
WNES.iso2==="GS"?WNES.name="South_Georgia":"";
// Area north of 60⁰ to stay on etopo:
WNES.source = function(){ return WNES.area>0.015?"etopo":"srtm";};
bb[1][1]>60||bb[0][1]<60?WNES.source="etopo":"";
WNES.iso2==="CA"?WNES.source:"etopo";
WNES.iso2==="GL"?WNES.source:"etopo";
WNES.iso2==="IS"?WNES.source:"etopo";
WNES.iso2==="NO"?WNES.source:"etopo";
WNES.iso2==="SE"?WNES.source:"etopo";
WNES.iso2==="FI"?WNES.source:"etopo";
// WNES.iso2==="RU"?WNES.area=0:"";
//WNES.iso2==="GB"&&WNES.name="United_Kingdom"?WNES.iso2="UK":"";
// borders' geo-coordinates (decimal degrees)
WNES.W = bb[0][0], // Note: D3js is WSEN based.
WNES.N = bb[1][1],
WNES.E = bb[1][0],
WNES.S = bb[0][1],
// frame's geo-dimensions (decimal degrees)
WNES.geo_width = (WNES.E - WNES.W),
WNES.geo_height= (WNES.N - WNES.S),
// center geo-coordinates
WNES.lat_center = (WNES.S + WNES.N)/2,
WNES.lon_center = (WNES.W + WNES.E)/2;
// WNES.source= function(){ return WNES.area > 0.015? "large":"small" }();
// add a 5% padding on all WNES sides
var WNESplus = {};
WNESplus.W = WNES.W - WNES.geo_width * 0.05,
WNESplus.N = WNES.N + WNES.geo_height * 0.05,
WNESplus.E = WNES.E + WNES.geo_width * 0.05,
WNESplus.S = WNES.S - WNES.geo_height * 0.05;
/* frame+paddings' (decimal degrees)
var WNESplus.geo_width = (WNESplus.E - WNESplus.W),
WNESplus.geo_height= (WNESplus.N - WNESplus.S) */;
//Degree of precision to keep 4 meaningful digits, ie: 048⁰75 OR 0⁰05'44"6.
var digits, geo_side_max = Math.abs( Math.max( WNES.geo_width, WNES.geo_height) );
if ( geo_side_max < 1000 && geo_side_max >= 100 ) { digits = 1; }
else if ( geo_side_max < 100 && geo_side_max >= 10 ) { digits = 2; }
else if ( geo_side_max < 10 && geo_side_max >= 1 ) { digits = 3; }
else if ( geo_side_max < 1 && geo_side_max >= 0.1 ) { digits = 4; }
else if ( geo_side_max < 0.1 && geo_side_max >= 0.01 ) { digits = 5; }
else if ( geo_side_max < 0.01 && geo_side_max >= 0.001 ) { digits = 6; };
//PRINT RESULTS (4 meaningful digits):
// console.log('"WNES" : { "id":"'+ WNES.id +'", "name":"'+ WNES.name +'", "W":' + WNES.W.toFixed(digits) +',"N":' + WNES.N.toFixed(digits) +',"E":' + WNES.E.toFixed(digits) +',"S":' + WNES.S.toFixed(digits) +'}');
// console.log('"WNES+": { "id":"'+ WNES.id +'", "name":"'+ WNES.name +'", "W+":'+ WNESplus.W.toFixed(digits) +',"N+":'+ WNESplus.N.toFixed(digits) +',"E+":'+ WNESplus.E.toFixed(digits) +',"S+":'+ WNESplus.S.toFixed(digits) +'}');
console.log('make -f master.makefile ISO2='+ WNES.iso2 +' SOV3='+ WNES.iso3 +' NAME='+ WNES.name.replace(/ /gi,"_") +' WEST='+ WNESplus.W.toFixed(digits) +' SOUTH='+ WNESplus.S.toFixed(digits) +' EAST='+ WNESplus.E.toFixed(digits) +' NORTH='+ WNESplus.N.toFixed(digits) + ' AREA_SIZE='+WNES.area.toFixed(4));
// END WNES JSON #########################################################################################################
// For all Earth::
if (bb[0][0] === -180 && bb[0][1] === -90 && bb[1][0] === 180 && bb[1][1] === 90) {
return {type: "Sphere"};
}
// For
if (bb[0][1] === -90) bb[0][1] += 1e-6;
if (bb[1][1] === 90) bb[0][1] -= 1e-6;
if (bb[0][1] === bb[1][1]) bb[1][1] += 1e-6;
return {
type: "Polygon",
coordinates: [
[bb[0]]
.concat(parallel(bb[1][1], bb[0][0], bb[1][0]))
.concat(parallel(bb[0][1], bb[0][0], bb[1][0]).reverse())
]
};
};
}
function parallel(φ, λ0, λ1) {
if (λ0 > λ1) λ1 += 360;
var dλ = λ1 - λ0,
step = dλ / Math.ceil(dλ);
return d3.range(λ0, λ1 + .5 * step, step).map(function(λ) { return [normalise(λ), φ]; });
}
function normalise(x) {
return (x + 180) % 360 - 180;
}
</script>
git@gist.github.com:/6391065.git
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){"GeometryCollection"===t.type?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"GeometryCollection"===e.type?{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 null==e.id&&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];n?n.push(e):o[t]=[e]})}function n(t,n){t.forEach(function(t){e(t,n)})}function r(t,e){"GeometryCollection"===t.type?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)})}};t.forEach(r);for(var c in o)for(var s=o[c],f=s.length,l=0;f>l;++l)for(var d=l+1;f>d;++d){var p,h=s[l],v=s[d];(p=a[h])[c=i(p,v)]!==v&&p.splice(c,0,v),(p=a[v])[c=i(p,h)]!==h&&p.splice(c,0,h)}return a}return{version:"1.1.4",mesh:e,feature:n,neighbors:u}}();