JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<button>Toggle Projection</button>

CSS

body {
  padding:0;
  margin:0;
}
.foreground {
  fill: none;
  stroke: #000;
  stroke-width: 1px;
  pointer-events: all;
  cursor: -webkit-grab;
  cursor: -moz-grab;
}
.foreground.dragging {
  cursor: -webkit-grabbing;
  cursor: -moz-grabbing;
}

.state-mesh {
  stroke:#BABFA1;
  fill:transparent;
}
.graticule {
  stroke: #E3E3E3;
  fill: transparent;
}
.land {
  fill: #4D4C33;
}
.jelly {
  fill: rgba(0, 0, 255, 0.1);
}
button {
  position: absolute;
  display: block;
  background: #ff0000;
  color: white;
  bottom: 30px;
  right: 30px;
  border: 0;
  outline: 0;
  cursor: pointer;
}

JavaScript

var app = {
  orthographic: 1
};


function bootstrapApplication(world) {
  app.d3win = d3.select(window);
  app.width = window.innerWidth;
  app.height = window.innerHeight;

  app.svg = d3.select('body')
    .append('svg')
    .attr('width', app.width)
    .attr('height', app.height)
    .on('mousedown', function() {
      d3.select(this).classed('dragging', true);
    })
    .on('mouseup', function() {
      d3.select(this).classed('dragging', false);
    });;

  app.g = app.svg.append('g');

  app.projection = ortho2Equi();
  // app.projection = orthographic();

  app.path = d3.geo.path().projection(app.projection);

  app.g.append('path')
    .datum(d3.geo.graticule())
    .attr('class', 'graticule')
    .attr('d', app.path);

  app.g.append('path')
    .datum({
      type: 'Sphere'
    })
    .attr('class', 'jelly foreground')
    .attr('d', app.path);

  app.g.append('path')
    .datum(topojson.feature(world, world.objects.land))
    .attr('class', 'land foreground')
    .attr('d', app.path);

  app.g.append('path')
    .datum(topojson.mesh(world, world.objects.countries))
    .attr('class', 'state-mesh foreground')
    .attr('d', app.path)

  app.g.call(setupDrag());

  app.paths = app.svg.selectAll("path");

  d3.select('button').on('click', function() {
    app.svg.transition()
      .duration(2000)
      .tween("projection", function() {
        return function(_) {
          app.projection.alpha(_);
          app.paths.attr("d", app.path);
        };
      })
      .transition()
      .each('end', function() {
        app.projection = app.orthographic ? equi2ortho() : ortho2Equi();
        app.path.projection(app.projection);
        alert('ended');
      })

    app.orthographic = !app.orthographic;
  });
}

function interpolatedProjection(a, b) {
  var projection = d3.geo.projection(raw)
    .scale(1);

  var center = projection.center;
  var clip = projection.clipAngle;
  var translate = projection.translate;
  var α;

  function raw(λ, φ) {
   ...