block by fil 4db96f1250ad6118290e24d62e67187d

Foucaut projections (1862)

Full Screen

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:

index.html

<!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>