var mapWidth = 960, mapHeight = 500, focused = false, ortho = true, speed = -7e-3, start = Date.now(), corr = 0; var projectionGlobe = d3.geo.orthographic() .scale(240) .translate([mapWidth / 2, mapHeight / 2]) .clipAngle(90); var projectionMap = d3.geo.equirectangular() .scale(145) .translate([mapWidth / 2, mapHeight / 2]) var projection = projectionGlobe; var path = d3.geo.path() .projection(projection); var svgMap = d3.select("div#map").append("svg") .attr("overflow", "hidden") .attr("width", mapWidth) .attr("height", mapHeight); var zoneTooltip = d3.select("div#map").append("div").attr("class", "zoneTooltip"), infoLabel = d3.select("div#map").append("div").attr("class", "infoLabel"); var g = svgMap.append("g"); //Starter for function AFTER All transitions function endall(transition, callback) { var n = 0; transition .each(function() { ++n; }) .each("end", function() { if (!--n) callback.apply(this, arguments); }); } //Loading data queue() .defer(d3.json, "/d/5685937/world-110m.json") .defer(d3.tsv, "/d/5685937/world-110m-country-names.tsv") .await(ready); function ready(error, world, countryData) { var countryById = {}, countries = topojson.feature(world, world.objects.countries).features; //Adding countries by name countryData.forEach(function(d) { countryById[d.id] = d.name; }); //Drawing countries on the globe var world = g.selectAll("path").data(countries); world.enter().append("path") .attr("class", "mapData") .attr("d", path) .classed("ortho", ortho = true); //Events processing world.on("mouseover", function(d) { if (ortho === true) { infoLabel.text(countryById[d.id]) .style("display", "inline"); } else { zoneTooltip.text(countryById[d.id]) .style("left", (d3.event.pageX + 7) + "px") .style("top", (d3.event.pageY - 15) + "px") .style("display", "block"); } }) .on("mouseout", function(d) { if (ortho === true) { infoLabel.style("display", "none"); } else { zoneTooltip.style("display", "none"); } }) .on("mousemove", function() { if (ortho === false) { zoneTooltip.style("left", (d3.event.pageX + 7) + "px") .style("top", (d3.event.pageY - 15) + "px"); } }) .on("click", function(d) { if (focused === d) return reset(); g.selectAll(".focused").classed("focused", false); d3.select(this).classed("focused", focused = d); infoLabel.text(countryById[d.id]) .style("display", "inline"); //Transforming Globe to Map if (ortho === true) { corr = projection.rotate()[0]; // <- save last rotation angle g.selectAll(".ortho").classed("ortho", ortho = false); projection = projectionMap; path.projection(projection); g.selectAll("path").transition().duration(3000).attr("d", path); } }); //Globe rotating via timer d3.timer(function() { var λ = speed * (Date.now() - start); projection.rotate([λ + corr, -5]); g.selectAll(".ortho").attr("d", path); }); //Adding extra data when focused function focus(d) { if (focused === d) return reset(); g.selectAll(".focused").classed("focused", false); d3.select(this).classed("focused", focused = d); } //Reset projection function reset() { g.selectAll(".focused").classed("focused", focused = false); infoLabel.style("display", "none"); zoneTooltip.style("display", "none"); //Transforming Map to Globe projection = projectionGlobe; path.projection(projection); g.selectAll("path").transition() .duration(3000).attr("d", path) .call(endall, function() { g.selectAll("path").classed("ortho", ortho = true); start = Date.now(); // <- reset start for rotation }); } };