block by bycoffe 5349287

Using topojson.mesh to toggle between congressional districts and counties.

Full Screen

index.html

<!doctype html>
<meta charset="utf-8">
<html>
  <head>

    <style type="text/css">
      #map {
        width: 600px;
        height: 500px;
      }
      path.county {
        stroke-width: 1;
        fill: #999;
        stroke: #999;
      }
      path.county.dem {
        fill: #5c6b95;
        stroke: #5c6b95;
      }
      path.county.gop {
        fill: #bc5c5c;
        stroke: #bc5c5c;
      }
      path.county.selected {
        stroke: #fff;
      }
      path.district-mesh {
        stroke-width: 1.5;
        stroke: #fff;
        fill: none;
      }
      path.county-mesh {
        opacity: 0;
        stroke-width: 1.5;
        stroke: #fff;
        fill: none;
      }
      #county-toggle {
        cursor: pointer;
      }
    </style>

  </head>

  <body>

    <button id="county-toggle">show counties</button>
    <div id="map"></div>

    <script src="//underscorejs.org/underscore-min.js"></script>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="//d3js.org/topojson.v1.js"></script>
    <script src="//d3js.org/queue.v1.min.js"></script>
    <script type="text/javascript" src="main.js"></script>

  </body>
</html>

house_results_2012.csv

district,county,candidate,party,votes
1,Beaufort,Tim Scott,REP,40460
1,Berkeley,Tim Scott,REP,36875
1,Charleston,Tim Scott,REP,72120
1,Colleton,Tim Scott,REP,540
1,Dorchester,Tim Scott,REP,29913
1,Beaufort,Keith Blandford,LIB,1218
1,Berkeley,Keith Blandford,LIB,1133
1,Charleston,Keith Blandford,LIB,3009
1,Colleton,Keith Blandford,LIB,9
1,Dorchester,Keith Blandford,LIB,965
1,Beaufort,Bobbie Rose,DEM,23040
1,Berkeley,Bobbie Rose,DEM,17297
1,Charleston,Bobbie Rose,DEM,42766
1,Colleton,Bobbie Rose,DEM,97
1,Dorchester,Bobbie Rose,DEM,14954
1,Beaufort,Bobbie Rose,WFM,1448
1,Berkeley,Bobbie Rose,WFM,1195
1,Charleston,Bobbie Rose,WFM,1776
1,Colleton,Bobbie Rose,WFM,2
1,Dorchester,Bobbie Rose,WFM,982
1,Beaufort,Write-In,NON,38
1,Berkeley,Write-In,NON,53
1,Charleston,Write-In,NON,97
1,Colleton,Write-In,NON,1
1,Dorchester,Write-In,NON,25
2,Aiken,Joe Wilson,REP,49155
2,Barnwell,Joe Wilson,REP,5490
2,Lexington,Joe Wilson,REP,86210
2,Orangeburg,Joe Wilson,REP,4643
2,Richland,Joe Wilson,REP,50618
2,Aiken,Write-In,NON,1388
2,Barnwell,Write-In,NON,59
2,Lexington,Write-In,NON,2550
2,Orangeburg,Write-In,NON,83
2,Richland,Write-In,NON,3522
3,Abbeville,Jeff Duncan,REP,5763
3,Anderson,Jeff Duncan,REP,47860
3,Edgefield,Jeff Duncan,REP,6429
3,Greenville,Jeff Duncan,REP,12894
3,Greenwood,Jeff Duncan,REP,16529
3,Laurens,Jeff Duncan,REP,15648
3,McCormick,Jeff Duncan,REP,2436
3,Newberry,Jeff Duncan,REP,1826
3,Oconee,Jeff Duncan,REP,21784
3,Pickens,Jeff Duncan,REP,33483
3,Saluda,Jeff Duncan,REP,4860
3,Abbeville,Brian Ryan B Doyle,DEM,4512
3,Anderson,Brian Ryan B Doyle,DEM,21649
3,Edgefield,Brian Ryan B Doyle,DEM,4798
3,Greenville,Brian Ryan B Doyle,DEM,8240
3,Greenwood,Brian Ryan B Doyle,DEM,11330
3,Laurens,Brian Ryan B Doyle,DEM,9224
3,McCormick,Brian Ryan B Doyle,DEM,2608
3,Newberry,Brian Ryan B Doyle,DEM,1080
3,Oconee,Brian Ryan B Doyle,DEM,7655
3,Pickens,Brian Ryan B Doyle,DEM,10339
3,Saluda,Brian Ryan B Doyle,DEM,3300
3,Abbeville,Write-In,NON,10
3,Anderson,Write-In,NON,128
3,Edgefield,Write-In,NON,12
3,Greenville,Write-In,NON,30
3,Greenwood,Write-In,NON,63
3,Laurens,Write-In,NON,18
3,McCormick,Write-In,NON,5
3,Newberry,Write-In,NON,0
3,Oconee,Write-In,NON,103
3,Pickens,Write-In,NON,138
3,Saluda,Write-In,NON,9
4,Greenville,Trey Gowdy,REP,108336
4,Spartanburg,Trey Gowdy,REP,64865
4,Greenville,Deb Morrow,DEM,51075
4,Spartanburg,Deb Morrow,DEM,33012
4,Greenville,Deb Morrow,WFM,3764
4,Spartanburg,Deb Morrow,WFM,2113
4,Greenville,Jeff Sumerel,GRN,2563
4,Spartanburg,Jeff Sumerel,GRN,827
4,Greenville,Write-In,NON,219
4,Spartanburg,Write-In,NON,110
5,Cherokee,Mick Mulvaney,REP,12899
5,Chester,Mick Mulvaney,REP,6204
5,Fairfield,Mick Mulvaney,REP,3766
5,Kershaw,Mick Mulvaney,REP,15626
5,Lancaster,Mick Mulvaney,REP,19094
5,Lee,Mick Mulvaney,REP,2667
5,Newberry,Mick Mulvaney,REP,6928
5,Spartanburg,Mick Mulvaney,REP,4417
5,Sumter,Mick Mulvaney,REP,17350
5,Union,Mick Mulvaney,REP,6091
5,York,Mick Mulvaney,REP,59282
5,Cherokee,Joyce Knott,DEM,6575
5,Chester,Joyce Knott,DEM,6998
5,Fairfield,Joyce Knott,DEM,7202
5,Kershaw,Joyce Knott,DEM,10470
5,Lancaster,Joyce Knott,DEM,12021
5,Lee,Joyce Knott,DEM,5719
5,Newberry,Joyce Knott,DEM,5499
5,Spartanburg,Joyce Knott,DEM,1616
5,Sumter,Joyce Knott,DEM,17646
5,Union,Joyce Knott,DEM,5262
5,York,Joyce Knott,DEM,34896
5,Cherokee,Joyce Knott,WFM,702
5,Chester,Joyce Knott,WFM,610
5,Fairfield,Joyce Knott,WFM,366
5,Kershaw,Joyce Knott,WFM,1046
5,Lancaster,Joyce Knott,WFM,1155
5,Lee,Joyce Knott,WFM,219
5,Newberry,Joyce Knott,WFM,440
5,Spartanburg,Joyce Knott,WFM,347
5,Sumter,Joyce Knott,WFM,902
5,Union,Joyce Knott,WFM,605
5,York,Joyce Knott,WFM,3147
5,Cherokee,Write-In,NON,21
5,Chester,Write-In,NON,3
5,Fairfield,Write-In,NON,7
5,Kershaw,Write-In,NON,24
5,Lancaster,Write-In,NON,31
5,Lee,Write-In,NON,2
5,Newberry,Write-In,NON,8
5,Spartanburg,Write-In,NON,11
5,Sumter,Write-In,NON,38
5,Union,Write-In,NON,12
5,York,Write-In,NON,79
6,Allendale,James E Jim Clyburn,DEM,3455
6,Bamberg,James E Jim Clyburn,DEM,5554
6,Beaufort,James E Jim Clyburn,DEM,3666
6,Berkeley,James E Jim Clyburn,DEM,8050
6,Calhoun,James E Jim Clyburn,DEM,5407
6,Charleston,James E Jim Clyburn,DEM,29416
6,Clarendon,James E Jim Clyburn,DEM,12092
6,Colleton,James E Jim Clyburn,DEM,11743
6,Dorchester,James E Jim Clyburn,DEM,6485
6,Florence,James E Jim Clyburn,DEM,4673
6,Hampton,James E Jim Clyburn,DEM,7259
6,Jasper,James E Jim Clyburn,DEM,7428
6,Orangeburg,James E Jim Clyburn,DEM,28189
6,Richland,James E Jim Clyburn,DEM,62344
6,Sumter,James E Jim Clyburn,DEM,9166
6,Williamsburg,James E Jim Clyburn,DEM,13790
6,Allendale,Nammu Y Muhammad,GRN,114
6,Bamberg,Nammu Y Muhammad,GRN,375
6,Beaufort,Nammu Y Muhammad,GRN,212
6,Berkeley,Nammu Y Muhammad,GRN,492
6,Calhoun,Nammu Y Muhammad,GRN,887
6,Charleston,Nammu Y Muhammad,GRN,1762
6,Clarendon,Nammu Y Muhammad,GRN,1289
6,Colleton,Nammu Y Muhammad,GRN,934
6,Dorchester,Nammu Y Muhammad,GRN,516
6,Florence,Nammu Y Muhammad,GRN,294
6,Hampton,Nammu Y Muhammad,GRN,243
6,Jasper,Nammu Y Muhammad,GRN,461
6,Orangeburg,Nammu Y Muhammad,GRN,1248
6,Richland,Nammu Y Muhammad,GRN,2982
6,Sumter,Nammu Y Muhammad,GRN,298
6,Williamsburg,Nammu Y Muhammad,GRN,813
6,Allendale,Write-In,NON,19
6,Bamberg,Write-In,NON,23
6,Beaufort,Write-In,NON,35
6,Berkeley,Write-In,NON,70
6,Calhoun,Write-In,NON,196
6,Charleston,Write-In,NON,277
6,Clarendon,Write-In,NON,241
6,Colleton,Write-In,NON,151
6,Dorchester,Write-In,NON,86
6,Florence,Write-In,NON,38
6,Hampton,Write-In,NON,29
6,Jasper,Write-In,NON,49
6,Orangeburg,Write-In,NON,208
6,Richland,Write-In,NON,407
6,Sumter,Write-In,NON,42
6,Williamsburg,Write-In,NON,107
7,Chesterfield,Tom Rice,REP,8467
7,Darlington,Tom Rice,REP,14598
7,Dillon,Tom Rice,REP,5567
7,Florence,Tom Rice,REP,27380
7,Georgetown,Tom Rice,REP,16491
7,Horry,Tom Rice,REP,71462
7,Marion,Tom Rice,REP,5327
7,Marlboro,Tom Rice,REP,3776
7,Chesterfield,Gloria Bromell Tinubu,DEM,7249
7,Darlington,Gloria Bromell Tinubu,DEM,14479
7,Dillon,Gloria Bromell Tinubu,DEM,6313
7,Florence,Gloria Bromell Tinubu,DEM,22944
7,Georgetown,Gloria Bromell Tinubu,DEM,13243
7,Horry,Gloria Bromell Tinubu,DEM,35795
7,Marion,Gloria Bromell Tinubu,DEM,8998
7,Marlboro,Gloria Bromell Tinubu,DEM,5573
7,Chesterfield,Gloria Bromell Tinubu,WFM,504
7,Darlington,Gloria Bromell Tinubu,WFM,627
7,Dillon,Gloria Bromell Tinubu,WFM,742
7,Florence,Gloria Bromell Tinubu,WFM,999
7,Georgetown,Gloria Bromell Tinubu,WFM,824
7,Horry,Gloria Bromell Tinubu,WFM,3314
7,Marion,Gloria Bromell Tinubu,WFM,445
7,Marlboro,Gloria Bromell Tinubu,WFM,340
7,Chesterfield,Write-In,NON,20
7,Darlington,Write-In,NON,19
7,Dillon,Write-In,NON,5
7,Florence,Write-In,NON,43
7,Georgetown,Write-In,NON,12
7,Horry,Write-In,NON,167
7,Marion,Write-In,NON,8
7,Marlboro,Write-In,NON,7

main.js

;(function() {

  var countyWinner = function(results) {
      return _(results).sortBy(function(d) {
        return parseInt(d.votes)*-1;
      })[0];
    },

    districtWinner = function(district) {
      return {"01": "gop",
              "02": "gop",
              "03": "gop",
              "04": "gop",
              "05": "gop",
              "06": "dem",
              "07": "gop"}[district];
    },

    colors = {
      "gop": "#bc5c5c",
      "REP": "#bc5c5c",
      "dem": "#5c6b95",
      "DEM": "#5c6b95"
    };

  var drawMap = function(topology, resultsByCounty) {
    var districtMesh = topojson.mesh(topology, topology.objects['sc-district-counties'], function(a, b) {
      return a.properties.district !== b.properties.district;
    });

    var countyMesh = topojson.mesh(topology, topology.objects['sc-district-counties'], function(a, b) {
      return a.properties.county !== b.properties.county;
    });


    var width = 600,
        height = 500,
        center = {
          x: 32.789,
          y: -79.941
        },

        projection = d3.geo.mercator()
                          .center([center.y, center.x])
                          .translate([(width/2)+50, (height/2)+50])
                          .scale(width * 9),

        path = d3.geo.path().projection(projection),

        svg = d3.select("#map").append("svg").attr({
                    width: width,
                    height: height
                  }),

        g = svg.append("g").attr({"class": "counties-g"}),

        counties = g.selectAll("path.county")
                        .data(topojson.feature(topology, topology.objects['sc-district-counties']).features)
                      .enter().append("path")
                        .attr({
                          "class": function(d, i) {
                            dWinner = districtWinner(d.properties.district);
                            return "county " + dWinner;
                          },
                          d: path
                        }),

        countyMesh = g.append("path")
                        .datum(countyMesh)
                        .attr({
                          "class": "county-mesh",
                          d: path
                        });

        districtMesh = g.append("path")
                        .datum(districtMesh)
                        .attr({
                          "class": "district-mesh",
                          d: path
                        });

  },

  countiesVisible = false,
  duration = 750,

  toggleCounties = function() {
    if (countiesVisible) {
      d3.selectAll(".district-mesh").transition().duration(duration).style({opacity: 1});
      d3.selectAll(".county-mesh").transition().duration(duration).style({opacity: 0});
      d3.selectAll("path.county")
              .transition()
              .duration(duration)
              .style({
                "fill": function(d, i) {
                  dWinner = districtWinner(d.properties.district);
                  return colors[dWinner];
                },
                stroke: function(d, i) {
                  dWinner = districtWinner(d.properties.district);
                  return colors[dWinner];
                }
              });
      d3.select(this).html("show counties");
      countiesVisible = false;
    } else {
      d3.selectAll(".district-mesh").transition().duration(duration).style({opacity: 0});
      d3.selectAll(".county-mesh")
              .transition()
              .duration(duration)
              .style({opacity: 1});

      d3.selectAll("path.county")
              .transition()
              .duration(duration)
              .style({
                "fill": function(d, i) {
                  cWinner = countyWinner(resultsByCounty[d.properties.county]).party;
                  return colors[cWinner];
                },
                stroke: function(d, i) {
                  cWinner = countyWinner(resultsByCounty[d.properties.county]).party;
                  return colors[cWinner];
                }
              });

      d3.select(this).html("show districts");
      countiesVisible = true;
    }
  };

  queue()
    .defer(d3.json, "sc-district-counties-topo.json")
    .defer(d3.csv, "house_results_2012.csv")
    .await(function(error, topology, results) {
      resultsByCounty = _(results).groupBy("county");
      drawMap(topology, resultsByCounty);
      d3.select("#county-toggle").on("click", toggleCounties);
    });

}());