block by syntagmatic 2041223

Selectable 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='//code.jquery.com/jquery-1.7.1.min.js'></script>
    <script src='demo.js'></script>

    <link rel="stylesheet" type="text/css" href="demo.css" />
  </head>

  <body>
    <ul>
    <h2><span id='account-name'></span></h2>
    <h1>Selectable Projection</h1>
    <p>
      Map projections are transformations between one shape to another,
      often a 2D surface such as a screen or printout.
      A selectable pair of projections is shown below,
      along with a mapping of points -
      every 10 degrees latitude and longitude - between the two.
    </p><p>
      This demo is made with <a href='//mbostock.github.com/d3/'>D3</a>,
      Mike Bostock's DOM-based visualization framework.
      It was adapted, via <a href='//bl.ocks.org/2005817'
                     >Albers to Orthographic Projection</a>,
      from <a href='//bl.ocks.org/1653763'
             >Mercator to Orthographic Projection</a>.
    </p>

    <select id='proj'>
      <option value='albers'  >Albers</option>
      <option value='mercator'>Mercator</option>
      <option value='stereo'  >Stereo</option>
    </select>
    <p/>
    <div id='chart'></div>
  </ul>
  </body>
</html>

demo.css

/* demo.css */

body {
  margin:         5px auto;
}

#chart svg {
  border:         solid 1px #ccc;
}

h1 {
  font:           20px/20px "Helvetica Neue";
  margin:         0;
}

p {
  color:          #333;
  font:           12px/15px "Helvetica Neue";
}

circle.left {
  fill:           #005982;
}

circle.right {
  fill:           #971c20;
}

path.connect {
  fill:           none;
  stroke-width:   0.2;
  stroke:         #aaa;
}

demo.js

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


window.onload = function() {

  // Set up some objects for the session.

  proj = {
    'albers':     d3.geo.albers()  .scale( 50).translate([180, 220]),
    'mercator':   d3.geo.mercator().scale(280).translate([180, 140]),

    'ortho':
      d3.geo.azimuthal()
        .scale(140)
        .origin([-71.03, 0])
        .mode('orthographic')
        .translate([600, 160]),

    'stereo':
      d3.geo.azimuthal()
        .scale(80)
        .origin([-71.03, 0])
        .mode('stereographic')
        .translate([200, 180])
  };

  function pf(key) { return function() { return key; }; }

  attrs = {};
  for (var key in proj) {
    attrs[key] = { r: 1,  transform: pf(key) };
  }

  var connections,
      delay   = 1500,
      drawn   = {},
      h       = 320,
      w       = 780;

  var svg = d3.select('#chart').append('svg:svg')
    .attr('width',  w)
    .attr('height', h);

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

  todo = { 'left': 'albers',  'right': 'ortho' };

  // Set up some functions.

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


  var set_attrs = function(object, hash) {
    for (var key in hash) { object.attr(key, hash[key]); }
  };


  var setup = function() {

    attrs_connect = { 'class': 'connect',  'd': line };

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

      drawn[side]   = svg.selectAll(circle_patt)
                        .data(points).enter()
                        .append('svg:circle')
                        .call(set_attrs, attrs[item]);
    }

    connections = svg.selectAll('path.connect')
      .data(points).enter()
      .append('svg:path')
      .call(set_attrs, attrs_connect);


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

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

        drawn[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[ todo['right'] ].origin([x, y]);
      do_dots();
      connections.attr('d', line);
    };

    svg.on('mousemove', mouse_move);

    proj[ todo['right'] ].origin([0, 0]);
    do_dots();
  };


  var transition_left = function() {
    var item = todo['left'];

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

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

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


  var change = function() {
    todo['left'] = this.value;
    transition_left();
  };

  $('select').bind('change', change);

  setup();
};