Built with blockbuilder.org
forked from dhexonian's block: timeline lollipop chart
license: mit |
Built with blockbuilder.org
forked from dhexonian's block: timeline lollipop chart
Person | Company | Year | |
---|---|---|---|
Carlos Ghosn | Nissan | 2001 | |
Dieter Zetsche | Daimler | 2006 | |
Akio Toyoda | Toyota | 2009 | |
Ralf Speth | Jaguar Land Rover | 2010 | |
Hakan Samuelsson | Volvo Cars | 2012 | |
Mary Barra | General Motors | 2014 |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<style> | |
html { | |
background-color: hsl(0, 0%, 100%); | |
overflow-y: scroll; | |
font-family: MetricWeb, sans-serif; | |
} | |
.bounding { | |
margin-left: 30px; | |
margin-right: 30px; | |
margin-top: 30px; | |
} | |
#chart { | |
width: 100%; | |
max-width: 650px; | |
} | |
.header { | |
width: 50px; | |
border-top: 2.5px solid #000000; | |
margin-bottom: 0px; | |
display: block; | |
} | |
.main { | |
fill: #33302e; | |
font-size: 17px; | |
} | |
.sub { | |
fill: #66605c; | |
display: inline-block; | |
font-size: 13px; | |
opacity: 0.90; | |
} | |
.y-axis path, | |
.x-axis path { | |
stroke: #757575; | |
shape-rendering: crispEdges; | |
stroke-width: 1px; | |
} | |
.x-axis text, | |
.y-axis text { | |
font-size: 11px; | |
fill: #66605c; | |
opacity: 0.95; | |
} | |
.x-axis .tick line { | |
stroke: #66605c; | |
stroke-width: 0.8px; | |
opacity: 0.2; | |
} | |
.y-axis .tick line { | |
stroke: #66605c; | |
stroke-width: 0.8px; | |
opacity: 0.2; | |
} | |
.footnote text { | |
font-size: 9px; | |
opacity: 0.85; | |
fill: #66605c; | |
} | |
</style> | |
<body> | |
<div class="bounding"> | |
<div class="header"></div> | |
<div id="chart"></div> | |
</div> | |
</body> | |
<script> | |
var dataset; | |
d3.csv("data.csv", function (err, data) { | |
data.forEach(function (d) { | |
d.Year = +d.Year; | |
}) | |
dataset = data | |
draw(dataset); | |
}); | |
function draw(data) { | |
"use strict"; | |
var margin = { | |
top: 120, | |
right: 40, | |
bottom: 70, | |
left: 190 | |
}, | |
container_width = 650, | |
container_height = 550, | |
width = container_width - margin.left - margin.right, | |
height = container_height - margin.top - margin.bottom; | |
var svg = d3 | |
.select("#chart") | |
.append("svg") | |
.attr("id", "svg_container") | |
.attr("viewBox", `0 0 ${container_width} ${container_height}`) | |
.attr("preserveAspectRatio", "xMidYMid") | |
.append("g") | |
.attr("id", "container") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var main_padding = 20; | |
var sub_padding = 45; | |
var chart = d3.select('#svg_container') | |
.append('g') | |
.attr('id', 'text-label') | |
chart.append("text") | |
.attr("class", "main") | |
.text("Long run at the top: Ghosn tenure compared with other car executives*") | |
.attr( | |
"transform", | |
"translate(" + 0 + "," + main_padding + ")" | |
); | |
chart | |
.append("text") | |
.attr("class", "sub") | |
.text("Year placed in charge of group") | |
.attr( | |
"transform", | |
"translate(" + 0 + "," + sub_padding + ")" | |
); | |
var footer_data = ["*Named Renault CEO in 2005 and later became CEO of Renault-Nissan-Mitsubishi alliance"] | |
svg | |
.append("g") | |
.attr('class', 'footnote') | |
.selectAll('text') | |
.data(footer_data) | |
.enter() | |
.append('text') | |
.text(function (d) { return d; }) | |
.attr("transform", function (d, i) { | |
return "translate(" + (-margin.left) + "," + (height + margin.bottom / 1.3 + i * 14) + ")" | |
}); | |
var y_scale = d3 | |
.scaleBand() | |
.domain( | |
data.map(function (d) { | |
return d.Person + "," + d.Company; | |
}) | |
) | |
.rangeRound([0, height]) | |
.paddingInner(0.15) | |
var x_scale = d3 | |
.scalePoint() | |
.domain(d3.range(2000, 2016)) | |
.range([0, width]); | |
var groups = svg.append("g") | |
.selectAll("g") | |
.data(data) | |
.enter() | |
.append("g") | |
.attr("transform", function (d) { | |
return `translate(0,${y_scale(d.Person + "," + d.Company)})`; | |
}) | |
groups | |
.append("rect") | |
.attr("class", "background") | |
.attr("x", -margin.left) | |
.attr("height", y_scale.bandwidth()) | |
.attr("width", container_width) | |
.style("fill", function (d, i) { | |
if (i % 2 != 0) { | |
return '#e5f1f5'; | |
} else { | |
return '#ffffff'; | |
} | |
}); | |
var yAxis = svg.append("g").attr("class", "y-axis"); | |
yAxis | |
.attr("transform", "translate(-5," + 0 + ")") | |
.call( | |
d3 | |
.axisLeft(y_scale) | |
.tickSizeInner(0) | |
.tickSizeOuter(0) | |
.tickPadding(5) | |
.tickFormat(function (d) { | |
let split = d.split(",") | |
return split[0] + ", " + split[1]; | |
}) | |
) | |
.call(g => g.select(".domain").remove()); | |
var xAxis = svg.append("g").attr("class", "x-axis"); | |
xAxis | |
.attr("transform", "translate(0," + 0 + ")") | |
.call( | |
d3 | |
.axisTop(x_scale) | |
.tickSizeInner(15) | |
.tickSizeOuter(0) | |
.tickPadding(5) | |
) | |
.call(g => g.select(".domain").remove()) | |
.call(g => g.selectAll("text").style('font-size', '12')); | |
d3.select(".x-axis") | |
.selectAll(".tick") | |
.each(function (d, i) { | |
if (i % 2 == 0) { | |
d3.select(this).remove(); | |
} | |
}); | |
svg.append("svg:defs").append("svg:marker") | |
.attr("id", 'word') | |
.attr("refX", 4) | |
.attr("refY", 4) | |
.attr("markerWidth", 30) | |
.attr("markerHeight", 30) | |
.attr("markerUnits", "userSpaceOnUse") | |
.attr("orient", "auto") | |
.append("path") | |
.attr("d", "M 0,0 8,4 0,8 3,4") | |
.style("fill", "#0079a2") | |
var bars = svg | |
.selectAll(".bar") | |
.data(data) | |
.enter() | |
.append("g"); | |
bars | |
.append("line") | |
.attr("class", "bar") | |
.attr("y1", function (d) { | |
return y_scale(d.Person + "," + d.Company) + y_scale.bandwidth() / 2; | |
}) | |
.attr("y2", function (d) { | |
return y_scale(d.Person + "," + d.Company) + y_scale.bandwidth() / 2; | |
}) | |
.attr("x1", function (d) { | |
return x_scale(d.Year); | |
}) | |
.attr("x2", function (d) { | |
return width; | |
}) | |
.attr("stroke-width", 2) | |
.style("stroke", "#0079a2") | |
.attr('marker-end', "url(#word)"); | |
bars | |
.append("circle") | |
.attr("class", "bar") | |
.attr("cy", function (d) { | |
return y_scale(d.Person + "," + d.Company) + y_scale.bandwidth() / 2; | |
}) | |
.attr("cx", function (d) { | |
return x_scale(d.Year); | |
}) | |
.attr("r", 5) | |
.style("fill", "#1e558a") | |
.append('title') | |
.text(function (d) { | |
return d.Year; | |
}) | |
svg | |
.append("g") | |
.selectAll('text') | |
.data(data) | |
.enter() | |
.append('text') | |
svg.selectAll(".text") | |
.data(data) | |
.enter() | |
.append("text") | |
.attr("x", function (d) { | |
return x_scale(d.Year) - 2.5; | |
}) | |
.attr("y", function (d) { | |
return y_scale(d.Person + "," + d.Company) + y_scale.bandwidth() / 2 + 10; | |
}) | |
.attr('text-anchor', 'middle') | |
.attr('dominant-baseline', 'hanging') | |
.attr("fill", "black") | |
.attr('font-size', '12') | |
.text(function (d, i) { | |
return d.Year; | |
}); | |
} | |
</script> | |
</html> |