block by wboykinm 9035841

Leaflet Vectors and Nested Functions, Oh My!

Full Screen

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Sacramento Tree Foundation Map</title>

<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no' />
<link href='https://api.tiles.mapbox.com/mapbox.js/v1.6.1/mapbox.css' rel='stylesheet' />
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Rokkitt:400,700" />
<link href='style.css' rel='stylesheet' />

</head>
<body>

<ul id='map-ui'>
  <li><a id="Percent_TC" class="lyr tree">% Tree Canopy</a></li>
  <li><a id="mean_bmi" class="lyr health">Mean BMI</a></li>
  <li><a id="per_ovw_ob" class="lyr health">% Overweight or Obese</a></li>
  <li><a id="per_ob" class="lyr health">% Obese</a></li>
  <li><a id="per_mvpa" class="lyr health active">% w/ >150min MVPA/wk</a></li>
  <li><a id="per_hi_bp" class="lyr health">% w/ High Blood Pressure</a></li>
  <li><a id="per_type2" class="lyr health">% w/ Type 2 Diabetes</a></li>
  <li><a id="per_frpr" class="lyr health">% in Fair/Poor health</a></li>
  <li><a id="per_asthma" class="lyr health">% w/ Asthma</a></li>
</ul>
<div id='map'></div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
<script src='//api.tiles.mapbox.com/mapbox.js/v1.6.1/mapbox.js'></script>
<script src='//api.tiles.mapbox.com/mapbox.js/plugins/leaflet-hash/v0.2.1/leaflet-hash.js'></script>
<script src="//d3js.org/topojson.v1.min.js"></script> 

<script>
  var mapdataviz, 
      popup,
      zips_geojson,
      zipsLayer;

  // Creat wrapper function
  $(function() { 

    // Create Data loading function, repeatable on page load and on button click
    var loadData = function() {

      // Create map
      mapdataviz = L.mapbox.map('map', 'landplanner.map-khn9uycz').setView([38.574, -121.384], 10);
      // Create Popup
      popup = new L.Popup({
        autoPan: false
      });

      var hash = L.hash(mapdataviz);

      // ADD THE REFERENCE OVERLAY
        var topPane = mapdataviz._createPane('leaflet-top-pane', mapdataviz.getPanes().mapPane);
        var topLayer = new L.mapbox.tileLayer('sactree.h7id69df', {
          maxZoom: 17,
          opacity: 0.4
        }).addTo(mapdataviz);
        topPane.appendChild(topLayer.getContainer());
        topLayer.setZIndex(7);

      // Add and define the variables that carry theme info to the layer constructor
      var actVar = $('a.active').attr('id');
      var actLayer = 'layer.feature.properties.' + actVar;
      var actFeature = 'feature.properties.' + actVar;
      //Get the topojson
      $.getJSON('sactree_zips.json', function(data) {
        console.log('json loaded!')
        // Convert the topojson to geojson
        zips_geojson = topojson.feature(data, data.objects.zips).features;
        // Create leaflet vector layer and add it to the map
        zipsLayer = L.geoJson(zips_geojson, {
          style: getStyle,
          onEachFeature: onEachFeature
        }).addTo(mapdataviz);

        // Define the vector styles
        function getStyle(feature) {
          return {
            weight: 1,
            opacity: 0.2,
            color: 'black',
            fillOpacity: 0.95,
            fillColor: getColor(eval(actFeature))
          };
        }
        
        // Define the polygon fill, conditional on theme and value
        function getColor(d) {

          if (actVar == 'Percent_TC') {
            return d > 33 ? '#588125' 
              : d > 23 ? '#729B3F' 
              : d > 15 ? '#8BB458' 
              : d > 9 ? '#A5CE72' 
              : d > 4 ? '#BEE78B' 
              : d > 0.5 ? '#D7FFA4' 
              : '#fff';
          }

          if (actVar == 'mean_bmi') {
            return d > 31 ? '#4b75b3' 
              : d > 29 ? '#523494' 
              : d > 27 ? '#99a9c6' 
              : d > 25 ? '#bcc5cf' 
              : d > 22 ? '#dde1d8' 
              : d > 20 ? '#ffffe0' 
              : '#fff';
          }

          else {
            return d > 0.7 ? '#4b75b3' 
              : d > 0.5 ? '#523494' 
              : d > 0.4 ? '#99a9c6' 
              : d > 0.25 ? '#bcc5cf' 
              : d > 0.1 ? '#dde1d8' 
              : d > 0.02 ? '#ffffe0' 
              : '#fff';
          }
        }

        // Define the interactivity
        function onEachFeature(feature, layer) {
          layer.on({
            mousemove: mousemove,
            mouseout: mouseout,
            click: zoomToFeature
          });
        }
        var closeTooltip;

        // Define the popup content, also conditional on theme and value 
        function mousemove(e) {
          var layer = e.target;
          popup.setLatLng(e.latlng);

          if (actVar == 'Percent_TC' || actVar == 'mean_bmi') {
            popup.setContent('<div class="marker-title">' + layer.feature.properties.NAME + ' - ' + layer.feature.properties.ID + '</div>' + $('.active').text() + ": <b>" + Math.round(eval(actLayer)).toFixed(0) + "</b>");
          }

          else {
            popup.setContent('<div class="marker-title">' + layer.feature.properties.NAME + ' - ' + layer.feature.properties.ID + '</div>' + Math.round(eval(actLayer) * 100).toFixed(0) + $('.active').text());
          }
          if (!popup._map) popup.openOn(mapdataviz);
          window.clearTimeout(closeTooltip);
          // highlight feature on mouseover
          layer.setStyle({
            weight: 3,
            opacity: 0.3,
            fillOpacity: 0.3
          });
          if (!L.Browser.ie && !L.Browser.opera) {
            layer.bringToFront();
          }
        }

        function mouseout(e) {
          zipsLayer.resetStyle(e.target);
          closeTooltip = window.setTimeout(function() {
            mapdataviz.closePopup();
          }, 100);
        }

        function zoomToFeature(e) {
          mapdataviz.fitBounds(e.target.getBounds());
        }
        
      });
     };

    // Define the reload-on-click function
    $('.lyr').click(function () {
      $('.lyr').removeClass('active');
      // todo - remove old polygons before reload:
      mapdataviz.removeLayer(zipsLayer);
      $(this).addClass('active');
      // Redefine the theme variables based on the clicked button
      actVar = $(this).attr('id');
      actLayer = 'layer.feature.properties.' + actVar;
      actFeature = 'feature.properties.' + actVar;
      // Fire the big data loading function
      loadData();
    });


    // init
    loadData();

  });
  </script>
</body>
</html>

style.css

body { 
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: normal 18px/25px 'Rokkitt', Georgia, serif;
    vertical-align: baseline;
  }
  #map { position:absolute; top:0; bottom:0; width:100%; }

  .map-legend .swatch {
  width:20px;
  height:20px;
  float:left;
  margin-right:10px;
  }
.leaflet-popup-close-button {
  display: none;
  }
.leaflet-popup-content-wrapper {
  pointer-events: none;
  }
.leaflet-top-pane {
    pointer-events: none;
  }
#map-ui {
    position: absolute;
    top: 15px;
    right: 10px;
    list-style: none;
    margin: 0;
    padding: 10px;
    z-index: 100;
    background-color: rgba(255,255,255,0.8);
    border: 2px solid #BBB;
}

#map-ui a {
    color: #E5EFD4;
    display: block;
    margin: 0;
    padding: 0;
    border-radius: 6px;
    min-width: 105px;
    padding: 10px;
    text-decoration: none;
    text-transform: uppercase;
    text-align: center;
    border: 1px solid #fff;
}

#map-ui a.tree {
    background-color: #729B3F;
}

#map-ui a.health {
    background-color: #4B75B3;
}

#map-ui a:hover {
    opacity: 0.8; 
    filter: alpha(opacity=80);
    border-color: #FFF;
}

#map-ui a.active {
    opacity: 0.6; 
    filter: alpha(opacity=60);
    border: 2px solid #333;
    color: #fff;
}