Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active February 27, 2019 05:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mbostock/5234763 to your computer and use it in GitHub Desktop.
Save mbostock/5234763 to your computer and use it in GitHub Desktop.
Cylindrical Stereographic
license: gpl-3.0
height: 611
redirect: https://observablehq.com/@d3/cylindrical-stereographic
// https://d3js.org/d3-geo-projection/ Version 1.0.0. Copyright 2016 Mike Bostock.
!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("d3-geo")):"function"==typeof define&&define.amd?define(["exports","d3-geo"],r):r(n.d3=n.d3||{},n.d3)}(this,function(n,r){"use strict";function t(n){return n?n/Math.sin(n):1}function e(n){return n>1?sn:n<-1?-sn:Math.asin(n)}function o(n){return n>1?0:n<-1?gn:Math.acos(n)}function i(n){return n>0?Math.sqrt(n):0}function u(n){return(tn(n)-tn(-n))/2}function a(n){return(tn(n)+tn(-n))/2}function c(n){return on(n+i(n*n+1))}function f(n){return on(n+i(n*n-1))}function l(n,r){var e=rn(r),i=t(o(e*rn(n/=2)));return[2*e*cn(n)*i,cn(r)*i]}function v(){return r.geoProjection(l)}function g(n){function r(n,r){var t=rn(n),e=rn(r),i=cn(r),u=e*t,a=-((1-u?on((1+u)/2)/(1-u):-.5)+o/(1+u));return[a*e*cn(n),a*i]}var t=fn(n/2),o=2*on(rn(n/2))/(t*t);return r.invert=function(r,t){var u,a=i(r*r+t*t),c=-n/2,f=50;if(!a)return[0,0];do{var l=c/2,v=rn(l),g=cn(l),s=fn(l),d=on(1/v);c-=u=(2/s*d-o*s-a)/(-d/(g*g)+1-o/(2*v*v))}while(Z(u)>ln&&--f>0);var p=cn(c);return[nn(r*p,a*rn(c)),e(t*p/a)]},r}function s(){var n=sn,t=r.geoProjectionMutator(g),e=t(n);return e.radius=function(r){return arguments.length?t(n=r*Mn):n*wn},e.scale(173).clipAngle(148)}function d(n){function r(n,r){var a=rn(r),c=rn(n/=2);return[(1+a)*cn(n),(o*r>-nn(c,i)-.001?0:10*-o)+u+cn(r)*e-(1+a)*t*c]}var t=cn(n),e=rn(n),o=n>=0?1:-1,i=fn(o*n),u=(1+t-e)/2;return r.invert=function(n,r){var a=0,c=0,f=50;do{var l=rn(a),v=cn(a),g=rn(c),s=cn(c),d=1+g,p=d*v-n,h=u+s*e-d*t*l-r,w=d*l/2,M=-v*s,R=t*d*v/2,y=e*g+t*l*s,P=M*R-y*w,j=(h*M-p*y)/P/2,A=(p*R-h*w)/P;a-=j,c-=A}while((Z(j)>ln||Z(A)>ln)&&--f>0);return o*c>-nn(rn(a),i)-.001?[2*a,c]:null},r}function p(){var n=20*Mn,t=n>=0?1:-1,e=fn(t*n),o=r.geoProjectionMutator(d),i=o(n),u=i.stream;return i.parallel=function(r){return arguments.length?(e=fn((t=(n=r*Mn)>=0?1:-1)*n),o(n)):n*wn},i.stream=function(r){var o=i.rotate(),a=u(r),c=(i.rotate([0,0]),u(r));return i.rotate(o),a.sphere=function(){c.polygonStart(),c.lineStart();for(var r=t*-180;t*r<180;r+=90*t)c.point(r,90*t);for(;t*(r-=n)>=-180;)c.point(r,t*-nn(rn(r*Mn/2),e)*wn);c.lineEnd(),c.polygonEnd()},a},i.scale(210).translate([480,353])}function h(n,r){var t=fn(r/2),e=i(1-t*t),o=1+e*rn(n/=2),u=cn(n)*e/o,a=t/o,c=u*u,f=a*a;return[4/3*u*(3+c-3*f),4/3*a*(3+3*c-f)]}function w(){return r.geoProjection(h).scale(63)}function M(n,r){var t=Z(r);return t<dn?[n,on(fn(dn+r/2))]:[n*rn(t)*(2*pn-1/cn(t)),an(r)*(2*pn*(t-dn)-on(fn(t/2)))]}function R(){return r.geoProjection(M).scale(110)}function y(n){function t(n,t){var o=r.geoAzimuthalEquidistantRaw(n,t);if(Z(n)>sn){var a=nn(o[1],o[0]),c=i(o[0]*o[0]+o[1]*o[1]),f=u*un((a-sn)/u)+sn,l=nn(cn(a-=f),2-rn(a));a=f+e(gn/c*cn(l))-l,o[0]=c*rn(a),o[1]=c*cn(a)}return o}var u=2*gn/n;return t.invert=function(n,t){var e=i(n*n+t*t);if(e>sn){var a=nn(t,n),c=u*un((a-sn)/u)+sn,f=a>c?-1:1,l=e*rn(c-a),v=1/fn(f*o((l-gn)/i(gn*(gn-2*l)+e*e)));a=c+2*$((v+f*i(v*v-3))/3),n=e*rn(a),t=e*cn(a)}return r.geoAzimuthalEquidistantRaw.invert(n,t)},t}function P(){var n=5,t=r.geoProjectionMutator(y),o=t(n),i=o.stream,u=.01,a=-rn(u*Mn),c=cn(u*Mn);return o.lobes=function(r){return arguments.length?t(n=+r):n},o.stream=function(r){var t=o.rotate(),f=i(r),l=(o.rotate([0,0]),i(r));return o.rotate(t),f.sphere=function(){l.polygonStart(),l.lineStart();for(var r=0,t=360/n,o=2*gn/n,i=90-180/n,f=sn;r<n;++r,i-=t,f-=o)l.point(nn(c*rn(f),a)*wn,e(c*cn(f))*wn),i<-90?(l.point(-90,-180-i-u),l.point(-90,-180-i+u)):(l.point(90,i+u),l.point(90,i-u));l.lineEnd(),l.polygonEnd()},f},o.scale(85).clipAngle(179.999).translate([480,275])}function j(n,r){var t,e=n*cn(r),o=30;do r-=t=(r+cn(r)-e)/(1+rn(r));while(Z(t)>ln&&--o>0);return r/2}function A(n,r,t){function o(e,o){return[n*e*rn(o=j(t,o)),r*cn(o)]}return o.invert=function(o,i){return i=e(i/r),[o/(n*rn(i)),e((2*i+cn(2*i))/t)]},o}function m(){return r.geoProjection(Pn).scale(165)}function C(n,r){var t=j(gn,r);return[jn*n/(1/rn(r)+An/rn(t)),(r+pn*cn(t))/jn]}function B(){return r.geoProjection(C)}function E(n){var t=0,e=r.geoProjectionMutator(n),o=e(t);return o.parallel=function(n){return arguments.length?e(t=n*Mn):t*wn},o}function S(n,r){return[n*rn(r),r]}function b(){return r.geoProjection(S)}function q(n){function r(r,e){var o=t+n-e,i=o?r*rn(e)/o:o;return[o*cn(i),t-o*rn(i)]}if(!n)return S;var t=1/fn(n);return r.invert=function(r,e){var o=i(r*r+(e=t-e)*e),u=t+n-o;return[o/rn(u)*nn(r,e),u]},r}function k(){return E(q).scale(120).translate([450,305]).parallel(45)}function x(n){function r(r,t){var e=sn-t,o=e?r*n*cn(e)/e:e;return[e*cn(o)/n,sn-e*rn(o)]}return r.invert=function(r,t){var e=r*n,o=sn-t,u=i(e*e+o*o),a=nn(e,o);return[(u?u/cn(u):1)*a/n,sn-u]},r}function z(){var n=.5,t=r.geoProjectionMutator(x),e=t(n);return e.fraction=function(r){return arguments.length?t(n=+r):n},e}function W(){return r.geoProjection(mn)}function _(n,r,t,u,a,c){var f,l=rn(c);if(Z(n)>1||Z(c)>1)f=o(t*a+r*u*l);else{var v=cn(n/2),g=cn(c/2);f=2*e(i(v*v+r*u*g*g))}return Z(f)>ln?[f,nn(u*cn(c),r*a-t*u*l)]:[0,0]}function I(n,r,t){return o((n*n+r*r-t*t)/(2*n*r))}function O(n){return n-2*gn*en((n+gn)/(2*gn))}function D(n,r,t,e,o,i){function u(n,r){var t,e=cn(r),o=rn(r),i=new Array(3);for(t=0;t<3;++t){var u=c[t];if(i[t]=_(r-u[1],u[3],u[2],o,e,n-u[0]),!i[t][0])return u.point;i[t][1]=O(i[t][1]-u.v[1])}var a=d.slice();for(t=0;t<3;++t){var f=2==t?0:t+1,l=I(c[t].v[0],i[t][0],i[f][0]);i[t][1]<0&&(l=-l),t?1==t?(l=g-l,a[0]-=i[t][0]*rn(l),a[1]-=i[t][0]*cn(l)):(l=s-l,a[0]+=i[t][0]*rn(l),a[1]+=i[t][0]*cn(l)):(a[0]+=i[t][0]*rn(l),a[1]-=i[t][0]*cn(l))}return a[0]/=3,a[1]/=3,a}for(var a,c=[[n,r,cn(r),rn(r)],[t,e,cn(e),rn(e)],[o,i,cn(i),rn(i)]],f=c[2],l=0;l<3;++l,f=a)a=c[l],f.v=_(a[1]-f[1],f[3],f[2],a[3],a[2],a[0]-f[0]),f.point=[0,0];var v=I(c[0].v[0],c[2].v[0],c[1].v[0]),g=I(c[0].v[0],c[1].v[0],c[2].v[0]),s=gn-v;c[2].point[1]=0,c[0].point[0]=-(c[1].point[0]=c[0].v[0]/2);var d=[c[2].point[0]=c[0].point[0]+c[2].v[0]*rn(v),2*(c[0].point[1]=c[1].point[1]=c[2].v[0]*cn(v))];return u}function F(){var n,t,e,o,i,u,a=r.geoProjectionMutator(D),c=a(),f=r.geoRotation(0,0),l=c.rotate,v=c.center;return delete c.rotate,delete c.center,c.points=function(c){if(!arguments.length)return[[n,t],[e,o],[i,u]];var g=[n=+c[0][0],t=+c[0][1]],s=[e=+c[1][0],o=+c[1][1]],d=[i=+c[2][0],u=+c[2][1]],p=r.geoCentroid({type:"MultiPoint",coordinates:[g,s,d]}),h=f.invert(v());return l(f=[-p[0],-p[1]]),f=r.geoRotation(f),g=f(g),s=f(s),d=f(d),v(f(h)),a(g[0]*Mn,g[1]*Mn,s[0]*Mn,s[1]*Mn,d[0]*Mn,d[1]*Mn)},c.center=function(n){return arguments.length?v(f(n)):f.invert(v())},c.points([[0,22],[45,22],[22.5,-22]]).center([22.5,0]).scale(450).clipAngle(90)}function G(n,r){var t=i(1-cn(r));return[2/hn*n*t,hn*(1-t)]}function H(){return r.geoProjection(G).scale(92)}function J(n){function r(n,r){return[n,(n?n/cn(n):1)*(cn(r)*rn(n)-t*rn(r))]}var t=fn(n);return r.invert=t?function(n,r){n&&(r*=cn(n)/n);var e=rn(n);return[n,2*nn(i(e*e+t*t-r*r)-e,t-r)]}:function(n,r){return[n,e(n?r*fn(n)/n:r)]},r}function K(){return E(J).scale(240).clipAngle(90)}function L(n,r){return[Cn*n*(2*rn(2*r/3)-1)/hn,Cn*hn*cn(r/3)]}function N(){return r.geoProjection(L)}function Q(n){function r(n,r){return[n*t,cn(r)/t]}var t=rn(n);return r.invert=function(n,r){return[n/t,e(r*t)]},r}function T(){return E(Q).parallel(38.58).scale(196)}function U(n){function r(n,r){return[n*t,(1+t)*fn(r/2)]}var t=rn(n);return r.invert=function(n,r){return[n/t,2*$(r/(1+t))]},r}function V(){return E(U).scale(120)}function X(n,r){var t=l(n,r);return[(t[0]+n/sn)/2,(t[1]+r)/2]}function Y(){return r.geoProjection(Bn).scale(150)}var Z=Math.abs,$=Math.atan,nn=Math.atan2,rn=Math.cos,tn=Math.exp,en=Math.floor,on=Math.log,un=Math.round,an=Math.sign||function(n){return n>0?1:n<0?-1:0},cn=Math.sin,fn=Math.tan,ln=1e-6,vn=1e-12,gn=Math.PI,sn=gn/2,dn=gn/4,pn=i(2),hn=i(gn),wn=180/gn,Mn=gn/180;l.invert=function(n,r){if(!(n*n+4*r*r>gn*gn+ln)){var t=n,e=r,u=25;do{var a,c=cn(t),f=cn(t/2),l=rn(t/2),v=cn(e),g=rn(e),s=cn(2*e),d=v*v,p=g*g,h=f*f,w=1-p*l*l,M=w?o(g*l)*i(a=1/w):a=0,R=2*M*g*f-n,y=M*v-r,P=a*(p*h+M*g*l*d),j=a*(.5*c*s-2*M*v*f),A=.25*a*(s*f-M*v*p*c),m=a*(d*l+M*h*g),C=j*A-m*P;if(!C)break;var B=(y*j-R*m)/C,E=(R*A-y*P)/C;t-=B,e-=E}while((Z(B)>ln||Z(E)>ln)&&--u>0);return[t,e]}},h.invert=function(n,r){if(n*=3/8,r*=3/8,!n&&Z(r)>1)return null;var t=n*n,o=r*r,l=1+t+o,v=i((l-i(l*l-4*r*r))/2),g=e(v)/3,s=v?f(Z(r/v))/3:c(Z(n))/3,d=rn(g),p=a(s),h=p*p-d*d;return[2*an(n)*nn(u(s)*d,.25-h),2*an(r)*nn(p*cn(g),.25+h)]};var Rn=i(8),yn=on(1+pn);M.invert=function(n,r){if((e=Z(r))<yn)return[n,2*$(tn(r))-sn];var t,e,o=dn,i=25;do{var u=rn(o/2),a=fn(o/2);o-=t=(Rn*(o-dn)-on(a)-e)/(Rn-u*u/(2*a))}while(Z(t)>vn&&--i>0);return[n/(rn(o)*(Rn-1/cn(o))),an(r)*o]};var Pn=A(pn/sn,pn,gn),jn=2.00276,An=1.11072;C.invert=function(n,r){var t,e,o=jn*r,i=r<0?-dn:dn,u=25;do e=o-pn*cn(i),i-=t=(cn(2*i)+2*i-gn*cn(e))/(2*rn(2*i)+2+gn*rn(e)*pn*rn(i));while(Z(t)>ln&&--u>0);return e=o-pn*cn(i),[n*(1/rn(e)+An/rn(i))/jn,e]},S.invert=function(n,r){return[n/rn(r),r]};var mn=A(1,4/gn,gn);G.invert=function(n,r){var t=(t=r/hn-1)*t;return[t>0?n*i(gn/t)/2:0,e(1-t)]};var Cn=i(3);L.invert=function(n,r){var t=3*e(r/(Cn*hn));return[hn*n/(Cn*(2*rn(2*t/3)-1)),t]},X.invert=function(n,r){var t=n,e=r,u=25;do{var a,c=rn(e),f=cn(e),l=cn(2*e),v=f*f,g=c*c,s=cn(t),d=rn(t/2),p=cn(t/2),h=p*p,w=1-g*d*d,M=w?o(c*d)*i(a=1/w):a=0,R=.5*(2*M*c*p+t/sn)-n,y=.5*(M*f+e)-r,P=.5*a*(g*h+M*c*d*v)+.5/sn,j=a*(s*l/4-M*f*p),A=.125*a*(l*p-M*f*g*s),m=.5*a*(v*d+M*h*c)+.5,C=j*A-m*P,B=(y*j-R*m)/C,E=(R*A-y*P)/C;t-=B,e-=E}while((Z(B)>ln||Z(E)>ln)&&--u>0);return[t,e]};var Bn=X;n.geoAitoff=v,n.geoAitoffRaw=l,n.geoAiry=s,n.geoAiryRaw=g,n.geoArmadillo=p,n.geoArmadilloRaw=d,n.geoAugust=w,n.geoAugustRaw=h,n.geoBaker=R,n.geoBakerRaw=M,n.geoBerghaus=P,n.geoBerghausRaw=y,n.geoBoggs=B,n.geoBoggsRaw=C,n.geoBonne=k,n.geoBonneRaw=q,n.geoBottomley=z,n.geoBottomleyRaw=x,n.geoBromley=W,n.geoBromleyRaw=mn,n.geoChamberlin=F,n.geoChamberlinRaw=D,n.geoCollignon=H,n.geoCollignonRaw=G,n.geoCraig=K,n.geoCraigRaw=J,n.geoCraster=N,n.geoCrasterRaw=L,n.geoCylindricalEqualArea=T,n.geoCylindricalEqualAreaRaw=Q,n.geoCylindricalStereographic=V,n.geoCylindricalStereographicRaw=U,n.geoMollweide=m,n.geoMollweideRaw=Pn,n.geoSinusoidal=b,n.geoSinusoidalRaw=S,n.geoWinkel3=Y,n.geoWinkel3Raw=Bn,Object.defineProperty(n,"__esModule",{value:!0})});
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.graticule {
fill: none;
stroke: #777;
stroke-width: 0.5px;
stroke-opacity: 0.5;
}
.land {
fill: #222;
}
.boundary {
fill: none;
stroke: #fff;
stroke-width: 0.5px;
}
</style>
<svg width="960" height="611"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="d3-geo-projection.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var projection = d3.geoCylindricalStereographic()
.scale(153)
.translate([width / 2, height / 2])
.precision(0.1);
var path = d3.geoPath()
.projection(projection);
var graticule = d3.geoGraticule();
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
svg.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere")
.attr("d", path)
.attr("fill", "none")
.attr("stroke", "black");
d3.json("/mbostock/raw/4090846/world-50m.json", function(error, world) {
if (error) throw error;
svg.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", path);
svg.insert("path", ".graticule")
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
.attr("class", "boundary")
.attr("d", path);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment