Visual representation of stories worldwide. Short description follows in the tooltip on a mouseover event, and a click opens the original news story in a new tab. Can be used to show global coverage of an event, even color/shape coded by different media outlet, type, etc.
xxxxxxxxxx
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet">
<style>
path {
fill: none;
stroke: black;
stroke-width: .7px;
}
#tooltip {
position: absolute;
display: block;
z-index: 100;
max-width: 200px;
max-height: 400px;
padding: 15px;
background-color: white;
overflow: auto;
}
.showing {
opacity: 1;
}
.notShowing {
opacity: 0;
}
span {
clear: both;
display: inline-block;
font-style: italic;
font-size: .8em;
}
</style>
<body>
</body>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
var width = 960;
var height = 600;
var margin = {top: 0, bottom: 0, left: 0, right: 0}
var bigCities = new Map();
var icon = 11;
var cirSize = 8;
d3.queue()
.defer(d3.json, "world.json")
.defer(d3.csv, "storyList.csv")
.await(ready)
function ready(error, world, cities) {
// IF WE WANTED TO USE A MAP INSTEAD
/*
cities.forEach(function(d){
bigCities.set(d.city, {"lat": +d.lat, "lon": +d.lng, "url": d.url, "exLink": d.exLink})
// console.log(bigCities.get(d.city)) <-- Data is storied in bigCities.get(d.city)
})
// Define Data variable for binding.
var data = Array.from(bigCities.values())
console.log(data) // Create an array of key-value pairs for mapping (can also access them with bigCities.entries())
// console.log(Array.from(bigCities.values())) // Create an array of just values
// console.log(Array.from(bigCities.keys())) // Create an array of just values
*/
// Create Generator
var projection = d3.geoMercator()
var path = d3.geoPath().projection(projection) // Geopath generator
var zoomExtent = d3.zoom().scaleExtent([1, 9]);
var color = d3.scaleOrdinal().domain(["terrorism","other"]).range(["red","green"])
function zoom() {
var zoomLvl = d3.event.transform.k
var iconMove = icon/zoomLvl;
g.attr("transform", d3.event.transform)
d3.selectAll("circle")
.attr("r", function(){
return cirSize/zoomLvl;
})
d3.selectAll(".storyImages")
.attr("width", `${iconMove}px`)
.attr("height", `${iconMove}px`)
.attr("x", (d) => projection([d.lng,d.lat])[0] - iconMove/2)
.attr("y", (d) => projection([d.lng,d.lat])[1] - iconMove/2)
d3.selectAll("path")
.style("stroke-width", function(){
return .7 / zoomLvl;
})
}
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.bottom + margin.top)
.style("background-color","lightgrey")
.call(zoomExtent
.on("zoom", zoom))
var g = svg.append("g")
.attr("class", "mapInformation")
.attr("transform",`translate(8,${margin.top})`)
var paths = g.selectAll("path")
.data(world.geometries)
.enter()
.append("path")
.attr("d", path)
.attr("transform","translate(0,0)")
var tooltip = d3.select("body")
.append("div")
.attr("id","tooltip")
.style("pointer-events", "none")
.style("top", height/2 + "px") // iniital x and y coordinates of tooltip
.style("left",width/2 + "px")
.style("opacity", 0)
var stories = g.selectAll("g.story")
.data(cities) // this could also be our data.values() Map
.enter()
.append("g")
.attr("class","story")
/* var icons = stories.append("image")
.attr("xlink:href", d => d.pubIcon)
.attr("class","storyImg")
.attr("width", "15px")
.attr("height", "15px")
.attr("x", (d) => projection([d.lat,d.lon])[0])
.attr("y", (d) => projection([d.lon,d.lat])[1])
*/
var circles = stories.append("circle")
.attr("cx", (d) => projection([d.lng,d.lat])[0])
.attr("cy", (d) => projection([d.lng,d.lat])[1])
.attr("r", cirSize)
.attr("fill", (d) => color(d.type))
var icons = stories.append("image")
.attr("xlink:href",(d)=> d.pubIcon)
.attr("class","storyImages")
.attr("x", (d) => projection([d.lng,d.lat])[0] - icon/2)
.attr("y", (d) => projection([d.lng,d.lat])[1] - icon/2)
.attr("width", `${icon}px`)
.attr("height", `${icon}px`)
.on("mouseover", showStory)
.on("mouseleave",hideStory)
.on("click", function(d){
window.open(d.exLink, "_blank")
})
function showStory(d){
$.ajax({
type: 'GET',
url: d.url,
success: function(result){
d3.select("#tooltip").html(result)
}
})
d3.select("#tooltip")
.transition()
.style("opacity",1)
.style("left", ()=> d3.event.x - (icon/2) + "px")
.style("top", ()=> d3.event.y - (icon/2) + "px")
}
function hideStory(){
console.log("OUT")
d3.select("#tooltip")
.transition()
.style("opacity",0)
}
}
</script>
https://code.jquery.com/jquery-3.2.1.min.js
https://d3js.org/d3.v4.min.js
https://d3js.org/topojson.v2.min.js