Last active
April 4, 2018 19:09
-
-
Save timproDev/b051510ce77f805f4876f4125687e8a3 to your computer and use it in GitHub Desktop.
Multi Line with Hover
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
line { | |
shape-rendering: crispEdges; } | |
.aboveLabelTickText { | |
font-family: 'Raleway', sans-serif; | |
font-size: 1rem; | |
fill: #404040; } | |
.barLabel { | |
font-family: 'Raleway', sans-serif; | |
font-size: 1.15rem; } | |
.legend-item text { | |
font-family: 'Raleway', sans-serif; | |
font-size: .85rem; } | |
.center-label { | |
font-family: 'Raleway', sans-serif; | |
font-size: 1rem; | |
letter-spacing: -.5px; | |
fill: #808080; | |
text-transform: uppercase; } | |
.center-label-value-null { | |
font-family: 'Raleway', sans-serif; | |
font-size: 1.5rem; | |
letter-spacing: -.75px; } | |
#lineChartMultiBlocks .cov-text { | |
font-family: 'Raleway', sans-serif; | |
font-size: 13px; } | |
.barLabelLight { | |
font-family: 'Raleway', sans-serif; | |
font-size: .75rem; } | |
text.barLabelLight { | |
cursor: default; | |
letter-spacing: -.5px; } | |
.global-chart-container { | |
text-align: center; | |
} | |
.global-chart-container > section > h5 { | |
padding: 0; | |
margin: 0; | |
font-family: 'Raleway', sans-serif; | |
font-size: 26px; | |
font-weight: normal; | |
color: #bfbfbf; | |
width: 50%; | |
margin: 0 auto; } | |
.prm-box, .tooltip { | |
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.5); | |
border-radius: 2px; | |
background-color: #fff; } | |
.mx-dv-container { | |
text-align: center; | |
margin: 2rem auto; | |
padding: .5rem 1rem 1rem 1rem; | |
border: 1px solid #f2f2f2; | |
border-radius: 3px; | |
max-width: 775px; | |
/* 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 { | |
padding: 1.15rem 0 0 0; | |
margin: 0; | |
text-align: left; } | |
.mx-dv-container .chart-premise, .mx-dv-container .chart-citation { | |
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 { | |
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 { | |
cursor: pointer; | |
margin: 0 0 .75rem 0; | |
padding: 0; } | |
.tooltip { | |
top: -1000px; | |
position: fixed; | |
padding: .65rem; | |
pointer-events: none; | |
max-width: 10%; | |
z-index: 500; | |
opacity: .9; } | |
.tooltip-info { | |
font-family: 'Raleway', sans-serif; | |
color: #45555f; | |
padding: 0; | |
margin: 0; | |
display: block; | |
width: 100%; } | |
.tooltip-info span { | |
font-family: 'Raleway', sans-serif; } | |
.tooltip-hidden { | |
opacity: 0; | |
transition: all .3s; | |
transition-delay: .1s; } | |
.tooltip.small { | |
padding: .25rem; } | |
.tooltip.small .tooltip-info { | |
font-size: .85rem; } | |
@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; } } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Genre | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | |
---|---|---|---|---|---|---|---|
Tuvan Throat Singing | 0 | 0.545454545 | 0.65 | -0.755555556 | 0.25 | -0.1 | |
Modern Pan Flute Music | 0 | 0.45 | -0.06 | 0.034482759 | 0.16 | -0.05 | |
Post-Modern | 0 | 1 | -0.025 | -0.35 | 0.6 | -1.25 | |
Chinese Opera | 0 | 0.7 | 0.176470588 | 0.3 | 0.192307692 | 0.096774194 | |
Nintendocore | 0 | 0.75 | 1.125 | -1.33 | 0 | -0.25 | |
Chap Hop | 0 | 0.22 | 0 | 0.09 | -0.08 | 0.04 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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>D3 Factory</title> | |
<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet"> | |
<link rel="stylesheet" href="app.css"> | |
</head> | |
<body> | |
<div class="global-chart-container"> | |
<section style="width:75%; margin:3rem 0; display: inline-block;"> | |
<div class="mx-dv-container" id="lineChartMultiBlocks"><div class="plot-wrap w-svg"></div></div> | |
</section> | |
</div> | |
<script src="line-chart-multi.js"></script> | |
<script src="line-chart-multi-init.js"></script> | |
<script src="https://rawgit.com/timproDev/d3-first-timer/master/js/d3v4-473-jetpack.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
document.addEventListener("DOMContentLoaded", function(){ | |
var path = ''; | |
var elemContainer = ['#lineChartMultiBlocks']; | |
var uiEl = '.chart-ui-container input'; | |
var cssFile = 'line-chart-multi.css'; | |
var dataFile = 'data.csv'; | |
var dataPoint = 'Genre'; | |
var lineChartMulti = new LineChartMulti({ | |
elem:document.querySelector(elemContainer[0]), | |
dataPoint: dataPoint, | |
dataByGroup:'header_one_name', | |
transSpeed:700 | |
}); | |
chartInit(lineChartMulti, elemContainer[0], dataFile); | |
function chartInit(chartInst, elem, dataFile) { | |
d3.csv((path + dataFile), | |
function(data) { | |
var dataNest2013 = d3.nest() | |
.key(function(d) {return d['Genre'];}) | |
.key(function(d) {return d['2013'];}) | |
.entries(data) | |
.map(function(d){ | |
return { | |
'Genre' : d.key, | |
"year":"2013", | |
"value":d.values[0].key | |
} | |
}) | |
var dataNest2014 = d3.nest() | |
.key(function(d) {return d['Genre'];}) | |
.key(function(d) {return d['2014'];}) | |
.entries(data) | |
.map(function(d){ | |
return { | |
'Genre' : d.key, | |
"year":"2014", | |
"value":d.values[0].key | |
} | |
}) | |
var dataNest2015 = d3.nest() | |
.key(function(d) {return d['Genre'];}) | |
.key(function(d) {return d['2015'];}) | |
.entries(data) | |
.map(function(d){ | |
return { | |
'Genre' : d.key, | |
"year":"2015", | |
"value":d.values[0].key | |
} | |
}) | |
var dataNest2016 = d3.nest() | |
.key(function(d) {return d['Genre'];}) | |
.key(function(d) {return d['2016'];}) | |
.entries(data) | |
.map(function(d){ | |
return { | |
'Genre' : d.key, | |
"year":"2016", | |
"value":d.values[0].key | |
} | |
}) | |
var dataNest2017 = d3.nest() | |
.key(function(d) {return d['Genre'];}) | |
.key(function(d) {return d['2017'];}) | |
.entries(data) | |
.map(function(d){ | |
return { | |
'Genre' : d.key, | |
"year":"2017", | |
"value":d.values[0].key | |
} | |
}) | |
dataNest2014.forEach(function(d,i){ | |
dataNest2013.splice((i+(i+1)),0,d); | |
}); | |
dataNest2015.forEach(function(d,i){ | |
dataNest2013.splice((i+(i+1)),0,d); | |
}); | |
dataNest2016.forEach(function(d,i){ | |
dataNest2013.splice((i+(i+1)),0,d); | |
}); | |
dataNest2017.forEach(function(d,i){ | |
dataNest2013.splice((i+(i+1)),0,d); | |
}); | |
dataNest2013.sort(function(a,b){ | |
return d3.descending(a['Genre'], b['Genre']) | |
}); | |
dataNest2013.forEach(function(d){ | |
d.value = +d.value; | |
}) | |
console.log('Here I had to manipulate the data so to convert some headers and their values into columns. In this case, the years were originally the header. Thanks to the power of d3.nest and .map, I created new columns years as the values.'); | |
console.log('raw data:', data); | |
console.log('nested data:', dataNest2013); | |
chartInst.setData(dataNest2013); | |
}); | |
} | |
// include resize event | |
d3.select(window).on('resize', function(){ | |
lineChartMulti.resize(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var LineChartMulti = function(opts){ | |
this.dataByGroup = opts.dataByGroup; | |
this.element = opts.elem.querySelector('.plot-wrap.w-svg'); | |
this.transSpeed = opts.transSpeed; | |
this.dataPoint = opts.dataPoint; | |
} | |
LineChartMulti.prototype.draw = function(){ | |
var self = this | |
this.margin = { | |
top:140, | |
left:40, | |
right:10, | |
bottom:30 | |
}; | |
this.width = this.element.offsetWidth - this.margin.left - this.margin.right; | |
this.height = this.width / 1.25 - (this.margin.top - this.margin.bottom); | |
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.buildLine() | |
} | |
LineChartMulti.prototype.createScales = function() { | |
var self = this | |
this.interpolateTypes = [ | |
d3.curveLinear, | |
d3.curveStepBefore, | |
d3.curveStepAfter, | |
d3.curveBasis, | |
d3.curveBasisOpen, | |
d3.curveBasisClosed, | |
d3.curveBundle, | |
d3.curveCardinal, | |
d3.curveCardinal, | |
d3.curveCardinalOpen, | |
d3.curveCardinalClosed, | |
d3.curveNatural | |
]; | |
this.percentFormat = d3.format(",.1%"); | |
this.xScale = d3.scalePoint().domain(["2013","2014","2015","2016", "2017"]).range([20,(this.width-20)]); | |
this.yScale = d3.scaleLinear().domain([-2,2]).range([this.height,0]); | |
this.colorScale = d3.scaleOrdinal(d3.schemeCategory10); | |
} | |
LineChartMulti.prototype.addAxes = function(){ | |
var self = this | |
this.xAxis = d3.axisBottom(this.xScale); | |
this.yAxis = d3.axisLeft(this.yScale).tickSize(-this.width).tickFormat(this.percentFormat); | |
this.plot.append('g.x-axis').call(this.xAxis).attr('transform','translate(0,' + this.height + ')'); | |
this.plot.append('g.y-axis').call(this.yAxis); | |
this.plot.selectAll('.domain').attr('display','none'); | |
this.plot.selectAll('.y-axis .tick line').attr('stroke','#efefef'); | |
} | |
LineChartMulti.prototype.buildLine = function(){ | |
var self = this | |
this.plot | |
.append('line') | |
.attr('x1',0) | |
.attr('x2',this.width) | |
.attr('y1',this.yScale(0)) | |
.attr('y2',this.yScale(0)) | |
.attr('fill','none') | |
.attr('stroke','#505050') | |
.attr('stroke-width','1'); | |
this.lineGen2 = d3.line() | |
.x( function(d){ return self.xScale(d.year); }) | |
.y( function(d){ return self.yScale(d.value); }) | |
.curve(this.interpolateTypes[0]); | |
this.nestedData = d3.nest() | |
.key(function(d){ return d[self.dataPoint]; }) | |
.sortValues(function(a,b) { return parseFloat(a.year) - parseFloat(b.year); }) | |
.entries(this.data); | |
this.plot.selectAll(".cov-path") | |
.data(this.nestedData) | |
.enter() | |
.append("path.cov-path") | |
.attr("d", function(d){ | |
return self.lineGen2(d.values); | |
}) | |
.attr('fill','none') | |
.attr('stroke',function(d){ | |
return self.colorScale(d.key); | |
}) | |
.attr('stroke-width','8') | |
.attr('opacity','.5'); | |
this.labels = this.plot.selectAll(".cov-text") | |
.data(this.data) | |
.enter() | |
.append("text.cov-text") | |
.attr('text-anchor','middle') | |
.attr("dy", function(d){ | |
if(d.value > 0) { | |
return "-10px"; | |
} else { | |
return "20px"; | |
} | |
}) | |
.attr("x",function(d){ | |
return self.xScale(d.year); | |
}) | |
.attr("y",function(d){ | |
return self.yScale(d.value); | |
}) | |
.attr('opacity','0') | |
.attr('font-size','.75rem') | |
.text(function(d){ | |
return self.percentFormat(d.value); | |
}); | |
var legendXPos = -this.margin.left; | |
// stack layout | |
this.legend = this.plot.append("g.legend") | |
.selectAll('g.legend-item') | |
.data(this.nestedData) | |
.enter() | |
.append('g.legend-item'); | |
this.legend | |
.append('rect.legend-color') | |
.attr("fill", function(d) { return self.colorScale(d.key); }) | |
.attr('width',10) | |
.attr('height',10) | |
.attr('x', legendXPos) | |
.attr("y", function(d, i){ return (i * 20) - self.margin.top + 10;}); | |
this.legend | |
.append('text.legend-text') | |
.text(function(d){ return d.key; }) | |
.attr('x', legendXPos + 15) | |
.attr("y", function(d, i){ return ((i * 20) + 9) - self.margin.top + 10;}); | |
this.plot.selectAll('path.cov-path, text.legend-text, rect.legend-color') | |
.on('mouseenter', function(d){ | |
var thisData = d; | |
self.plot.selectAll('path.cov-path, text.legend-text, rect.legend-color').transition(20).style('opacity','.25'); | |
self.plot.selectAll('path.cov-path, text.legend-text, rect.legend-color').transition(20).style('opacity',function (d,i) { | |
return (d === thisData) ? 1.0 : 0.25; | |
}); | |
self.plot.selectAll('.cov-text').transition(20).style('opacity',function (d,i) { | |
return (d[self.dataPoint] === thisData.key) ? 1.0 : 0; | |
}); | |
}) | |
.on('mouseleave', function(d){ | |
self.plot.selectAll('text.legend-text, rect.legend-color').transition(20).style('opacity','1'); | |
self.plot.selectAll('text.cov-text').transition(20).style('opacity','0'); | |
self.plot.selectAll('path.cov-path').transition(20).style('opacity','.25'); | |
self.plot.selectAll('path.cov-path').transition(20).style('opacity',function () { | |
return .5; | |
}); | |
}); | |
this.plot.selectAll('.cov-path, .legend-color, .legend-text').attr('cursor','default'); | |
} | |
LineChartMulti.prototype.setData = function(newData) { | |
this.data = newData; | |
this.draw(); | |
} | |
LineChartMulti.prototype.resize = function(){ | |
this.width = parseInt(d3.select(this.element).style('width'), 10); | |
this.draw(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment