var width = 2000, τ = 2 * Math.PI, ε = 1e-3, height = 0.5 * width * Math.sin(τ/6); // ############### scaling and translating ############### // from http://stackoverflow.com/questions/14492284/#answer-14691788 // var bb = { "type": "Sphere"}; // // find proper scale and translation from bounds of bb polygon // var projection = d3.geo.polyhedron.cahillKeyes().scale(1).translate([0,0]); // var path = d3.geo.path().projection(projection); // var b = path.bounds(bb), // s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height), // t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; // console.log("width = "+ width); // console.log("height = "+ height); // console.log("s = "+s); // console.log("t = ["+t[0]+","+t[1]+"]"); // as found via the code above with width = 2000 and height = 866.0254037844387 var s = 0.04750001479994384, t = [1241.9205623963537,156.21906841388483]; // ####################################################### var x0 = 20, // rotation φ0 = 22.5, // Tropic of Cancer φ1 = 67.5, // Arctic Circle graticule = d3.geo.graticule() .majorStep([20, 20]) .precision(0.5); var projection = d3.geo.polyhedron.cahillKeyes() .rotate([x0, 0]) .scale(s) .translate(t) .precision(.1); var path = d3.geo.path() .projection(projection); var svg = d3.select("#map").append("svg") .attr("width", width) .attr("height", height); var defs = svg.append("defs"); // create filter with id #drop-shadow // height=130% so that the shadow is not clipped var filter = defs.append("filter") .attr("id", "drop-shadow") .attr("height", "130%"); // SourceAlpha refers to opacity of graphic that this filter will be applied to // convolve that with a Gaussian with standard deviation 3 and store result // in blur filter.append("feGaussianBlur") .attr("in", "SourceAlpha") .attr("stdDeviation", 3) .attr("result", "blur"); // translate output of Gaussian blur to the right and downwards with 2px // store result in offsetBlur filter.append("feOffset") .attr("in", "blur") .attr("dx", 2) .attr("dy", 2) .attr("result", "offsetBlur"); filter.append("feComponentTransfer") .append("feFuncA") .attr("type" ,"linear") .attr("slope","0.2") // overlay original SourceGraphic over translated blurred opacity by using // feMerge filter. Order of specifying inputs is important! var feMerge = filter.append("feMerge"); feMerge.append("feMergeNode") .attr("in", "offsetBlur") feMerge.append("feMergeNode") .attr("in", "SourceGraphic"); defs.append("path") .datum({type: "Sphere"}) .attr("id", "sphere") .attr("d", path); defs.append("clipPath") .attr("id", "clip") .append("use") .attr("xlink:href", "#sphere"); svg.append("use") .attr("class", "stroke") .attr("xlink:href", "#sphere"); svg.append("use") .attr("class", "fill") .attr("xlink:href", "#sphere"); svg.append("path") .datum(graticule) .attr("class", "graticule") .attr("clip-path", "url(#clip)") .attr("d", path); // tropics and circles svg.selectAll("path.parallel") .data([ d3.range(-180, 181, 1).map(function(x) { return [x - x0, φ0]; }), d3.range(-180, 181, 1).map(function(x) { return [x - x0, φ1]; }), d3.range(-180, 181, 1).map(function(x) { return [x - x0, -φ0]; }), d3.range(-180, 181, 1).map(function(x) { return [x - x0, -φ1]; }) ]) .enter().append("path") .datum(function(d) { return {type: "LineString", coordinates: d}; }) .attr("class", "parallel") .attr("clip-path", "url(#clip)") .attr("d", path); // equator svg.selectAll("path.equator") .data([ d3.range(-180, 181, 1).map(function(x) { return [x - x0, 0]; }) ]) .enter().append("path") .datum(function(d) { return {type: "LineString", coordinates: d}; }) .attr("class", "equator") .attr("clip-path", "url(#clip)") .attr("d", path); d3.json("world-50m.json", function(error, world) { var countries = topojson.feature(world, world.objects.countries).features, neighbors = topojson.neighbors(world.objects.countries.geometries); svg.insert("path", ".graticule") .datum(topojson.feature(world, world.objects.land)) .attr("class", "land") .style("filter", "url(#drop-shadow)") .attr("clip-path", "url(#clip)") .attr("d", path); }); d3.select(self.frameElement).style("height", height + "px");