block by syntagmatic 2478722

Projection Demo

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Selectable Projection Demo</title>
    <script src='//mbostock.github.com/d3/d3.v2.js'></script>
    <script src='demo.js'></script>

    <style>
circle {
  fill-opacity: 0.5;
}

circle.left {
  fill:           #005982;
}

circle.right {
  fill:           #971c20;
}

path.connect {
  fill:           none;
  stroke-width:   1.2;
  stroke-opacity: 0.25;
  stroke: #aaa;
}
    </style>
  </head>

  <body>
    <select id='proj-left'>
      <option value='albers'>Albers</option>
      <option value='mercator'>Mercator</option>
      <option value='stereo'>Stereo</option>
      <option value='bonne'>Bonne</option>
      <option value='equirectangular'  selected=selected>Equirectangular</option>
      <option value='ortho'>Orthographic</option>
    </select>
    <select id='proj-right'>
      <option value='albers'>Albers</option>
      <option value='stereo'>Stereo</option>
      <option value='bonne'>Bonne</option>
      <option value='ortho' selected=selected>Orthographic</option>
    </select>
    <div id='chart'></div>
  </ul>
  </body>
</html>

demo.js

// demo.js
//
// Adapted by Kai Chang and Rich Morin from http://bl.ocks.org/1653763

window.onload = function() {

  proj = {
    'albers':     d3.geo.albers()  .scale( 50),
    'mercator':   d3.geo.mercator().scale(280),
    'bonne': d3.geo.bonne().scale(60),
    'equirectangular': d3.geo.equirectangular().scale(360),
    'ortho':
      d3.geo.azimuthal()
        .scale(140)
        .origin([-71.03, 0])
        .mode('orthographic'),
    'stereo':
      d3.geo.azimuthal()
        .scale(80)
        .origin([-71.03, 0])
        .mode('stereographic')
  };

  var connections,
      delay   = 1500,
      drawn   = {},
      h       = 220,
      w       = 580;

  var svg = d3.select('#chart')
              .append('svg:svg');

  var points = [];
  for (var lon = -180; lon < 180; lon += 10) {
    for (var lat = -90; lat < 90; lat += 10) { points.push([lon, lat]); }
  }

  state = {
    'left': 'equirectangular',
    'right': 'ortho'
  };

  var line = function(d) {
    return  'M' + proj[ state['left' ] ](d).join(' ') +
            'L' + proj[ state['right'] ](d).join(' ') +  'z';
  };

  var setup = function() {

    for (var side in state) {
      item          = state[side];
      circle_patt   = 'circle.' + side;

      drawn[side]   = svg.selectAll(circle_patt)
                        .data(points).enter()
                        .append('svg:circle')
                        .attr("r", 1.5);
    }

    connections = svg.selectAll('path.connect')
      .data(points).enter()
      .append('svg:path')
      .attr('class', 'connect')
      .attr('d', line);

    var do_dots = function() {
      for (var side in state) {
        item  = state[side];

        var transform = function(d) {
          return 'translate(' + proj[item](d).join(',') + ')';
        };

        drawn[side].attr('class', side).attr('transform', transform);
      }
    };


    var mouse_move = function() {
      var x = ((d3.event.pageX / w) * 360) - 180;
      var y = ((d3.event.pageY / h) * 360) - 180;

      proj[ state['right'] ].origin([x, y]);
      do_dots();
      connections.attr('d', line);
    };

    svg.on('mousemove', mouse_move);

    do_dots();
  };

  var transition = function(side) {
    var item = state[side];

    var transform = function(d) {
      return 'translate(' + proj[item](d).join(',') + ')';
    };

    drawn[side]
      .transition().duration(delay)
      .attr('transform', transform);

    connections
      .transition().duration(delay)
      .attr('d', line);
  };

  var change = function(side, val) {
    state[side] = val;
    transition(side);
  };

  d3.select('#proj-left').on('change', function() { change('left', this.value) });
  d3.select('#proj-right').on('change', function() { change('right', this.value) });

  setup();
};