Skip to content

Instantly share code, notes, and snippets.

@jkeohan
Last active November 5, 2015 18:03
Show Gist options
  • Select an option

  • Save jkeohan/86014cf5d84b1372fcc0 to your computer and use it in GitHub Desktop.

Select an option

Save jkeohan/86014cf5d84b1372fcc0 to your computer and use it in GitHub Desktop.
yazanealaily - 5 largest megacities
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Population in Megacities</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script type="text/javascript" src="reuseable.d3.charts.js"></script>
<style type="text/css">
body {
background-color: #69425E;
color: white;
-webkit-font-smoothing: antialiased;
}
h3 {
margin-top: 0;
line-height: 40px;
font-size: 22px;
}
footer {
margin-top: 270px;
}
a {
text-decoration: none;
color: white;
}
#years li {
text-decoration: none;
display: inline-block;
margin-left: 25px;
margin-right: 60px;
margin-top: 10px;
font-size: 18px;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}
#totals li {
text-decoration: none;
display: inline-block;
margin-left: 15px;
margin-right: 41px;
margin-top: 2px;
}
#header {
height: 100px;
width: 100%;
margin-bottom:25px;
}
svg {
background-color: #69425E;
}
a:hover {
color: #FF6ED6;
}
rect:hover {
fill: #FF6ED6;
}
#legend2 {
margin-bottom:25px;
}
</style>
</head>
<body>
<div class="container">
<div class = "row">
<div class="col-md-12" id="header">
<h2>Population of the Top 5 Megacities 1950-2015</h2>
</div>
</div>
<div class = "row">
<div class="col-md-5" id = "barChart">
</div>
<div class="col-md-7" id = "chartDescr">
<h3 class="text-justify">A megacity is an urban agglomeration of ten or more million people.</h3>
<h3 class="text-justify">This chart shows the growth in population of the five largest megacities in the world: Tokyo, New York, Mexico City, Mumbai, and Sao Paolo.</h3>
<footer>Source: <a href="http://www.earth-policy.org/">Earth Policy Institute</a></footer>
</div>
</div>
<div class = "row" id = "additionalInfo">
<ul id="years">
<li>1950</li>
<li>2007</li>
<li>2015</li>
</ul>
<ul id="totals">
<li>31 million</li>
<li>111 million</li>
<li>119 million</li>
</ul>
</div>
</div>
<script type="text/javascript">
//Width and height
var w = 400;
var h = 500;
//Reusable charts takes an ordintal scale as input for legend text and color
var colors = d3.scale.ordinal()
.range(["#FC5C64", "#7A0751", "#EE9D2A", "#FED3C9", "#9A427C"])
//var colors = ["#FC5C64", "#7A0751", "#EE9D2A", "#FED3C9", "#9A427C"];
//Original data
var dataset = [
[
{ x: 1950, y: 11.3 , z: "Tokyo"},
{ x: 2007, y: 35.7, z: "Tokyo" },
{ x: 2015, y: 36.4, z: "Tokyo" }
],
[
{ x: 1950, y: 12.3, z: "New York" },
{ x: 2007, y: 19.0, z: "New York" },
{ x: 2015, y: 20.0, z: "New York" }
],
[
{ x: 1950, y: 2.9, z: "Mexico City" },
{ x: 2007, y: 19.0, z: "Mexico City" },
{ x: 2015, y: 20.2, z: "Mexico City" }
],
[
{ x: 1950, y: 2.9, z: "Mumbai" },
{ x: 2007, y: 19.0, z: "Mumbai" },
{ x: 2015, y: 21.9, z: "Mumbai" }
],
[
{ x: 1950, y: 2.3, z:"Sao Paolo" },
{ x: 2007, y: 18.8, z:"Sao Paolo" },
{ x: 2015, y: 20.5, z:"Sao Paolo" }
]
];
//Set up stack method
var stack = d3.layout.stack()
.order("reverse"); //Flip the order
//Data, stacked
stack(dataset);
//Set up scales
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset[0].length))
.rangeRoundBands([0, w], 0.2);
var yScale = d3.scale.linear()
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([0, h]);
//Create SVG element
var svg = d3.select("#barChart")
.append("svg")
.attr("width", w)
.attr("height", h);
// Add a group for each row of data
var groups = svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.style("fill", function(d, i) {
//return colors[colors.length - 1 - i];
return colors(i)
})
.style("stroke", "white");
// Add a rect for each data value
var rects = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("width", xScale.rangeBand())
.attr("y", function(d) {
return h - yScale(d.y0) - yScale(d.y); //Flip the math!
})
.attr("height", function(d) {
return yScale(d.y);
})
.append("title").text(function(d,i) {return d.z + ": " + d.y + "mn Residents";});
//PULLED OUT THE Z VALUES AND ADDED TO COLORS SCALE
var cityNames = d3.set(dataset.map(function(d) { return d[0].z })).values()
colors.domain(cityNames)
//CREATED THE VERTICAL LEGEND
var rlegend_vertical = d3.models.legend()
//.fontSize(".8em")
.position("vertical").gxPos(25).gyPos(200).item_height(30).fontColor("white").inputScale(colors)
//.on("onClick", filterLegend);
svg.call(rlegend_vertical);
//CREATED THE HORIZONTAL LEGEND WITH RECS
var rlegend_horizontal_recs = d3.models.legend()
.position("horizontal-recs").fontSize(20).inputScale(colors)
var svg_legend = d3.select('#header')
svg_legend.call(rlegend_horizontal_recs);
//CREATED THE HORIZONTAL LEGEND WITH NO RECS
var rlegend_horizontal_norecs = d3.models.legend()
.position("horizontal-norecs").fontSize(20).inputScale(colors)
var svg_legend = d3.select('#header')
//svg_legend.call(rlegend_horizontal_norecs);
</script>
</body>
</html>
//First, we add our sub-namespace to the d3 namespace. It is not essential to do this,
//but name-spacing is good practice to not pollute the global space.
d3.models = {};
// We add the legend module, which is a simple function returning a function. The outer
// function serves as the scoped closure for our module.
d3.models.legend = function () {
// Some variables are available in the closure and not accessible from the outside (pri- vate).
// They have default values.
var fontSize = 15;
var gxPos = 0;
var gyPos = 0;
// var width = 10;
// var height = 100;
var item_height = 20;
var fontColor = "white";
var legendValues;
var position = "vertical";
// One way for the module to expose events to the outside world is by using d3.dispatch to declare
// an event that we can then listen to from the out- side when it’s triggered in the module.
//Both d3.dispath and d3.rebind are classified as d3 Internals and are utilities for implementing reusable components.
var dispatch = d3.dispatch("mouseOver", "mouseOut","onClick");
function render(selection) {
//console.log(selection)
selection.each(function(data) {
console.log(selection)
switch (position) {
case "vertical": return vertical();
case "horizontal-recs": return horizontalRecs();
case "horizontal-norecs": return horizontalNoRecs();
}
function vertical() {
//D3 Vertical Legend//////////////////////////
var group = selection.append("g")
.attr("transform", function(d,i) { return "translate(" + gxPos + "," + gyPos + ")"})
var legend = group.selectAll("legend").data(legendValues).enter().append("g")
.attr("class", "legend")
//.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")" })
.attr("transform", function (d, i) { return "translate(0," + i * item_height + ")" })
.on("mouseover",dispatch.mouseOver) //dispath name cannot be same as event
.on("mouseout", dispatch.mouseOut)
.on("click", dispatch.onClick)
legend.append('rect')
.attr({ x:5, y:5, width: 10, height: 10 })
.style("fill", function (d, i) { return d.color })
legend.append('text')
.attr({ x: 25, y: 15})
.text(function (d, i) { return d.text})
.style("text-anchor", "start")
.style("font-size", fontSize)
.style("fill",fontColor)
}//end vertical
function horizontalRecs() {
var legend = selection.selectAll('legend').data(legendValues)
legend.enter().append("div").attr("class","legend")
.style("float","left")
.style("margin-right","1em")
var p = legend.append("p").attr("class","country-name")
p.append("span").attr("class","key-dot").style("background",function(d,i) { return d.color } )
.style("display","inline-block")
.style("height","10px")
.style("margin-right",".5em")
.style("width","10px")
p.insert("text").text(function(d,i) { return d.text } )
.style("font-weight","bold")
}//end horizontalRecs
function horizontalNoRecs() {
console.log("inside")
var legend = selection.selectAll("legend").data(legendValues).enter().append('div')
.attr("class", "legend")
.style("display","block")
legend
.html(function(d,i) {return d.text})
.style("color", function(d,i) {return d.color })
.style("display","inline-block")
.style("padding","0px 5px")
.style("margin",".2em")
.style("font-size","20px")
.style("font-weight","bold")
.on("mouseover",dispatch.mouseOver)
.on("mouseout", dispatch.mouseOut)
.on("click", dispatch.onClick)
}//end horizonal
})//_selection.each()
}//render()
//Functions are also objects so we can add addtional properties and\or methods
// These “public” functions will be used as getters and setters at the same time.
// They are getters when no argument is passed to the function; otherwise they set
// the private variable to the new value passed as an argument. When setting, we return
// the current context this, as we want these methods to be chainable.
render.fontSize = function(_x) {
if (!arguments.length) return fontSize;
fontSize = _x;
return this;
}
render.fontColor = function(_x) {
if (!arguments.length) return fontColor;
fontColor = _x;
return this;
}
render.width = function(_x) {
if (!arguments.length) return width;
width = _x;
return this;
}
render.height = function(_x) {
if (!arguments.length) return height;
height = _x;
return this;
}
render.gxPos = function(_x) {
if (!arguments.length) return gxPos;
gxPos = _x;
return this;
}
render.gyPos = function(_x) {
if (!arguments.length) return gyPos;
gyPos = _x;
return this;
}
render.item_height = function(_x) {
if (!arguments.length) return item_height;
item_height = _x;
return this;
}
render.inputScale = function(_x) {
if (!arguments.length) return inputScale;
scale = _x;
legendValues = [];
scale.domain().forEach(function (el) {
var cellObject = {color: scale(el), text: el}
legendValues.push(cellObject)
//console.log(legendValues)
})
return this;
}
render.position = function(_x) {
if(!arguments.length) return position;
position = _x;
return this;
}
//https://github.com/mbostock/d3/wiki/Internals#rebind
d3.rebind(render, dispatch, "on")
return render
}
//d3.rebind
// Copies the methods with the specified names from source to target, and returns target.
// Calling one of the named methods on the target object invokes the same-named method on the source object,
// passing any arguments passed to the target method, and using the source object as the this context
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment