Skip to content

Instantly share code, notes, and snippets.

@timproDev
Last active January 25, 2018 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timproDev/39ad3846b38069cd2bc8e1b488cb3cdd to your computer and use it in GitHub Desktop.
Save timproDev/39ad3846b38069cd2bc8e1b488cb3cdd to your computer and use it in GitHub Desktop.
Bar Chart
var d3Config = d3Config || {};
d3Config.init = function(settings) {
console.log("Configing!!");
d3Config.linkStyle(settings);
if (typeof settings.win.d3 === "undefined") {
console.log("lib undefined");
d3Config.loadLib(settings);
}
if (typeof settings.win.d3 !== "undefined") {
console.log("lib defined");
d3Config.loadComp(settings);
}
}
d3Config.linkStyle = function(params){
var linkElem = document.createElement('link');
document.getElementsByTagName('head')[0].appendChild(linkElem);
linkElem.rel = 'stylesheet';
linkElem.type = 'text/css';
linkElem.href = (params.path + params.css);
}
d3Config.loadLib = function(params){
$.when(
$.getScript((params.path + params.lib)),
$.Deferred(function( deferred ){
$( deferred.resolve );
})
).done(function(){
console.log("lib defined");
d3Config.loadComp(params);
});
}
d3Config.loadComp = function(params){
$.when(
$.getScript((params.path + params.comp)),
$.Deferred(function( deferred ){
$( deferred.resolve );
})
).done(function(){
params.win[params.func](params.path, params.data, params.elem, params.options);
d3Config.chartRefire(params);
});
}
d3Config.chartRefire = function(params){
var resizeTimer;
$(params.win).on('resize', function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
params.win[params.func](params.path, params.data, params.elem, params.options);
}, 300);
});
}
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flood Data Barchart</title>
<link href="https://fonts.googleapis.com/css?family=Quicksand" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="m-flood-barc.css">
<script src="https://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
</head>
<body>
<section style="width:80%; margin: 0 auto;">
<div class="mx-dv-container" id="cBarChart">
<h3 class="chart-title">U.S. Natural Catastrophe Losses 2019</h3>
<div class="chart-premise"></div>
<div class="plot-wrap w-svg"></div>
<div class="plot-wrap no-svg">
<img src="barchart.png">
</div>
</div>
</section>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(){
var d3settings = {
win: window,
path:"",
css: "m-flood-barc.css",
lib: "d3v4-473-jetpack.js",
comp: "m-flood-barc.js",
data: "nat-cat.csv",
elem: "cBarChart",
func: "mfBarChart",
options:{
axisCategory:"Catastrophe",
axisValue:"Total losses",
rangeMax:false,
chartHeight:250,
showDataOpt:false
}
};
d3Config.init(d3settings);
});
</script>
<script src="d3-config.js"></script>
<script src="https://rawgit.com/timproDev/d3-first-timer/master/js/d3v4-473-jetpack.js"></script>
</body>
</html>
/* Global Styles and resets */
@media only screen and (min-width: 641px) {
body, html {
overflow-x: hidden; } }
@media only screen and (max-width: 40em) {
html {
-webkit-text-size-adjust: 100%; } }
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: 'Quicksand', Arial, sans-serif;
height: auto;
display: block;
background-color: #fcfcfc; }
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block; }
img {
border: none; }
button,
input,
optgroup,
select,
textarea {
color: inherit;
/* 1 */
font: inherit;
/* 2 */
margin: 0;
/* 3 */
-webkit-font-smoothing: antialiased; }
input, button, select {
outline: none; }
*,
*:before,
*:after {
box-sizing: border-box; }
.prm-box, .tooltip {
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.5);
border-radius: 2px;
background-color: #fff; }
.chart-container-linedot-table, .chart-container-table {
margin-top: 1rem; }
.chart-container-linedot-table table, .chart-container-table table {
width: 100%;
background-color: #fff; }
.chart-table-container {
margin-top: 1rem; }
.chart-table-container table {
width: 100%;
background-color: #fff; }
.mx-dv-container {
text-align: center;
margin: 0 0 2rem 0;
background-color: transparent;
border-top: 6px solid #f5f5f5;
border-bottom: 6px solid #f5f5f5;
font-weight: normal;
font-size: 16px;
font-family: 'Quicksand', Arial, sans-serif;
/* IE HACK CANVAS */ }
.mx-dv-container .plot-wrap.no-svg {
display: none;
padding-bottom: 1rem; }
.mx-dv-container .plot-wrap.no-svg img {
width: 100%;
max-width: 706px; }
.mx-dv-container .svg-container {
position: relative; }
.mx-dv-container .svg-container canvas {
display: block;
height: 100%;
visibility: hidden; }
.mx-dv-container .svg-container svg {
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%; }
.mx-dv-container .chart-title {
font-weight: normal;
font-size: 25px;
font-family: 'Quicksand', Arial, sans-serif;
padding: 1.15rem 0 0 0;
margin: 0;
text-align: left; }
.mx-dv-container .chart-premise, .mx-dv-container .chart-citation {
font-weight: normal;
font-size: 16px;
font-family: 'Quicksand', Arial, sans-serif;
color: #808080;
padding: .25rem 0 1rem 0;
margin: 0;
text-align: left; }
.mx-dv-container .chart-premise p, .mx-dv-container .chart-premise input, .mx-dv-container .chart-citation p, .mx-dv-container .chart-citation input {
margin: 0;
text-align: left;
display: inline-block;
vertical-align: middle;
padding: 0 .75rem .25rem 0; }
.mx-dv-container .chart-citation {
font-weight: normal;
font-size: 13px;
font-family: 'Quicksand', Arial, sans-serif;
color: #bdbdbd; }
.mx-dv-container .raw-wrap {
text-align: right;
padding: 0 1.5rem 0 0;
margin: 0; }
.mx-dv-container .raw-wrap .raw-btn {
font-weight: normal;
font-size: 14px;
font-family: 'Quicksand', Arial, sans-serif;
cursor: pointer;
margin: 0 0 .75rem 0;
padding: 0; }
.tooltip {
top: -1000px;
position: fixed;
padding: .65rem;
pointer-events: none;
max-width: 25%;
z-index: 500; }
.tooltip-info {
color: #45555f;
font-weight: normal;
font-size: 16px;
font-family: 'Quicksand', Arial, sans-serif;
padding: 0;
margin: 0;
display: block;
width: 100%; }
.tooltip-info span {
font-weight: normal;
font-size: 16px;
font-family: 'Quicksand', Arial, sans-serif; }
.tooltip-hidden {
opacity: 0;
transition: all .3s;
transition-delay: .1s; }
.dnld-btn {
display: block;
width: 100%;
margin-top: -1.25rem;
padding: .75rem 1.25rem;
text-align: right;
font-weight: normal;
font-size: 14px;
font-family: 'Quicksand', Arial, sans-serif; }
.dnld-btn:hover {
text-decoration: underline; }
@media only screen and (max-width: 40em) {
.mx-dv-container .plot-wrap.no-svg {
display: block; }
.mx-dv-container .plot-wrap.w-svg {
display: none; } }
#cBarChart .domain {
display: none; }
#cBarChart .comp-rect {
transition: opacity 250ms; }
#cBarChart .comp-rect.is-hover, #cBarChart .comp-rect.tooltipped {
opacity: .65; }
#cBarChart .bg-bar {
fill: #ececec; }
#cBarChart .bar-label {
font-weight: bold;
font-size: 14px;
font-family: 'Quicksand', Arial, sans-serif; }
#cBarChart .axis-category-text {
font-weight: bold;
font-size: 13px;
font-family: 'Quicksand', Arial, sans-serif;
fill: #404040;
font-size: 1rem;
text-anchor: end; }
#cBarChart .x-axis .tick line {
stroke-width: 1;
stroke: #45555f; }
#cBarChart .chart-premise .btn-wrap {
display: inline-block;
vertical-align: middle;
padding-bottom: .25rem; }
#cBarChart .chart-premise .btn-wrap .input-group {
display: inline-block;
vertical-align: middle;
display: inline-block;
padding: .3rem .75rem .25rem 0;
margin: 0 0.25rem 0 0; }
#cBarChart .chart-premise .btn-wrap .input-group .ui-label {
padding: 0 0 0 .5rem;
color: #404040;
transition: color 250ms; }
#cBarChart .chart-premise .btn-wrap .input-group .ui-radio {
cursor: pointer;
margin-bottom: 3px; }
#cBarChart .chart-premise .btn-wrap .input-group .ui-radio:checked + .ui-label {
color: #006D9E; }
#cBarChart .chart-premise .btn-wrap .input-group .ui-radio[value="Total losses"]:checked + .ui-label {
color: #006D9E; }
#cBarChart .chart-premise .btn-wrap .input-group .ui-radio[value="Insured losses"]:checked + .ui-label {
color: #D06F1A; }
#cBarChart .chart-premise .btn-wrap .input-group .ui-radio[value="Uninsured losses"]:checked + .ui-label {
color: #625BC4; }
@media only screen and (max-width: 40em) {
#cBarChart .chart-premise .btn-wrap {
display: none; } }
function mfBarChart(setPath, setData, elem, opts) {
var settings = {
premise: opts.premise,
title: opts.title,
axisCategory: opts.axisCategory,
axisValue: opts.axisValue,
rangeMax: opts.rangeMax,
chartHeight: opts.chartHeight,
transSpeed: 500,
dataPath: setPath + setData,
chartContainerID: "#" + elem,
labelSplit:3,
showDataOpt:opts.showDataOpt
};
// horizontal bar margins
var margin = {
top:20,
left:0,
right:0,
bottom:30
};
var chartContainer = d3.select(settings.chartContainerID);
var plotContainer = chartContainer.select(".plot-wrap.w-svg").html('');
var w = plotContainer.node().clientWidth - margin.left - margin.right,
h = settings.chartHeight - margin.top - margin.bottom;
// h = .7 * width;
var premiseDiv = chartContainer.select("div.chart-premise");
// create inner div
var div = plotContainer
.append("div.svg-container")
.style("width", (w + margin.left + margin.right) + "px")
.style("height", (h + margin.top + margin.bottom) + "px");
// insert canvas inner div
div.insert("canvas");
// append svg in inner div
var svg = div
.append("svg")
.style("width", (w + margin.left + margin.right) + "px")
.style("height", (h + margin.top + margin.bottom) + "px")
.append("g.wrap")
.translate([margin.left,margin.top]);
d3.queue()
.defer(d3.csv, settings.dataPath)
.await(ready);
function ready(error, data) {
if (error) throw "error: not loading data, bro";
data.forEach(function(d){
d[settings.axisValue] = +d[settings.axisValue];
d["Uninsured losses"] = +d["Total losses"] - +d["Insured losses"];
});
// manipulate data
var valArray = data.map(function(d){
return d[settings.axisValue];
});
// if range
if (settings.rangeMax == true) {
var fullRange = d3.max(valArray);
} else {
var fullRange = 20;
}
// ui interaction
var optionsArray = d3.keys(data[0]);
// Remove Catastrophe, Events and Fatalities keys from UI options
optionsArray = optionsArray.filter(function(d){
if (d !== "Catastrophe" && d !== "Events" && d !== "Fatalities") {
return d;
}
});
// var optWrap = premiseDiv.append("div.btn-wrap");
chartContainer.select("div.btn-wrap").remove();
var uiWrap = premiseDiv.append("div.btn-wrap");
var radios = uiWrap
.selectAll('div.input-group')
.data(optionsArray).enter()
.append('div.input-group');
radios
.append("input")
.attr("type","radio")
.classed("ui-radio",true)
.attr("value", function(d) {return d;})
.attr("name", "natCat")
.property("checked", function(d, i) {return i===0;});
radios
.append('label.ui-label')
.text(function (d) { return d; });
uiWrap.selectAll('input').on('click', onchange);
// sort
data.sort(function(a,b){
return d3.descending(+a[settings.axisValue], +b[settings.axisValue])
});
// bind data
var gRects = svg.selectAll(".g-comp-rect")
.data(data)
.enter()
.append("g.g-comp-rect");
// fire charts
// pass range AND axisValue
var axisValue = settings.axisValue;
createHorizScales(fullRange);
fireScales();
createHorizElements(fullRange, axisValue);
function createHorizScales(rangeOpt) {
yscale = d3.scaleBand()
.rangeRound([0,h])
.domain(data.map(function(d) { return d[settings.axisCategory]; }))
.paddingInner(0.65);
xscale = d3.scaleLinear()
.domain([0, rangeOpt])
.range([0,w]);
}
function createHorizElements(rangeOpt, axisValue) {
gRects
// append grey background
.append("rect.bg-bar")
.attr("y",function(d){
return yscale(d[settings.axisCategory]);
})
.attr("x",0)
.attr("height",yscale.bandwidth())
.attr("width", function(d){
return xscale(rangeOpt);
});
gRects
// append bars
.append("rect.comp-rect")
.attr("y",function(d){
return yscale(d[settings.axisCategory]);
})
.attr("x",0)
.attr("height",yscale.bandwidth())
.attr("width",0)
.transition().delay(function(d, i) { return i * 120; })
.attr("width", function(d){
return xscale(d[axisValue]);
})
.attr("fill","#0080b4");
svg.selectAll("rect.comp-rect")
.on("mouseenter", function(d){
d3.select(this).classed("is-hover", true);
d3.select('body').selectAppend('div.tooltip');
d3.select(this).call(d3.attachTooltip);
d3.select('.tooltip')
.html(
"<p class=\'tooltip-info\'>" + d["Events"] + " events" +
"</p><p class=\'tooltip-info\'>" + d["Fatalities"] + " fatalities" +
"</p>")
})
.on("mouseleave", function(d){
d3.select(this).classed("is-hover", false);
});
gRects.append("text.bar-label")
// append labels
.attr("y", function(d) { return yscale(d[settings.axisCategory]) + yscale.bandwidth()/2; })
.attr("x", function(d) {
if (d[axisValue] < settings.labelSplit) {
return (xscale(d[axisValue]) + 5);
} else {
return (xscale(d[axisValue]) - 10);
}
})
.attr("dy", "5px")
.style("text-anchor",function(d){
if (d[axisValue] < settings.labelSplit) {
return "start";
} else {
return "end";
}
})
.style("fill",function(d){
if (d[axisValue] < settings.labelSplit) {
return "#45555f";
} else {
return "#ffffff";
}
})
.style("opacity",0)
.transition().delay(function(d, i) { return i * 120; })
.style("opacity",1)
.text(function(d) {
if (settings.axisValue == "Events" || settings.axisValue == "Fatalities") {
return d[axisValue];
} else {
return "$" + d[axisValue] + " Billion";
}
});
// tick text line
yText
.style("text-anchor","start")
.attr("x",0)
.attr("y", function(d) { return -yscale.bandwidth() - 2; })
.classed("axis-category-text", true);
yLine
.style("display","none");
xTick
.style("display","none");
}
function onchange() {
selectValue = d3.select(this).property('value');
updateChart(fullRange, selectValue);
};
function fireScales() {
// create axis element variables
yaxis = d3.axisLeft(yscale);
xaxis = d3.axisBottom()
.scale(xscale)
.tickSize(h);
svg.append("g.y-axis").call(yaxis);
svg.append("g.x-axis").call(xaxis);
// tick presentation | fire after axis appended
yText = svg.selectAll(".y-axis .tick text"),
xText = svg.selectAll(".x-axis .tick text"),
yTick = svg.selectAll(".y-axis .tick"),
xTick = svg.selectAll(".x-axis .tick"),
yLine = svg.selectAll(".y-axis .tick line"),
xLine = svg.selectAll(".x-axis .tick line");
}
function updateChart(rangeOpt, axisValue) {
data.forEach(function(d){
d[axisValue] = +d[axisValue];
});
var upyscale = d3.scaleBand()
.rangeRound([0,h])
.domain(data.map(function(d) { return d[settings.axisCategory]; }))
.paddingInner(0.65);
var upxscale = d3.scaleLinear()
.domain([0, rangeOpt])
.range([0,w]);
var upGreys = svg.selectAll("rect.bg-bar");
upGreys
.transition().duration(settings.transSpeed)
.attr("y",function(d){
return upyscale(d[settings.axisCategory]);
});
var upgRects = svg.selectAll("g.g-comp-rect").data(data);
upgRects
.selectAll("rect.comp-rect")
.transition().duration(settings.transSpeed)
.attr("y",function(d){
return upyscale(d[settings.axisCategory]);
})
.attr("width", function(d){
return upxscale(d[axisValue]);
})
.attr("fill", function(d){
if (axisValue == "Total losses") {
return "#0080b4";
} else if (axisValue == "Insured losses") {
return "#D06F1A";
} else if (axisValue == "Uninsured losses") {
return "#625BC4";
}
});
upgRects.selectAll("text.bar-label")
.style("opacity",0)
.transition().duration(settings.transSpeed)
.attr("y", function(d) { return upyscale(d[settings.axisCategory]) + upyscale.bandwidth()/2; })
.attr("x", function(d) {
if (d[axisValue] < settings.labelSplit) {
return (upxscale(d[axisValue]) + 5);
} else {
return (upxscale(d[axisValue]) - 10);
}
})
.attr("dy", "5px")
.style("text-anchor",function(d){
if (d[axisValue] < settings.labelSplit) {
return "start";
} else {
return "end";
}
})
.style("fill",function(d){
if (d[axisValue] < settings.labelSplit) {
return "#45555f";
} else {
return "#ffffff";
}
})
.style("opacity",1)
.text(function(d) {
if (axisValue == "Events" || axisValue == "Fatalities") {
return d[axisValue];
} else {
if (d[axisValue] < 1) {
return "$" + Math.floor(d[axisValue]*1000) + " Million";
} else {
return "$" + d[axisValue] + " Billion";
}
}
});
} // end update
// The table generation function
function tabulate(data, columns) {
var table = d3.select(".chart-container-table").append("table"),
thead = table.append("thead"),
tbody = table.append("tbody");
// append the header row
thead.append("tr")
.selectAll("th")
.data(columns)
.enter()
.append("th")
.text(function(column) { return column; });
// create a row for each object in the data
var rows = tbody.selectAll("tr")
.data(data)
.enter()
.append("tr");
// create a cell in each row for each column
var cells = rows.selectAll("td")
.data(function(row) {
return columns.map(function(column) {
return {column: column, value: row[column]};
});
})
.enter()
.append("td")
.html(function(d) { return d.value; });
return table;
}
if (settings.showDataOpt) {
// render the table | show Hide jQuery
var headers = d3.keys(data[0]);
var rawWrap = chartContainer.append("div.raw-wrap");
var showBtn = rawWrap
.append('p.raw-btn').html("View Raw Data");
var $chartTable = $(".chart-container-table").hide();
showBtn.on('click', function(){
if ($chartTable.is(':visible')) {
$chartTable.slideUp();
showBtn.html("View Raw Data");
} else {
$chartTable.html('');
tabulate(data, headers);
$chartTable.append("<a class=\'dnld-btn\'>Download Raw Data</a>").on("click", function(){
window.open(settings.dataPath);
return false;
});
$chartTable.slideDown();
showBtn.html("Hide Raw Data");
}
});
}
} // end ready
}
Catastrophe Events Fatalities Total losses Insured losses
Severe Thunderstorm 43 40 19.0 14
Flood, Flash Flood 19 83 15.0 4.3
Wildfire, Heat Waves, Drought 18 32 1.2 1.0
Winter Storms, Cold Waves 7 55 1.7 1.0
Tropical Cyclone 2 52 7.0 3.5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment