Skip to content

Instantly share code, notes, and snippets.

@timproDev
Last active January 31, 2018 20:43
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/54826a84bcef96afcb83a52cd4c8bfff to your computer and use it in GitHub Desktop.
Save timproDev/54826a84bcef96afcb83a52cd4c8bfff to your computer and use it in GitHub Desktop.
Updated Barchart - Reusable Pattern

Reusable js Pattern & Platform Config 2.0

2.0 because it is a revision to the earlier approach. Life is all about improving oneself. One's self? Anyhow. This D3 bundle will include 2 parts: html and server side

HTML

The is the markup injected into the body of the page. This declares the location of the D3-generated svg element via id or class attributes. The code here includes script tags linking to the chart function, the chart initializer function and the d3 library.

<div id="horizBarchart"></div>
<script src="chart.js"></script>
<script src="chart-init.js"></script>
<script src="d3v4-473-jetpack.js"></script>

Server side assets

This includes all the files and assets. This can include:

image files
custom.css
data.csv
chart.js
chart-init.js
d3v4-473-jetpack.js

Done. For now.

document.addEventListener("DOMContentLoaded", function(){
var options = {
window: window,
path:"",
css: "horiz-barchart.css",
js: "horizBarchart.js",
dataFile: "nat-cat.csv",
element: document.querySelector("#horizBarchart"),
functionName: "horizBarchart",
dataX: "Total losses",
dataY: "Catastrophe"
};
function d3Init() {
var linkElem = document.createElement('link');
document.getElementsByTagName('head')[0].appendChild(linkElem);
linkElem.rel = 'stylesheet';
linkElem.type = 'text/css';
linkElem.href = (options.path + options.css);
var resizeTimer;
window.addEventListener('resize', function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
window[options.functionName].init(options);
}, 300);
});
d3.csv((options.path + "nat-cat.csv"), function(data){
data.forEach(function(d){
d["Total losses"] = +d["Total losses"];
d["Events"] = +d["Events"];
d["Fatalities"] = +d["Fatalities"];
d["Total losses"] = +d["Total losses"];
d["Insured losses"] = +d["Insured losses"];
});
options.data = data;
window[options.functionName].init(options);
});
};
var span = document.querySelector('.data-event');
var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function(){
span.innerHTML = this.innerHTML;
});
}
function userEvents(){
document.querySelector('#dataChange').addEventListener('click', function(){
d3.csv((options.path + "nat-cat-2.csv"), function(data){
data.forEach(function(d){
d["Total losses"] = +d["Total losses"];
d["Events"] = +d["Events"];
d["Fatalities"] = +d["Fatalities"];
d["Total losses"] = +d["Total losses"];
d["Insured losses"] = +d["Insured losses"];
});
options.data = data;
window[options.functionName].init(options);
});
});
document.querySelector('#salmonColor').addEventListener('click', function(){
window[options.functionName].setColor("salmon");
});
document.querySelector('#emeraldColor').addEventListener('click', function(){
window[options.functionName].setColor("#00A160");
});
document.querySelector('#xData').addEventListener('click', function(){
window[options.functionName].setDataX("Fatalities");
});
document.querySelector('#default').addEventListener('click', function(){
d3.csv((options.path + "nat-cat.csv"), function(data){
data.forEach(function(d){
d["Total losses"] = +d["Total losses"];
d["Events"] = +d["Events"];
d["Fatalities"] = +d["Fatalities"];
d["Total losses"] = +d["Total losses"];
d["Insured losses"] = +d["Insured losses"];
});
options.data = data;
window[options.functionName].init(options);
window[options.functionName].setDataX("Total losses");
window[options.functionName].setColor("#0080b4");
});
});
};
d3Init();
userEvents();
});
* {
font-family: arial, verdana, sans-serif;
color:#808080;
}
text.bar-label {
font-size: 1rem;
}
.y-axis .tick text {
font-weight: bold;
font-size: .65rem;
text-transform: uppercase;
color:#bdbdbd;
font-style: italic;
}
.button-container {
padding:2rem 0 1rem 0;
}
.chart-premise {
font-size: .75rem;
line-height: 1.5;
}
button {
border:none;
width: 19.5%;
background: #efefef;
padding: .75rem .5rem;
border-radius: 3px;
border: 2px solid #f5f5f5;
outline:none;
display: inline-block;
cursor: pointer;
font-weight: bold;
font-size: .65rem;
text-transform: uppercase;
color:#bdbdbd;
}
button:hover {
background: #c6eae4;
border: 2px solid #e0f9f4;
color:#0b9c8a;
}
.data-event {
color:#000000;
}
var horizBarchart = {
init: function(opts){
this.data = opts.data;
this.dataX = this.dataX || opts.dataX;
this.dataY = this.dataY || opts.dataY;
this.element = opts.element;
this.draw();
},
draw: function(){
this.width = this.element.offsetWidth;
this.height = this.data.length * 60;
this.margin = {
top:40,
left:0,
right:0,
bottom:0
};
this.element.innerHTML = '';
var svg = d3.select(this.element).append('svg');
svg.attr('width', (this.width + this.margin.left + this.margin.right));
svg.attr('height', (this.height + this.margin.top + this.margin.bottom));
this.plot = svg.append('g')
.attr('transform',`translate(${this.margin.left},${this.margin.top})`);
this.createScales();
this.addAxes();
this.addGrey();
this.addRect();
this.addLabels();
},
createScales: function() {
var self = this;
var yscaleDomain = this.data.map(function(d) { return d[self.dataY]; });
var valArray = this.data.map(function(d){
return d[self.dataX];
});
this.yscale = d3.scaleBand()
.rangeRound([0,this.height])
.domain(yscaleDomain)
.paddingInner(0.5);
this.xscale = d3.scaleLinear()
.domain([0, d3.max(valArray)])
.range([0,this.width]);
},
addAxes: function(){
var self = this;
var yaxis = d3.axisLeft(this.yscale);
var xaxis = d3.axisBottom()
.scale(this.xscale)
.tickSize(this.height);
this.plot.append("g.y-axis").call(yaxis);
this.plot.append("g.x-axis").call(xaxis);
},
addRect: function() {
var self = this;
this.gRects = this.plot.selectAll(".g-comp-rect")
.data(this.data)
.enter()
.append("g.g-comp-rect")
.append("rect.comp-rect")
.attr("y",function(d){
return self.yscale(d[self.dataY]);
})
.attr("x",0)
.attr("height",self.yscale.bandwidth())
.attr("width",0)
.style('fill', this.lineColor || '#0080b4')
.transition().delay(function(d, i) { return i * 120; })
.attr("width", function(d){
return self.xscale(d[self.dataX]);
});
},
addGrey: function(){
var self = this;
this.plot.selectAll(".g-comp-rect")
.data(this.data)
.enter()
.append("rect.bg-bar")
.attr("y", function(d){
return self.yscale(d[self.dataY]);
})
.attr("x",0)
.attr("height",this.yscale.bandwidth())
.attr("width", this.width)
.style("fill","#efefef");
},
addLabels: function(){
var self = this;
this.rectLabels = d3.selectAll(".g-comp-rect")
.append("text.bar-label")
.attr("y", function(d) { return self.yscale(d[self.dataY]) + self.yscale.bandwidth()/2;})
.attr("x", function(d) {
if (d[self.dataX] < 3) {
return (self.xscale(d[self.dataX]) + 5);
} else {
return (self.xscale(d[self.dataX]) - 10);
}
})
.attr("dy", "5px")
.style("text-anchor",function(d){
if (d[self.dataX] < 3) {
return "start";
} else {
return "end";
}
})
.style("fill",function(d){
if (d[self.dataX] < 3) {
return "#45555f";
} else {
return "#ffffff";
}
})
.text(function(d) {
return "$" + d[self.dataX] + " Billion";
});
this.plot.selectAll(".domain").style("display","none");
yText = this.plot.selectAll(".y-axis .tick text"),
xText = this.plot.selectAll(".x-axis .tick text"),
yTick = this.plot.selectAll(".y-axis .tick"),
xTick = this.plot.selectAll(".x-axis .tick"),
yLine = this.plot.selectAll(".y-axis .tick line"),
xLine = this.plot.selectAll(".x-axis .tick line");
yText
.style("text-anchor","start")
.attr("x",0)
.attr("y", function(d) { return -self.yscale.bandwidth() + 6; });
yLine
.style("display","none");
xTick
.style("display","none");
},
// the following are "public methods"
// which can be used by code outside of this file
setColor:function(newColor) {
this.plot.selectAll('rect.comp-rect')
.style('fill', newColor);
// store for use when redrawing
this.lineColor = newColor;
},
setDataX:function(val) {
this.dataX = val;
this.draw();
},
setDataY:function(val) {
this.dataY = val;
this.draw();
},
setData: function(newData) {
this.data = newData;
this.draw();
}
}
<!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>Reusable Pattern</title>
<link rel="stylesheet" type="text/css" href="horiz-barchart.css">
</head>
<body>
<section style="width:800px; margin:5rem auto;">
<div class="mx-dv-container">
<h3 class="chart-title">Updated reusable chart pattern. <span class="data-event">chart state</span></h3>
<div class="chart-premise">This chart uses a more reusable pattern which makes updates and changes easier to manage. The click events also introduce the use of public methods in setting variables and values such as color and data.</div>
<div class="button-container">
<button id="dataChange">Change data</button>
<button id="salmonColor">Salmon Color</button>
<button id="emeraldColor">Emerald Color</button>
<button id="xData">Change X Data</button>
<button id="default">Reset Default</button>
</div>
<div class="plot-wrap w-svg" id="horizBarchart"></div>
<div class="plot-wrap no-svg">
<!-- <img src="assets/d3-bundles/horiz-barchart.png"> -->
</div>
</div>
</section>
<script src="horiz-barchart.js"></script>
<script src="horiz-barchart-init.js"></script>
<script src="https://rawgit.com/timproDev/d3-first-timer/master/js/d3v4-473-jetpack.js"></script>
</body>
</html>
Catastrophe Events Fatalities Total losses Insured losses
Earthquake 2 56 2 8
Blackout 34 11 8 3
Alien Invasion 2 35 1 7
Godzilla 56 33 2 12
The Black Plague Again 22 45 75 1.9
Bigger Earthquake 2 56 2 8
Brownout 34 11 2 3
Ghost Invasion 2 35 1 7
The Avengers Pick a Fight 56 33 2 12
The Flu 22 45 56 1.9
Catastrophe Events Fatalities Total losses Insured losses
Really Bad Storm 43 40 19.0 14
Tidal Wave 19 83 15.0 4.3
Fire 18 32 1.2 1.0
Blizzard 7 55 1.7 1.0
Anything from the movie Twister 2 52 7.0 3.5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment