block by samselikoff 9422682

OpenStreetMap + d3 tiles + brush slider

Full Screen

index.html

<html>
  <meta charset="utf-8">
  <style>
    body {
      width: 960px;
      margin: 0 auto;
    } 
    .map {
      width: 100%;
      height: 400px;
    }

    path {
      fill: none;
      stroke: #000;
      stroke-linejoin: round;
      stroke-linecap: round;
    }

    .major_road { stroke: #776; }
    .minor_road { stroke: #ccb; }
    .highway { stroke: #666; stroke-width: 1.5px; }
    .rail { stroke: #999; }

    .water, .ocean, .riverbank { 
      fill: #C7DBFF; 
      stroke: none;
    }

    .tick line {
      stroke: black;
    }
    .tick text {
      font-size: 10px;
    }
  </style>
  <body>
    <div class="map"></div>
    <div class="controls"></div>
  </body>    
  <script src="//d3js.org/d3.v3.min.js"></script>
  <script src="//d3js.org/d3.geo.tile.v0.min.js"></script>
  <script>
    /*
      Map
    */
    var width = 960,
        height = 500;

    var tiler = d3.geo.tile()
        .size([width, height]);

    var center = [-71.07, 42.355];

    var projection = d3.geo.mercator()
        .center(center)
        .scale((1 << 22) / 2 / Math.PI)
        .translate([width / 2, height / 2]);

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

    var w = d3.select('.map').style('width').replace('px',''),
        h = d3.select('.map').style('height').replace('px','');

    var svg = d3.selectAll('.map').append('svg')
        .attr('width', w)
        .attr('height', h);

    svg.selectAll('g')
        .data(tiler
          .scale(projection.scale() * 2 * Math.PI)
          .translate(projection([0, 0])))
      .enter().append('g')
        .each(function(d) {
          var g = d3.select(this);
          // d3.json('//' + ['a', 'b', 'c'][(d[0] * 31 + d[1]) % 3] + '.tile.openstreetmap.us/vectiles-water-areas/' + d[2] + '/' + d[0] + '/' + d[1] + '.json', function(error, json) {
          d3.json('//' + ['a', 'b', 'c'][(d[0] * 31 + d[1]) % 3] + '.tile.openstreetmap.us/vectiles-all/' + d[2] + '/' + d[0] + '/' + d[1] + '.json', function(error, json) {

            // Water areas 
            g.selectAll('path')
                .data(json["water-areas"].features.sort(function(a, b) { return a.properties.sort_key - b.properties.sort_key; }))
              .enter().append('path')
                .attr('class', function(d) { return d.properties.kind; })
                .attr('d', path);

            // Highroads
            g.selectAll('path')
                .data(json["highroad"].features.sort(function(a, b) { return a.properties.sort_key - b.properties.sort_key; }))
              .enter().append('path')
                .attr('class', function(d) { return d.properties.kind; })
                .attr('d', path);

          });
        });

    // Features
    d3.json('points.json', function(err, raw) {

      // Add dummy data for force, angle, quality
      var data = raw;
      data.points.forEach(function(p) {
        p.angle = Math.floor(Math.random() * 360) + 1;
        p.force = Math.floor(Math.random() * 10) + 1;
        p.quality = Math.floor(Math.random() * 10) + 1;
      });

      d3.selectAll('svg')
          .selectAll('.sensor')
          .data(data.points)
        .enter()
          .append('g')
          .attr('class', function(d, i) {return 'sensor ' + i;})
          .attr('transform', function(d) {return 'translate(' + projection(d.coordinates)[0] + ',' + projection(d.coordinates)[1] + ')';});

      var colors = {
        worst: '#fee6ce',
        middle: '#fdae6b',
        best: '#e6550d'
      };

      /*
        Bubbles + slider
      */
      var line = d3.svg.line(),
          x = function(d) {return d.force*5 * Math.cos(d.angle * (Math.PI/180));},
          y = function(d) {return d.force*5 * Math.sin(d.angle * (Math.PI/180));};

      var wind = d3.selectAll('.sensor')
          .append('circle')
          .attr('class', 'area')
          .attr('r', function(d) {return d.force * 2;})
          .style('fill', function(d) {
            return d.quality < 4 ? colors.worst : (d.quality < 8 ? colors.middle : colors.best);
          })
          .style('opacity', 0.8)
          ;

      var parse = d3.time.format("%X %x").parse,
          formatter = d3.time.format('%I %p');

      var domain = ['08:00:00 03/06/2014', '18:00:00 03/06/2014'],
          xScale = d3.time.scale()
            .domain([parse(domain[0]), parse(domain[1])])
            .range([0, 500])
            .clamp(true),
          xAxis = d3.svg.axis().scale(xScale)
            .tickFormat(function(d) {
              var t = formatter(d);
              return t.charAt(0) == '0' ? t.substring(1) : t;
            });


      var g = d3.select('.controls').append('svg').append("g")
              .attr("transform", "translate(30,40)");

      g.append('g').attr('class', 'x axis').call(xAxis);

      var brush = d3.svg.brush()
        .x(xScale)
        .extent([0, 0])
        .on("brush", brushed)
        ;

      var height = 40;

      var slider = g.append("g")
          .attr("class", "slider")
          .attr('transform', 'translate(0,'+(-height/2)+')')
          .call(brush);

      slider.selectAll(".extent,.resize")
          .remove();

      slider.select(".background")
          .attr("height", height);

      var handle = slider.append("circle")
        .attr("class", "handle")
        .attr("transform", "translate(0," + height / 2 + ")")
        .attr("r", 5);

      slider.on('mousemove', function() {
        var value = xScale.invert(d3.mouse(this)[0]),
            nearestHour = d3.time.hour.round(value);

        brush.extent([nearestHour, nearestHour]);
        brushed();
      });

      var lastHour;

      function brushed() {
        var nearestHour = d3.time.hour.round(brush.extent()[0]);
        brush.extent([nearestHour, nearestHour]);

        if (+nearestHour !== +lastHour) {
          lastHour = nearestHour;
          handle.attr("cx", xScale(nearestHour));
          d3.selectAll('.map circle').attr('r', function(d) {return d.force*Math.random()*4;});
        }
      }
    });
  </script>
</html>

points.json

{
  "points": [
    {
      "coordinates": [-71.08695301055909,42.351447955911695]
    },
    {
      "coordinates": [-71.08343395233155,42.35246284613574]
    },
    {
      "coordinates": [-71.07905658721924,42.35360457804949]
    },
    {
      "coordinates": [-71.07493671417237,42.35480971701297]
    },
    {
      "coordinates": [-71.07219013214112,42.35874211499499]
    },
    {
      "coordinates": [-71.07064517974854,42.361025329932644]
    },
    {
      "coordinates": [-71.06798442840577,42.36660617273091]
    },
    {
      "coordinates": [-71.06446537017823,42.3660988438709]
    },
    {
      "coordinates": [-71.06326374053955,42.366542756847466]
    },
    {
      "coordinates": [-71.06000217437744,42.36597201101572]
    },
    {
      "coordinates": [-71.05768474578858,42.363625557007076]
    },
    {
      "coordinates": [-71.05296405792237,42.36051795600514]
    },
    {
      "coordinates": [-71.056139793396,42.36235716699952]
    },
    {
      "coordinates": [-71.05768474578858,42.361596120703894]
    },
    {
      "coordinates": [-71.05665477752687,42.35899580964063]
    },
    {
      "coordinates": [-71.05948719024659,42.35931292650732]
    },
    {
      "coordinates": [-71.0645512008667,42.352335985753925]
    },
    {
      "coordinates": [-71.05819972991944,42.35239941597684]
    },
    {
      "coordinates": [-71.05150493621827,42.35487314473933]
    },
    {
      "coordinates": [-71.05193408966065,42.359439772805864]
    },
    {
      "coordinates": [-71.05090412139893,42.36242058710804]
    },
    {
      "coordinates": [-71.05201992034914,42.36673300430575]
    },
    {
      "coordinates": [-71.05631145477297,42.36825496323038]
    },
    {
      "coordinates": [-71.05819972991944,42.35220912511607]
    },
    {
      "coordinates": [-71.05957302093506,42.35005245509584]
    },
    {
      "coordinates": [-71.0605171585083,42.3465001313957]
    },
    {
      "coordinates": [-71.05665477752687,42.34643669521955]
    },
    {
      "coordinates": [-71.0619762802124,42.342884167190505]
    },
    {
      "coordinates": [-71.06841358184815,42.347578536596444]
    }
  ]
}