Skip to content

Instantly share code, notes, and snippets.

@easadler
Last active March 17, 2017 03:05
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 easadler/d66f761a9c6df4d8c6bf3de6a0fbbe41 to your computer and use it in GitHub Desktop.
Save easadler/d66f761a9c6df4d8c6bf3de6a0fbbe41 to your computer and use it in GitHub Desktop.
Tobler Projection
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/2.2.0/topojson.js">
</script>
<script>module={}</script>
<script src="https://unpkg.com/integrate-adaptive-simpson/index.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var abs = Math.abs,
pi = Math.pi,
sign = Math.sign,
sin = Math.sin,
pow = Math.pow
epsilon = 0.00001
function toblerY(phi, alpha, gamma, k) {
var y=0.01, i = 30, delta;
do {
y -= delta = (sin(phi) - alpha * y + ((alpha - 1) / gamma) * integrate((y) => elipticFunc(y, gamma, k),0, y,1e-4)) / (((alpha - 1) / gamma) * elipticFunc(y, gamma, k) - alpha);
if (y >= gamma) { y = gamma; break };
if (y <= 0) { y = 0; break } ;
}
while (abs(delta) > epsilon && --i > 0);
return y;
}
function toblerRaw(alpha, gamma, k) {
function forward(lambda, phi) {
return [(alpha + ((1- alpha) / gamma) * elipticFunc(y = toblerY(abs(phi), alpha, gamma, k), gamma, k)) * lambda * 0.8679, sign(phi) * y / 0.8679]
}
return forward;
}
var tobler = function() {
return d3.geoProjection(toblerRaw(0, 1.183136, 2.5))
}
function elipticFunc(y, gamma, k) {
if (y >= gamma) { return 0 };
if (y <= 0) { return gamma };
return pow((pow(gamma, k) - pow(y, k)) , 1.0 / k);
}
function toblerIntegrate(f, a, b) {
var n = 54,
h = (b - a) / n,
s = f(a) + f(b);
for (var i = 1; i < n; i+=2) s += 2 * f(a + i * h);
for (var i = 1; i < n - 1; i+=2) s += 4 * f(a + i * h);
return s * h / 3;
}
var width = 960,
height = 500;
var projection = tobler()
.translate([width / 2, height / 2])
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
var path = d3.geoPath()
.projection(projection.precision(0.1))
.context(context);
d3.json("https://gist.githubusercontent.com/abenrob/787723ca91772591b47e/raw/8a7f176072d508218e120773943b595c998991be/world-50m.json",
function(error, world) {
if (error) throw error;
var land = topojson.feature(world, world.objects.land),
graticule = d3.geoGraticule(),
outline = {type: "Sphere"};
context.fillStyle = "#fff";
context.fillRect(0, 0, width, height);
context.save();
context.beginPath();
path(graticule());
context.strokeStyle = "rgba(119,119,119,0.5)";
context.stroke();
context.beginPath();
path(land);
context.fillStyle = "#000";
context.fill();
context.restore();
context.beginPath();
path(outline);
context.strokeStyle = "#000";
context.stroke();
});
d3.select(self.frameElement).style("height", height + "px");
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment