Skip to content

Instantly share code, notes, and snippets.

@hugolpz
Forked from jasondavies/README.md
Last active August 29, 2015 14:05
Show Gist options
  • Save hugolpz/f02abc3d4a395f280f6a to your computer and use it in GitHub Desktop.
Save hugolpz/f02abc3d4a395f280f6a to your computer and use it in GitHub Desktop.
World tour WP guidelines

World tour using Wikipedia Map guidelines, more precisely the soon to come new globe locator convention. Inspired from Jason Davies world tour, merged into my localisator code.

V.2 Change log

This code is a second wave of customization.

  • Base: Own made Wikiatlas localisator and some of Jason Davies codes.
  • Dependencies: Migration to topojson v.1.0
  • CSS: migration to Wikipedia map guidelines and internalize to svg
  • JS: removed Jason Davies more accurate spherical interpolation.
  • JS: removed smooth transition (not relevant to our needs)
  • JS: added red geoframe for areas smaller than 15 steradians.
  • use of d3.geo.centroid(feature) to place it
  • use of d3.geo.bounds(feature) to get a bounding box with +5⁰ margins on each side
  • use of d3.geo.area(feature) to conditionally display a frame

V.3 ideas

In a 3rd wave of customization, this code could be refactored to reduce code redundancies. The loop on data's .countries should in order recalculate the bounding box, run the localisator with conditional framing, print the file, before to go to i+1.

References :

<!DOCTYPE html>
<meta charset="utf-8">
<style>
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 18px;
font-weight: bold;
text-anchor: middle;
}
</style>
<body>
<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.1.0/topojson.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3-geo-projection/0.2.9/d3.geo.projection.min.js"></script>
<script src="../js/wikiatlas.js"></script>
<script>
/**
* Created with Wikiatlas.
* User: hugolpz
* Version: 2014.09.04 */
/* ****************************************************** */
/* MATH TOOLKIT ***************************************** */
function parallel(φ, λ0, λ1) {
if (λ0 > λ1) λ1 += 360;
var dλ = λ1 - λ0,
step = dλ / Math.ceil(dλ);
return d3.range(λ0, λ1 + 0.5 * step, step).map(function(λ) { return [normalise(λ), φ]; });
}
function normalise(x) {
return (x + 180) % 360 - 180;
}
/* ****************************************************** */
/* LOCALISATOR FN *************************************** */
var localisator = function (hookId,localisator_width, title, WNES0, WNES1, WNES2, WNES3) {
/* Init ************************************************* */
var width = 1*localisator_width,
height = 1*localisator_width;
var lon_central = function(){
var num;
if(WNES2<WNES0){ num= -(WNES0+WNES2)/2+180; }
else{ num= -(WNES0+WNES2)/2; }
return num;
};
var proj = d3.geo.orthographic()
.scale(1/2*localisator_width)
.rotate([ lon_central(), -(WNES1+WNES3)/2 +10 ]); // orthographic + 10⁰ to simulate real life globe watching.
var projection2 = proj
.translate([width / 2 , height / 2 ])
.clipAngle(90);
var path = d3.geo.path()
.projection(projection2);
/* SVG container **************************************** */
var svg = d3.select(hookId).append("svg")
.attr("id", title+"-orthographic_globe_locator_(wikiatlas_2014)")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.drag()
.origin(function() {
var rotate = projection2.rotate();
return {x: 2 * rotate[0], y: -2 * rotate[1]};
})
.on("drag", function() {
projection2.rotate([d3.event.x / 2, -d3.event.y / 2, projection2.rotate()[2]]);
svg.selectAll("path").attr("d", path);
}))
.on("dblclick", function() {
projection2.rotate([ lon_central(), -(WNES1+WNES3)/2 +10 ]);
svg.selectAll("path").attr("d", path);
});
/* SVG background *************************************** */
// Blue circle
svg.append("circle")
.attr("class", "water")
.attr("cx", width/2)
.attr("cy", height/2)
.attr("r", width/2 )
.style({'fill':'#C6ECFF'})
.style({'stroke': '656565', 'stroke-width': 1.5});
// Gradiant settings
var gradient = 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");
gradient.append("svg:stop") // middle step setting
.attr("offset", "50%")
.attr("stop-color", "#FFF")
.attr("stop-opacity", 0.3);
gradient.append("svg:stop") // final step setting
.attr("offset", "100%")
.attr("stop-color", "#009")
.attr("stop-opacity", 0.3);
// Gradiant-circle
var circle = svg.append('circle') // append gradient to circle
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', width/2 )
.attr('fill', 'url(#gradient)');
/* ****************************************************** */
/* GIS data injection *********************************** */
d3.json("world-110m-ids.json", function(error, world) {
/**/ var countries = topojson.feature(world, world.objects.countries).features,
/**/ i = -1,
/**/ n = countries.length;
var country = svg.selectAll(".country")
.data(topojson.feature(world, world.objects.countries).features)
.enter().append("path")
.attr("id", function(d){ return d.id } )
.attr("class", "country")
.style("fill", "#FDFBEA")
.attr("d", path);
var focus = d3.selectAll("#"+title)
.style("fill", "#B10000");
var boundaries = svg.append("path")
//.datum( topojson.mesh(world, world.objects.countries, function(a,b) { if (a!==b){var ret = b;}return ret;}))
.datum( topojson.mesh(world, world.objects.countries, function(a,b) { return a!==b; }))
.attr("class", "boundary")
.attr("d", path)
.style({'fill':'none','stroke': '#656565', 'stroke-width': 0.5});
var graticule = svg.append("path")
.datum(d3.geo.graticule().step([20,20]))
.attr("class", "graticule")
.attr("d", path)
.style({'fill':'none', 'stroke':'#777', 'stroke-width': 0.5, 'stroke-opacity': 0.5});
var coast = svg.append("path")
//.datum( topojson.mesh(world, world.objects.countries, function(a,b) { if (a==b){var ret = b;}return ret;}))
.datum( topojson.mesh(world, world.objects.countries, function(a,b) { return a==b; }))
.attr("class", "Coast_border")
.style({'fill': 'none', 'stroke': '#0978AB', 'stroke-linejoin': 'round'})
.style({'stroke-width': 0.5 })
.attr("d", path);
/* Red graniticule drawing
svg.append("path")
.attr("d", path(d3.geo.graticule()
.majorExtent([[WNES0, WNES3], [WNES2, WNES1]]).outline()))
.style({'fill': '#B10000', 'fill-opacity': 0.3, 'stroke': '#B10000', 'stroke-linejoin': 'round'})
.style({'stroke-width': 1 }); /**/
//* Red polygon drawing
var redwindow = svg.append("path")
.datum({type: "Polygon", coordinates: [ //LineString
[[WNES0,WNES3]]
.concat(parallel(WNES1, WNES0, WNES2))
.concat(parallel(WNES3, WNES0, WNES2).reverse())
]})
.style({'fill': '#B10000', 'fill-opacity': 0.3, 'stroke': '#B10000', 'stroke-linejoin': 'round'})
.style({'stroke-width': 1 })
.attr("d", path); /**/
var label = svg.append("text")
.attr("x", width / 2)
.attr("text-anchor","middle")
.text(title)
.attr("y", height * 57/100 );
var step = function() {
if (++i >= n) { i = 0} ;
label.text(countries[i].id);
svg.transition();
country.transition()
.style("fill", function(d, j) { return j === i ? "#B10000" : "#FDFBEA"; });
var centroid = d3.geo.path()
.projection(function(d) { return d; })
.centroid;
var area = d3.geo.path()
.projection(function(d) { return d; })
.area;
var bounds = d3.geo.path()
.projection(function(d) { return d; })
.bounds;
d3.transition()
.delay(250)
.duration(1250)
.tween("rotate", function() {
var point = centroid(countries[i]);
var surface = area(countries[i]);
var bb = bounds(countries[i]);
console.log("area: "+surface+"; bb: "+ JSON.stringify(bb) );
return function(t) {
projection2.rotate([-point[0], -point[1]+10]); // area of interest slide 10⁰ up
country.attr("d", path);
boundaries.attr("d", path);
graticule.attr("d", path);
coast.attr("d", path);
// draw polygon (red frame) bigger than bb:
if (surface <15) { // is visible
redwindow.datum({type: "Polygon", coordinates: [ //LineString
[[bb[0][0]-5,bb[0][1]-5]]
.concat(parallel(bb[1][1]+5, bb[0][0]-5, bb[1][0]+5))
.concat(parallel(bb[0][1]-5, bb[0][0]-5, bb[1][0]+5).reverse())
]})
.style({'fill': '#B10000', "opacity": 1, 'fill-opacity': 0.3})
.style({'stroke-width': 1, 'stroke-opacity': 1, 'stroke': '#B10000', 'stroke-linejoin': 'round' })
.attr("d", path); /**/
} else if (surface >15 ) { // isn't visible
redwindow.style({'opacity': 0})
}
};
})
.transition() // runs transition
.each("end", function(){ console.log(countries[i].id); return step(); } );
}
step();
});
};
</script>
<script>
var WNES = { "item":"India", "W": 67.0, "N":37.5, "E": 99.0, "S": 5.0 };
localisator("body",500, WNES.item, WNES.W, WNES.N, WNES.E, WNES.S);
</script>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment