block by pstuffa adcdd7a52a0bb8943eace15707ce7049

Map with Popover & Zoom

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">

<style type="text/css">

.counties {
	fill: none;
	stroke: #000;
	stroke-width: .25;
	stroke-dasharray: 1, 1;
}

.background {
  fill: none;
}

#countyText {	
  position: absolute;			
  text-align: center;					
  padding: 2px;				
  font: 12px sans-serif;		
  background: lightsteelblue;	
  border: 0px;		
  border-radius: 8px;			
  pointer-events: none;
  opacity: 0;			
}

.bubbles {
  fill-opacity: .25;
  stroke: #000;
  pointer-events: none;
}

</style>

<body>

  <input type="range" min='0' max='50' id='slider' value='0'/> 
  <span id='sliderValue'>0</span> Guns

<div id='countyText'> </div>


<div id='map'> </div>

</body>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>

<script type="text/javascript">
  
var width = 960,
    height = 500,
    centered;

var svg = d3.select("#map").append("svg")
    .attr("width", width)
    .attr("height", height);

var colorScale = d3.scale.threshold() 
    .domain([1,910,1107,1880,2716,15782])
    .range(["#fff","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a"]);

var projection = d3.geo.albersUsa()
    .scale(1070)
    .translate([width / 2, height / 2]);

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

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

var g = svg.append("g")

// Load the datasets
queue()
  .defer(d3.csv, "guns-history.csv")
  .defer(d3.json, "us.json")
  .await(ready);

// Control the slider's functionality 
d3.select("#slider")
  .on("input", function() {

    var myValue = this.value
    // Update the fill of the counties
    d3.selectAll(".counties")
      .style("fill", function(d) {
       return gunsLookup[d.id] > myValue ? "#bfbfbf" : "#fff" ;
      })
    // Update the bubbles radius (hide if they dont meet criteria)
    d3.selectAll(".circles")
    .attr("r", function(d) {
       return gunsLookup[d.id] > myValue ? Math.sqrt(gunsLookup[d.id])/Math.PI : 0;
    })
    // Change the slider text value
    d3.select("#sliderValue").text(myValue);
  })


// Data Callback
function ready(error, guns, us) {
  if (error) return console.warn(error);

  // create data for counties and states
  var countyFeatures = topojson.feature(us, us.objects.counties).features;
  var stateFeatures = topojson.feature(us, us.objects.states).features;

  // create looksups for guns and location
  gunsLookup = {};
  locationLookup = {};

  guns.forEach(function(d) {
  	d.count3 = +d.count3;
  	gunsLookup[d.FIPS] = d.count3;
    locationLookup[d.FIPS] = d.county;
  })

  // append a g
  g.append("g")
    .attr("id", "county")
    // run the data bind on paths
    .selectAll(".counties")
  	.data(countyFeatures)
  .enter().append("path")
  	.attr("class","counties")
  	.attr("d", path)
  	.style("fill", function(d) {
  		 return gunsLookup[d.id] > 0 ? "#bfbfbf" : "#fff" ;
  	})  
    // This triggers the zoom functionality 
    .on("click", clicked)
    // This triggers the popover functionality 
  	.on("mouseenter", function(d) {
  		d3.select(this)
  		.style("stroke-width", 1.5)
  		.style("stroke-dasharray", 0)

  		d3.select("#countyText")
  		.transition()
  		.style("opacity", 1)
  		.style("left", (d3.event.pageX) + "px")
  		.style("top", (d3.event.pageY) + "px")
  		.text(locationLookup[d.id])
  	})
  	.on("mouseleave", function(d) { 
  		d3.select(this)
  		.style("stroke-width", .25)
  		.style("stroke-dasharray", 1)

  		d3.select("#countyText")
  		.transition()
  		.style("opacity", 0);
  	});


  // Same process for counties we do for states
  // we dont have all the interaction for states though
  g.append("g")
    .attr("id", "state")
    .selectAll(".states")
  	.data(stateFeatures)
  .enter().append("path")
  	.attr("class","states")
  	.attr("d", path)
  	.style("fill", "none")
  	.style("stroke","#000")

  // draw bubbles for the counties
  g.selectAll(".bubbles")
  	.data(countyFeatures)
  .enter().append("g")
  	.attr("class","bubbles")
  	.attr("transform",function(d) 
  		{ return "translate(" + path.centroid(d) + ")"})
  	.append("circle")
    .attr("class","circles")
  	.attr("r", function(d) {
  		 return Math.sqrt(gunsLookup[d.id])/Math.PI;
  	})
  	.style("fill", function(d) {
  		 return colorScale(gunsLookup[d.id]);
  	});

}

// Click to Zoom Function 
function clicked(d) {
  var x, y, k;

  if (d && centered !== d) {
    var centroid = path.centroid(d);
    x = centroid[0];
    y = centroid[1];
    k = 4;
    centered = d;
  } else {
    x = width / 2;
    y = height / 2;
    k = 1;
    centered = null;
  }

  g.selectAll("path")
      .classed("active", centered && function(d) { return d === centered; });

  g.transition()
      .duration(750)
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
      .style("stroke-width", 1 / k + "px");
}

</script>