block by mrchrisadams 89d053977513e6042adf

I don't know how I managed to wipe out the ability to select text in this map, but I have. Try clicking a country, then highlighting the "Policies and Interventions" text. Line 130 in d3_map.js seems to be the culprit. Gold star to anyone who can help get to the bottom of this.

Full Screen

index.html

<!DOCTYPE html>

<html xmlns="//www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta charset="utf-8">
  <meta name="viewport" content="width=975" />
  <script src="loglevel.min.js"></script>

  <script type="text/javascript" src="jquery.min.js"></script>


</head>

<body>
  <div id="wrapper">
    <div id="main">
      <div class="main-holder">




        <div id="content-holder" class="two-columns">
            <div id="content">


            <h1>POLICIES AND INTERVENTIONS</h1>

            <!-- custom behaviour -->
            <link rel="stylesheet" href="d3_map.css" type="text/css" media="screen" title="no title" charset="utf-8">
            <link rel="stylesheet" href="//yui.yahooapis.com/pure/0.6.0/buttons-min.css" media="screen" title="no title" charset="utf-8">

            <div class="map-container clearfix">
              <div class="map-header">
                <h3 data-file-url="data.json" data-map="23" class="map-title">Policies and Interventions</h3>
                <h3 class="menu">
                </h3>

              </div>
              <div class="map-main">

                <!-- canvas -->
                <div id="container" data-map-centre="53.0,10.0" data-map-scale="300"></div>

                <div class="map-key">
                  <div class="lhs">
                    <div class="title">
                      Key
                      <span class="subtitle">Click countries to see details</span>
                    </div>
                    <div class="ranges">

                      <div data-value="0" data-colour="dddddd" class="range first" style="background-color: #dddddd; width: 120px; margin-right: 10px;">
                      </div>

                      <div data-value="1" data-colour="ffae4f" class="range" style="background-color: #ffae4f; width: 120px; margin-right: 10px;">
                      </div>

                    </div>
                    <div class="range-labels">
                      <div class="range-label first" style="width: 120px; margin-right: 10px;">Data not available
                      </div>
                      <div class="range-label" style="width: 120px; margin-right: 10px;">Data available</div>
                    </div>
                  </div>
                </div>

                                <div id="map-data-container">
                  <div id="map-data-area">

                  </div>
                </div>
              </div>
            </div>

            <!-- libraries -->
            <script type="text/javascript" src="//underscorejs.org/underscore-min.js"></script>

            <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
            <script type="text/javascript" src="//d3js.org/topojson.v1.min.js"></script>
            <script type="text/javascript" src="//d3js.org/d3.geo.projection.v0.min.js"></script>
            <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script>

            <script type="text/javascript" src="d3_map.js"></script>
            <script type="text/javascript" src="map_filters.js"></script>







          </div>
        </div>





      </div>
    </div>


  </div>
</body>

</html>
  

d3_map.css

.hero-image {
  width: 910px;
  font-style: "italic"
}

.hero-image #content {
  width: 910px;
  padding-left:0px;
}

#extra-content{
  float:left;
  width:680px;
  padding:0px 0px 0px 25px;
}

.background {
      fill: none;
      pointer-events: all;
}

.country {
  fill: #ccc;
  stroke: #bbb;
  stroke-width: .5px;
  stroke-linejoin: round;
}

path.inactive.country {
  fill-opacity: 0.3;
  transition-duration: 0.25s;
}
path.inactive.country:hover {
  fill-opacity: 0.75;
  transition-duration: 0.25s;
}

path.active.country {
  /*stroke-width: 2px;*/
  transition-duration: 0.25s;
}

#container .controls{
  background-color: #fff;
  /*position: absolute;*/
}


.hidden {
  display: none;
}
div.tooltip {
  color: #222;
  background: #fff;
  padding: .5em;
  text-shadow: #f5f5f5 0 1px 0;
  border-radius: 2px;
  box-shadow: 0px 0px 2px 0px #a6a6a6;
  opacity: 0.95;
  position: absolute;
  z-index: 999;
  /*width:400px*/
}

/* STYLES FOR MAPS */

/*div.map-container {
  background-color: #eeeeee;
  border: #000;
  margin-top: 3px;
}*/

.map-main #container {
  border: 1px solid #ddd;
  /*position: relative;*/
}

div.map-header {
  height: 24px;
  width: 100%;
  background-color:#ccc;
  padding-top:0.5em
}
div.map-header h3 {
  color: #000;
  margin: 0;
  font-size: 0.95em;
  padding-left: 8px;
  padding-top: 1px;
  line-height: 1.4em;
  font-weight: normal;
  float: left;
  display: block;
  height: 23px;
  font-family: Arial, Helvetica, sans-serif;
}
div.map-header h3.menu {
  height: 23px;
  padding-right: 10px;
  float: right;
}
div.map-header h3.menu span.menu-item {
  padding-left: 8px;
  padding-right: 8px;
  display: block;
  float: right;
}
div.map-header h3.menu span.menu-item a {
  color: #5c5c5c;
}
div.map-header h3.menu span.selected {
  height: 24px;
  color:#fff;
}
div.map-key {
  background-color: white;
  /*margin: 0px 5px 0px 5px;*/
  padding: 2px 3px 3px 5px;
  padding: 3px 3px 3px 15px;
  border-bottom: 1px solid #DFDFDF;
}
div.map-key div.rhs {
  float: right;
  width: 150px;
  padding-top: 1em;
}
#content div.map-key div.rhs p {
  font-size: 80%;
  text-align: right !important;
}
div.map-key div.rhs p {
  text-align: right;
  margin-right: 37px;
  font-size: 75%;
  line-height: 1em;
  margin-top: 3px;
  font-style: italic;
}
div.map-key div.rhs img {
  float: right;
}
div.map-key div.range {
  float: left;
  height: 10px;
}
div.map-key div.range-label {
  float: left;
  width: 60px;
  font-size: 0.7em;
  line-height: 0.9em;
  padding-top: 0.2em;
}
div.map-key div.range.first {
  width: 64px;
}
div.map-key div.range-labels {
  clear: left;
  width: 400px;
  height: 20px;
}
div.map-key div.title {
  font-size: 75%;
  font-weight: bold;
  line-height: 1.6em;
  padding-top: 1em;
}
div.map-key div.title span.subtitle {
  font-weight: normal;
  font-style: italic;
}
div.map-main {
  background: #EEEEEE;
}
div.map-data-content {
  padding: 12px 0;
  border-top: 5px solid #DFDFDF;
}

.map-data-content > p{
  padding-left:1em;
  padding-right:1em;
}

.map-data-content .graphs{
  margin-bottom: 1em;
  margin-top: 1em;
  margin-left:1em;
}

.map-data-content .highchart-chart{
  width:552px;
  border: 1px solid #e1e1e1;
  margin-top:1em;
}

.country-jump {
    background-color: #fff;
    padding-top: 1em;
    padding-bottom: 1em;
    padding-left: 0;
}
.country-jump li{
  padding: 1em;
  margin: 4px;
  font-size: 14px;
  border-left: 1px solid #ddd;
  background-color: #fff;
  list-style: none;
  cursor: pointer;
  display:inline;
  color: red;
  text-decoration: underline;
}
.country-jump li:hover{
  background-color: #ddd;
}
.country-jump li.hint{
  border:none;
  background-color: #fff;
  cursor: default;
  color: #111;
  text-decoration: none;
  font-family: 'AvenirLT-Roman';
}
.country-jump li.intro:hover{
  display: inline;
  padding:2em;
}

div.map-data-content h4{
  font-family: 'AvenirLT-Roman', Arial, Helvetica, sans-serif;
  font-size: 16px;
  font-weight:normal;
}
div.map-data-content h3{
  font-family: 'AvenirLT-Roman', Arial, Helvetica, sans-serif;
  font-size: 18px;
  font-weight:normal;
}

div.map-data-content ul li{
  padding:0.3em;
}
div#map-data-area table {
  border-collapse: separate;
  border: 1px solid gray;
  font-size: 95%;
  width:90%;
  margin-left:10px;
  margin-bottom: 1em;
  margin-top: 1em;
}
div#map-data-area table td,
div#map-data-area table th {
  padding: 7px;
  border: 1px solid gray;

}
div#map-data-area table th {
  min-width: 10em;
  background-color:#444;
  color:#eee;
  border: 1px solid gray;
}
div#map-data-area table tr.even td {
  background-color:#eee;
}
div#map-data-area table td.intervention-link,
div#map-data-area table td.intervention-description{
    font-family: 'AvenirLT-Roman';
}

div.notabene{
  margin-left: 1em;
}

.notabene p,
div.map-data-content div.notabene p{
  font-size: 14px;
}

div.definitions {
  padding-top:1em;
  padding-bottom:1em;
  background-color: #f9f9f9;
}

div.definitions h4{
  margin-top:0;
  padding-left: 1em;
  padding-right: 1em;
}

div.definitions p {
  font-style: italic;
  font-size: 95%;
  margin-top: 1em;
  line-height: 1.4em;
  padding-left: 1em;
  padding-right: 1em;
}

/*  Policy Intervention */

#content div.map-data-content h1,
#content div.map-data-content h2,
#content div.map-data-content h3,
#content div.map-data-content h4 {
  margin-left:1em;
}

#content div.map-data-content .back-to-top{
  font-size: 0.9em;
  color: red;
  text-decoration: underline;
  float:right;
  margin-right:3em;
  margin-top:1.5em;
}

div.self-reported{
  border-top: 1px solid rgb(227, 118, 90);
  border-bottom: 1px solid rgb(227, 118, 90);
  background-color: rgb(255, 234, 234);
  width:560px;
  margin-left:1em;
  margin-bottom: 0.5em;
}
#content div.self-reported p{
  margin: 0;
  padding: 0.5em;
  margin
}
div.self-reported:hover{
  cursor: help;
}

div.self-reported .explanation{
  display:none;
}
div.self-reported .explanation p{
  font-size: 13px;
}

#content div.map-data-content .back_to_policy_map{
  margin-left:1em;
  font-size: 14px;
}

div.map-data-content .main_meta {
  background-color: rgba(23, 176, 185, 0.8);

  color: white;
  padding: 0.5em 0em;
}

#content div.map-data-content .main_meta a{
  color:white;
}

div.map-data-content .description,
div.map-data-content .reference,
div.map-data-content .disclaimer,
div.map-data-content .country-filter-status {
  padding: 0.5em 0.5em;
  overflow:auto;
}

div.map-data-content .reference{
  background-color: rgb(200, 200, 200);
  border-top: 1px solid #ddd;
}

div.map-data-content .disclaimer {
  border-top: 1px solid #ddd;
}

div.map-data-content p{
  font-family: 'AvenirLT-Light';
  font-size: 16px;
}

p.image-graph-caption{
  font-size: 0.7em;
  font-style: italic;
  padding-left:1em;
}

div.map-data-content .graphs img{
  margin: 1em 1em 1em 0;

}

#content div.map-data-content .main_meta h3,
#content div.map-data-content .disclaimer h3,
#content div.map-data-content .description h3{
  border-bottom: 3px solid #DFDFDF;
  padding-left: 0;
  margin-left: 0;
}



div.map-data-country{
  border-bottom: 3px solid #DFDFDF;
  border-left: 1px solid #e1e1e1;
  border-right: 1px solid #e1e1e1;

}
div.map-data-country:nth-child(odd){
  background-color: #fff;
}
div.map-data-country:nth-child(even){
  /*background-color: #f6f6f6;*/
  background-color: #eFeFeF;
}

div.main_meta span.definition{
  font-family: 'AvenirLT-Heavy';
  margin-right: 1em;
  width: 150px;
  display:inline-block;
  vertical-align: top;
}
div.main_meta span.definition-content{
  width: 350px;
  display:inline-block;
  vertical-align: top;
  overflow: hidden;
}


#content .import-from-spotlight,
#content .disclaimer p{
  font-family: 'AvenirLT-LightOblique';
  font-style: italic;
  font-size:14px;
}

div.main_meta ul{
  padding-left: 1em;
}

div.main_meta ul > li{
  list-style: none;
  font-family: AvenirLT-Light;
}

div.map-data-content thead {
  background-color: #111;
  color: white;
}

ul.policy-kinds .active{
  /*font-weight: bold;*/
  font-family: 'AvenirLT-Heavy';
}


/* no interventions */
.map-data-content div.no-policy-interventions {
  width: 90%;
  border: 1px solid #ddd;
  margin-left: 10px;
  margin-top: 20px;
  padding-top:2em;
  padding-bottom:2em;
}

#content .map-data-content .no-policy-interventions h3{
  margin-left: 4em;
  color: #aaa;
}

#content .map-data-content .no-policy-interventions p{
  margin-left: 4em;
  color: #aaa;
}

d3_map.js

/* jshint -W033 */
var problemCountries = [];
var goodcountries = [];
var nohoverCountries = [];

// module pattern
var WOF = WOF || {};

WOF.filterDetailPanel = function() {
  WOF.tidyUpDefinitions();
  if ($('.map-data-country').length > 1){
    WOF.addCountryJumpLinks();
  }
};

WOF.tidyUpDefinitions = function() {
  var obesityDefinitions = $('div.definitions').first();
  $('div.definitions').remove();

  $("#content").append(obesityDefinitions);
}

WOF.addCountryJumpLinks = function() {

  var jumper = $("<ul>").addClass("country-jump").prependTo($('#map-data-area'));
  jumper.append("<li class='hint'>Click a country to jump to:</li>")

  $('.map-data-country').each(function(index) {
    var countryName = $(this).attr('data-country');
    var scrollTop = $(this).offset().top - 10;
    var item = $("<li>").text(countryName);
    console.log("scrollTop for " + countryName + ": " + scrollTop)

    // I can't seem to pass in scrollTop as a param,
    // so we need to use the closure
    $(item).click(function() {
      jqscrollTo(scrollTop)

    });
    jumper.append(item);
  });

  $('.map-data-country h2').each(function (index) {
    var topLink = $("<div>")
      .text("(back to top)")
      .addClass('back-to-top');

    $(topLink).click(function () {
      jqscrollTo(jumper.offset().top - 400);
    })

    $(this).before(topLink);
  });

}

function jqscrollTo(scrollTop) {
  log.debug(scrollTop)
  $('html,body').animate({
        scrollTop: scrollTop
  });
}
var topo, projection, svg, g, country_info, width, height, tooltip,
  ranges, clicked_country, zoom, zoomLevel, zoomTouch, data;

jQuery(document, WOF).ready(function($) {

  width = $('#container').attr('offsetWidth');

  height = width / 2;
  active = d3.select(null);

  // set up tool tip to edit later
  var tooltip = d3.select("#container")
    .append("div")
    .attr("class", "tooltip hidden");

  var tooltipOffsetLeft = $("#container")
    .attr('offsetLeft') + 40;
  var tooltipOffsetTop = $("#container")
    .attr('offsetTop') + 20;

  // set up tool tip to edit later
  var control = d3.select("#container")
    .append("div")
    .attr("class", "controls")
    .html("<button>Reset zoom</button>")
    .on('click', reset);

  control.style({
    'top': $("#container").attr('offsetTop') + (height * 0.9) + 'px',
    'left': $("#container").attr('offsetLeft') + 10 + 'px',
    'position': 'absolute',
  });


  function setup(width, height) {
      // work out which projection to read, where to centre the map, and how
      // big it should be

      projection = d3.geo.robinson()
        .scale(155) // scale the map to an appropriate size to fit in the canvas
        .translate([width / 2, height / 1.7]); // move to middle of the canvas

      // store path
      path = d3.geo.path()
        .projection(projection);

      zoom = d3.behavior.zoom()
        .translate([0, 0])
        .scale(1)
        .scaleExtent([1, 8])
        .on("zoom", zoomed);

      // finally create our 'canvas' for all of this to take place on
      svg = d3.select("#container") // select our container div
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .attr('overflow', 'hidden')
        .on('click', stopped, true);

      svg.append("rect")
        .attr("class", "background")
        .attr("width", width)
        .attr("height", height)
        .on("click", reset);

      // add drag behaviour to the map
      // TODO: find out why this breaks text select behaviour after clicking on
      // a country
      svg.call(zoom);

      if ($('#container').attr('data-map-centre')) {
        startWithZoomedMap();
      }

      // add group for holding the world
      g = svg.append("g");
      WOF.g = g;
    }
  // takes the topojson represention of each country in world,
  // and obesity data for each country, merges them before
  // rendering on screen
  function ready(error, world, country_data) {
    var countries = topojson.feature(world, world.objects.countries).features;

    for (var j = 0; j < countries.length; j++) {
      // TODO: create a new topojson dump with country names _and_ iso codes,
      // to replace the current one.
      country_values = [
        "3 letter code: " + countries[j].id,
        "2 letter code from IASO: " + countries[j].properties.id,
        "name: " + countries[j].properties.name
      ]

      if (!countries[j].properties.id) {
        problemCountries.push(countries[j]);
      }
      if (countries[j].properties.id) {
        goodcountries.push(countries[j]);
      }
      if (!countries[j].properties.hover) {
        nohoverCountries.push(countries[j]);
      }
    }

    WOF.allCountryData = country_data;
    WOF.allCountryFeatures = countries;
    WOF.draw = draw;

    // put data on map
    draw();

    $('#map-data-container').appendTo('#extra-content');
    $('#map-data-container').append("<div class='map-data-content'><h3 class='instructions'> Select a country above for further details</h3></div>");

    if(window.location.hash) {
      var countryId = window.location.hash.split('=')[1]
      WOF.selectCountry(countryId);
    }
  }

  WOF.findCountry = function(countryId) {
    return _.find( WOF.annotatedCountries, function(country) {
      return country.id == countryId;
    });
  }

  WOF.resetMap = function(fillValueCallback) {
    WOF.g.html('');
    WOF.draw(fillValueCallback);
    WOF.triggerZoom();
  }

  WOF.triggerZoom = function() {
    zoom.event(svg);
  }

  // draws map on svg canvas, based on merged country data
  function draw(fillValueCallback) {
    ranges = buildRanges();
    var countries = WOF.annotatedCountries = annotateTopography(WOF.allCountryFeatures, WOF.allCountryData, fillValueCallback);

    // add a countries group, to contain ech country
    // bind dataset to the collection of country elements
    // var country = svg.selectAll(".country").data(countries);
    var country_group = g.append('g')
      .attr("id", countries)
      .selectAll(".country")
      .data(countries)

    country_group.enter()
      .insert("path")
      .attr("class", "country")
      .attr("d", path)
      .attr("id", function(d, i) {
        return d.id;
      })
      .style('fill', function(d) {
        var col = fillBasedOnRange(d.properties.name, d.properties.data);
        return col;
      })
      .call(zoom)

    //tooltips
    country_group
      .on("mouseover", hovered)
      .on("mouseout", function(d, i) {
        tooltip.classed("hidden", true)
      })
      .on('click', clicked)
      // this triggers the click, but we end up with a messy zoom
      .on('touchstart', logTouchCoordsStart)
      // get rid of the ugly zoom when you first touch a country
      .on('touchstart.zoom', null)
      .on('touchend', logTouchCoordsEnd)

    WOF.setActiveClasses();
  }

  WOF.setActiveClasses = function() {
    if(WOF.activeCountry) {
      var selector = '#' + WOF.activeCountry;
      d3.selectAll('svg .country').classed("inactive", true);
      d3.select(selector).classed("inactive", false);
      d3.select(selector).classed("active", true);
    } else {
      d3.selectAll('svg .country').classed("inactive", false);
      d3.selectAll('svg .country').classed("active", false);
    }
  };


  function annotateTopography(topoCountries, countryData, fillValueCallback) {

    var countries = topoCountries;

    for (var i = 0; i < countryData.length; i++) {
      var cd = countryData[i]

      for (var c = 0; c < countries.length; c++) {
        if (cd.iso3166_a3 == countries[c].id) {

          var data;
          if(typeof fillValueCallback == 'function') {
            data = fillValueCallback(countries[c].id)
          } else {
            data = cd.data;
          }

          countries[c].properties.hover = cd.hover;
          countries[c].properties.id = cd.id;
          countries[c].properties.name = cd.name;
          countries[c].properties.data = data;
          countries[c].properties.payload = cd.payload;
        }
      }
    }
    return topoCountries;
  }

  function logTouchCoordsStart(d) {
    // console.log("TouchStart object", d)
    // console.log("TouchStart:", d3.event)
    if (d3.event.targetTouches) {
      // console.log("TouchStart: ", d3.event.targetTouches[0].clientX, d3.event.targetTouches[0].clientY);
      zoomTouch = [d3.event.targetTouches[0].clientX, d3.event.targetTouches[0].clientY];
    }
    // console.log("touchstarted:", d3.touches(d))
  }

  function logTouchCoordsEnd(d) {

    if (zoomTouch[0] === d3.event.changedTouches[0].clientX) {
      clicked(d)
    }
  }

  function buildRanges(argument) {

    var ranges = [];
    // fetch range from the available to us
    var rangesDOM = d3.selectAll('.ranges div');

    $.each(rangesDOM[0], function(index, range) {
      var $r = $(range);
      ranges.push({
        value: $r.attr('data-value'),
        color: $r.attr('data-colour')
      });
    });

    return ranges
  }

  // Pass in name and value, to have the matching colour returned
  function fillBasedOnRange(name, value) {

    // if the value is null, we have a country for which
    // we don't have data, or the country code doesn't match one
    // in the database
    if (!value) {
      problemCountries.push([name, value]);
      return "#ddd";
    }

    for (var i = 0; i < ranges.length; i++) {
      var lowerBound = ranges[i].value;
      if (i + 1 < ranges.length) {
        var upperBound = ranges[i + 1].value
      }

      // if it's lower than the lower bound of the first bucket
      // serve a fallback grey
      if (i === 0 && value < lowerBound) {
        // console.log("Lowest bucket. limit: " + lowerBound, "value: " + value)
        problemCountries.push([name, value])
        return "#ddd";
      }
      // and if the value is higher than lower bound of our final bucket
      // use that colour
      if (i + 1 == ranges.length) {
        if (value >= lowerBound) {
          // console.log("highest bucket. limit: " + lowerBound, "value: " + value)
          return "#" + ranges[i].color;
        }
      }
      // if the value is between the lower and upper bound of the
      // current bucket, shade it accordingly
      if (value >= lowerBound && value < upperBound) {
        // console.log("middle bucket. limit: " + lowerBound, "value: " + value, "range: " + ranges[i])
        return "#" + ranges[i].color;
      }
    }
  }

  function startWithZoomedMap() {
    // Fetch latlng info for a map from the DOM, and zooms the map to the
    // corresponding place and zoom level.
    // Used to zoom a map into a given region on load.
    var zoomOutCentre = $('#container').attr('data-map-centre');
    var zoomOutScale = $('#container').attr('data-map-scale');
    var scale_multiple = zoomOutScale / 100;

    var zoomCoords = zoomOutCentre.split(',');
    var projectedZoomCoords = projection(
      [(zoomCoords[1]), (zoomCoords[0])]
    );

    var new_x_midpoint = width / 2 - scale_multiple * projectedZoomCoords[0];
    var new_y_midpoint = height / 2 - scale_multiple * projectedZoomCoords[1];

    var new_translate = [new_x_midpoint, new_y_midpoint];
    WOF.new_translate = new_translate;
    WOF.scale_multiple = scale_multiple;


    svg.transition()
      .duration(1400)
      .call(zoom.translate(new_translate).scale(scale_multiple).event);
  }

  function hovered(d) {

    function offScreenBottom() {
      var distanceFromScreenBottom = window.innerHeight - d3.event.clientY
      return distanceFromScreenBottom < tooltipOffsetTop;
    }

    var mouse = d3.mouse(svg.node()).map(function(d) {
      return parseInt(d);
    });

    var mouseLeft = mouse[0] + tooltipOffsetLeft;
    var mouseTop = mouse[1] + tooltipOffsetTop;

    tooltip.classed("hidden", false)
      .style({
        left: +mouseLeft + "px",
        top: +mouseTop + "px"
      });


    log.debug(d)

    showPanelForTooltip(d, tooltip);


    // move this to the left hand side if we're on the right hand side
    if (mouse[0] > (width / 2)) {
      // debugger
      var tooltipWidth = parseInt(tooltip.style('width'));
      tooltip.style({
        left: tooltip.style({
          'left': (mouseLeft - tooltipWidth) + 'px'
        })
      })
    }

    if(offScreenBottom()) {
      var tooltipHeight = parseInt(tooltip.style('height'));
      tooltip.style({
        top: (mouseTop - tooltipHeight - 50) + 'px'
      });
    }
  }

  function chartingPayloadPresent(payload) {
    //  quit early if we don't have charting functions present
    if (typeof buildSummaryChart !== 'function'){
      return false;
    }
    if (!payload){
      return false;
    }
    // for most countries this should be an ok for charting data
    if (!jQuery.isEmptyObject(payload[0])){
      return true
    }
  }

  function showPanelForTooltip(d, tooltip){

    // filter out empty payload members (i.e countries within within sovereign
    // states, that don't have data)
    var payload = _.filter(d.properties.payload, function(p){
      return !jQuery.isEmptyObject(p);
    });

    if(chartingPayloadPresent(payload)) {
      log.debug("we have a payload!")
      log.debug(d)

      if(payload[0].chart_image_url) {
        log.info("we have an uploaded chart");
        tooltip.html('<h3>' + d.properties.name + ':</h3><img src="' + payload[0].chart_image_url + '" />')
        return true
      }
      // if have a data to build a chart from
      if(payload[0]){
        log.info("we have a chart to build:", d.id)
        tooltip.html("<div class='barchart'></div>")
        tooltip.style('width', "400px");
        selectionString = ".tooltip .barchart";
        buildSummaryChart(selectionString, payload[0], d.properties.name);
        return true
      }
    } else {
      log.debug("No payload");
      log.debug(d)

      if(d.properties.hover) {
        log.debug("But we have a hover")

        if (typeof WOF.showPolicyMapPopup == 'function'){
          WOF.showPolicyMapPopup(d, tooltip, payload)
          return true
        } else{
          tooltip.html(d.properties.hover.split("\n").join('<br>'));
          return true
        }

      }
      if(d.properties.name) {
        tooltip.html('<div class="no-data">' + d.properties.name + ': No information.</div>');
        return true
      } else {
        log.debug("no name here")
        tooltip.classed("hidden", true);
        return false
      }
    }
  }

  function clicked(d) {
    var t;
    if (d3.event.type === 'touchend') {
      t = d3.event.changedTouches[0].target;
    }
    // this is the problem line
    // log.info(d)
    // log.info(d3.event);
    if (d3.event.type === 'click') {
      t = d3.event.target;
    }

    log.debug("Click registered:", d.id);
    selectCountry(d.id);
    WOF.setCountryHash();
  }

  function selectCountry(countryId) {
    var d = WOF.findCountry(countryId);

    WOF.activeCountry = countryId;
    WOF.setActiveClasses();

    // now, use the bounds to work out how far we zoom:
    // found the top, left
    var bounds = path.bounds(d),
      dx = bounds[1][0] - bounds[0][0],
      dy = bounds[1][1] - bounds[0][1],
      // dx and dy are height and width of the bounding box
      // x, y are the coordinates for the centre of the bounding box
      x = (bounds[0][0] + bounds[1][0]) / 2,
      y = (bounds[0][1] + bounds[1][1]) / 2,
      // return the largest of the two fractions, so you can scale
      // in, without zooming to close into long or thin shapes
      scale = 0.9 / Math.max(dx / width, dy / height),
      // scale = 1
      // take our midpoint for the larger map, and subtract the difference , and
      translate = [width / 2 - scale * x, height / 2 - scale * y];

    svg.transition()
      .duration(750)
      .call(zoom.translate(translate).scale(scale).event);

    var map_id = $('h3.map-title').attr('data-map');

    // fetch the html to load into the page
    showStaticOverride(countryId, map_id)
  }

  WOF.selectCountry = selectCountry;

  WOF.setCountryHash = function() {
    window.location.hash = 'country=' + WOF.activeCountry;
  }

  function showStaticOverride(countryId, map_id){
    $("div#map-data-area")
      .load("/maps/ajax/" + map_id + "/" + countryId, function() {
          $(".map-data-content .instructions").hide();
          //scroll down
          var scrollTop = $("div.map-container").offset().top - 10;
          //  provides buffer in viewport
          $('html,body').animate({
            scrollTop: scrollTop
          }, 500);
          WOF.filterDetailPanel();
        });
  }

  function reset() {
    // resets the zoom of the map the original scale, and
    // area of focus as when the map was first loaded
    var new_translate = WOF.new_translate || 0;
    var scale_multiple = WOF.scale_multiple || 1;
    // console.log("reset the map please")
    svg.transition()
      .duration(750)
      .call(zoom.translate(new_translate).scale(scale_multiple).event);
  }

  // adjust thickness of lines to match the level of zoom,
  // and move the object around, based on drag movements
  // TODO fix this problem function to allow us to highlight things again!
  function zoomed() {
    g.selectAll('.country').style("stroke-width", 1 / d3.event.scale + "px");

    if (!isNaN(d3.event.translate[0])){
      g.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
    }
  }

  // If the drag behavior prevents the default click,
  // also stop propagation so we don’t click-to-zoom.
  function stopped() {
    if (d3.event.defaultPrevented) d3.event.stopPropagation();
  }

  // clean up formatting of hoverString, to keep compatibility with Flash
  function cleanString(hoverString) {
    if (hoverString !== "" && hoverString) {
      var str = hoverString.split('\n');
      arr = $.map(str, function(val, i) {
        return "<p>" + val + "</p>";
      });
      hoverString = arr.join().replace(/,/g, '');
    }
    if (!hoverString) {
      hoverString = "";
    }
    return hoverString;
  }

  function addSelfReportDropDown(){
    $('#map-data-container').click(function(ev){
      // this version of jquery can't do $(this).nearest('.self-reported'),

      // if the target is the self report p tag
      if ($(ev.target).parent().hasClass('self-reported')) {
        ev.stopPropagation();
        ev.preventDefault();
        $(ev.target).parent().find('.explanation').toggle('slow');
      }

      // if it's the self report link inside the p tag
      if ($(ev.target).parent().parent().hasClass('self-reported')) {
        ev.stopPropagation();
        ev.preventDefault();
        $(ev.target).parent().parent().find('.explanation').toggle('slow');
      }
    });
  }

  setup(width, height);
  var countryDataUrl = $('h3.map-title').attr('data-file-url');

  log.setLevel(log.levels.DEBUG);

  addSelfReportDropDown();


  queue()
    .defer(d3.json, "world-topo-smaller.json")
    .defer(d3.json, countryDataUrl)
    .await(ready);
});

loglevel.min.js

/*! loglevel - v1.3.0 - https://github.com/pimterry/loglevel - (c) 2015 Tim Perry - licensed MIT */
!function(a,b){"object"==typeof module&&module.exports&&"function"==typeof require?module.exports=b():"function"==typeof define&&"object"==typeof define.amd?define(b):a.log=b()}(this,function(){function a(a){return typeof console===i?!1:void 0!==console[a]?b(console,a):void 0!==console.log?b(console,"log"):h}function b(a,b){var c=a[b];if("function"==typeof c.bind)return c.bind(a);try{return Function.prototype.bind.call(c,a)}catch(d){return function(){return Function.prototype.apply.apply(c,[a,arguments])}}}function c(a,b){return function(){typeof console!==i&&(d(b),g[a].apply(g,arguments))}}function d(a){for(var b=0;b<j.length;b++){var c=j[b];g[c]=a>b?h:g.methodFactory(c,a)}}function e(a){var b=(j[a]||"silent").toUpperCase();try{return void(window.localStorage.loglevel=b)}catch(c){}try{window.document.cookie="loglevel="+b+";"}catch(c){}}function f(){var a;try{a=window.localStorage.loglevel}catch(b){}if(typeof a===i)try{a=/loglevel=([^;]+)/.exec(window.document.cookie)[1]}catch(b){}void 0===g.levels[a]&&(a="WARN"),g.setLevel(g.levels[a])}var g={},h=function(){},i="undefined",j=["trace","debug","info","warn","error"];g.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},g.methodFactory=function(b,d){return a(b)||c(b,d)},g.setLevel=function(a,b){if("string"==typeof a&&void 0!==g.levels[a.toUpperCase()]&&(a=g.levels[a.toUpperCase()]),!("number"==typeof a&&a>=0&&a<=g.levels.SILENT))throw"log.setLevel() called with invalid level: "+a;return b!==!1&&e(a),d(a),typeof console===i&&a<g.levels.SILENT?"No console available for logging":void 0},g.enableAll=function(a){g.setLevel(g.levels.TRACE,a)},g.disableAll=function(a){g.setLevel(g.levels.SILENT,a)};var k=typeof window!==i?window.log:void 0;return g.noConflict=function(){return typeof window!==i&&window.log===g&&(window.log=k),g},f(),g});

map_filters.js


$(function() {

  function intersects( list1, list2 ) {
    return _.intersection( list1, list2 ).length > 0;
  }

  WOF.showPolicyMapPopup = function(d, tooltip, payload){
    // Accepts a payload of interventinos, and a dom element to update
    // updates the policy map popup with the correct numbers of intervention
    // present, based on the current active filters
    log.debug("Defaulting to the normal behaviour for now");

    // find function to return a list of interventions in the payload
    // that have the same active filters
    // WOF.selectedCategories;
    counter = 0;

    _.each(payload.interventions_with_kinds, function(p) {
        p.kinds

    });

    tooltip.html(d.properties.hover.split("\n").join('<br>'));
    log.debug(payload);
    log.debug(tooltip);
  };

  WOF.filterDetailPanel = function() {
    $interventionTable = $('table.policy-intervention-table');
    $noInterventions = $('.no-policy-interventions');

    var rowsVisible = 0;
    $interventionTable.find('tbody tr').each(function() {
      var $row = $(this);
      var rowCategories = $(this).data('intervention-types');
      var showRow = intersects( rowCategories, WOF.selectedCategories );
      if(showRow) {
        $row.show();
        rowsVisible++;
      } else {
        $row.hide();
      }
    });
    if(rowsVisible > 0) {
      $interventionTable.show();
      $noInterventions.hide();
    } else {
      $interventionTable.hide();
      $noInterventions.show();
    }

    $('.filtered-count').text(rowsVisible);
  };

  function filterMap() {
    var matchingCountries = _.filter(WOF.allCountryData, function(country) {
      if(country.payload.length > 0) {
        return intersects(country.payload[0].kinds, WOF.selectedCategories);
      }
      return false;
    });
    var matchingCountryIds = _.pluck(matchingCountries, 'iso3166_a3');
    WOF.resetMap(function(countryId) {
      var data = _.contains(matchingCountryIds, countryId) ? 1 : 0;
      return data;
    });
  }

  function setFilterCategories() {
    WOF.selectedCategories = [];
    $('.policy-map-controls input:checked').each(function() {
      WOF.selectedCategories.push( $(this).attr('name') );
    });
  }

  $('.policy-map-controls input[type=checkbox]').change(function() {
    $(this).parent().toggleClass('inactive');
    setFilterCategories();
    filterMap();
    WOF.filterDetailPanel();
  });

  setFilterCategories();
});