Skip to content

Instantly share code, notes, and snippets.

@Fil
Last active October 31, 2018 13:33
Show Gist options
  • Save Fil/4db96f1250ad6118290e24d62e67187d to your computer and use it in GitHub Desktop.
Save Fil/4db96f1250ad6118290e24d62e67187d to your computer and use it in GitHub Desktop.
Foucaut projections (1862)
license: gpl-3.0

Foucaut projections (1862), according to Waldo Tobler (1973).

Parameter alpha between 0 (sinusoidal projection) and 1 (Lambert cylindrical projection).

Initial research by Philippe Rivière for d3-geo-projection issue #66.

Note that this is the easy part of #66 :)


References:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #e6e6d5;
}
.stroke {
fill: none;
stroke: #000;
stroke-width: 3px;
}
.fill {
fill: #fff;
}
.graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .5;
}
.land {
fill: #222;
}
.boundary {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<!-- dat.gui -->
<script src="https://unpkg.com/dat.gui/build/dat.gui.min.js"></script>
<link rel="stylesheet" href="https://raw.githack.com/liabru/dat-gui-light-theme/master/dat-gui-light-theme.css"/>
<script>
function gui(opts, redraw, config) {
var gui = new dat.GUI(config.options || {});
for (var i in opts) {
add(gui, opts, i);
}
function add(src, o, t) {
if (typeof o[t] == 'object') {
var group = src.addFolder(t);
for (var j in o[t]) {
add(group, o[t], j);
}
} else {
var control = (t.match(/color/i))
? src.addColor(o, t)
: src.add(o, t);
if (config.listen) control.listen();
if (redraw) control.onChange(redraw);
}
}
}
</script>
<!-- /dat.gui -->
<script>
d3.json("https://unpkg.com/visionscarto-world-atlas/world/110m.json", function (error, world) {
if (error) throw error;
var width = 960,
height = 480;
var graticule = d3.geoGraticule();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var defs = svg.append("defs");
defs.append("path")
.datum({
type: "Sphere"
})
.attr("id", "sphere");
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)");
svg.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("clip-path", "url(#clip)");
svg.insert("path", ".graticule")
.datum(topojson.mesh(world, world.objects.countries, function (a, b) {
return a !== b;
}))
.attr("class", "boundary")
.attr("clip-path", "url(#clip)");
var opts = { alpha: 0.5 };
gui(opts, redraw, {});
redraw();
function redraw() {
var alpha = opts.alpha = Math.min(opts.alpha,1),
beta = 1.0 - alpha;
var equatorial = foucaultraw(Math.PI, 0)[0] - foucaultraw(-Math.PI, 0)[0];
var polar = foucaultraw(0, Math.PI / 2)[1] - foucaultraw(0, -Math.PI / 2)[1];
var ratio = Math.sqrt(2 * polar / equatorial);
console.log('ratio', ratio, polar, equatorial)
function foucaultraw(lambda, phi) {
var cosphi = Math.cos(phi),
sinphi = Math.sin(phi);
return [
cosphi / (beta + alpha * cosphi) * lambda,
(beta * phi + alpha * sinphi)
];
}
function foucault(lambda, phi) {
var p = foucaultraw(lambda, phi);
return [ p[0] * ratio, p[1] / ratio ];
}
var projection = d3.geoProjection(foucault)
.rotate([-10.5])
.fitExtent([[10, 10], [width - 30, height - 10]], {
type: "Sphere"
});
var path = d3.geoPath()
.projection(projection);
svg.selectAll('path').attr("d", path);
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment