Create a gist now

Instantly share code, notes, and snippets.

@shimizu /.block
Last active Dec 20, 2016

D3 v4 - SlopeChart
license: mit
height: 900
Country GDP_2000 GDP_2015
America 10284.75 17947.00
England 1551.75 2849.34
Italy 1145.56 1815.75
India 476.64 2090.70
Canada 739.45 1552.38
Germany 1952.92 3357.61
Brazil 657.24 1772.58
France 1372.45 2421.56
Mexico 683.65 1143.80
China 1192.85 10982.82
Japan 4731.20 4123.25
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>D3 v4 - SlopeChart</title>
</head>
<style>
html, body {
width: 100%;
height: 100%;
}
#wrapper {
width: 100%;
}
svg {
display: block;
width: 50%;
height: 900px;
background-color: #e2e2e2;
margin: auto;
}
text {
font-size: 12px;
}
.slopeAxis {
stroke-dasharray: 3;
}
.Japan {
fill:green;
fill-opacity:1;
}
.valueLine.Japan {
stroke:green;
}
</style>
<body>
<div id="wrapper">
<svg></svg>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js"></script>
<script>
function cast(d){
Object.keys(d).forEach(function(key){
if (!isNaN(+d[key])) d[key] = +d[key]
})
return d
}
d3.tsv("gdp.tsv", cast, main)
function main(data) {
var slopeColumns = ["GDP_2000", "GDP_2015"]
var domain = [500, 20000]
var margin = {top:60, left:100, bottom:30, right:100}
var width,height
var plotWidth, plotHeight
var svg = d3.select("svg")
var plotLayer = svg.append("g").attr("class", "plotLayer")
var slopeLeft = plotLayer.append("g").attr("class", "slopeLeft")
var slopeRight = plotLayer.append("g").attr("class", "slopeRight")
var xScale = d3.scalePoint().domain(slopeColumns)
var yScale = d3.scaleLog().domain(domain)
setSize()
rendring(data)
setReSizeEvent()
function rendring(data){
renderAxis(data)
renderSlope(data)
renderLabel(data)
}
function setSize() {
width = svg.node().clientWidth
height = svg.node().clientHeight
plotWidth = width - (margin.left + margin.right)
plotHeight = height - (margin.top + margin.bottom)
plotLayer.attr("transform", "translate("+[margin.left, margin.top]+")")
.attr("width", plotWidth)
.attr("height", plotHeight)
xScale.range([0, plotWidth])
yScale.range([plotHeight, 0])
slopeLeft.attr("transform", "translate("+[xScale(slopeColumns[0]), 0]+")")
slopeRight.attr("transform", "translate("+[xScale(slopeColumns[1]), 0]+")")
}
function renderAxis(data) {
//draw slopeAxis
var selectedSlopeAxis = plotLayer.selectAll(".slopeAxis").data(slopeColumns)
var newSlopeAxis = selectedSlopeAxis.enter().append("line")
.attr("class", "slopeAxis")
var slopeAxis = selectedSlopeAxis.merge(newSlopeAxis)
slopeAxis
.attr("x1", function(d){ return xScale(d)})
.attr("y1", 0)
.attr("x2", function(d){ return xScale(d)})
.attr("y2", plotHeight)
.attr("stroke", "black")
//draw axisLable
var selectedAxisLabel = plotLayer.selectAll(".AxisLabel").data(slopeColumns)
var newAxisLabel = selectedAxisLabel.enter().append("text")
.attr("class", "AxisLabel")
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
var axisLabel = selectedAxisLabel.merge(newAxisLabel)
axisLabel
.attr("x", function(d){ return xScale(d)})
.attr("y", "-2em")
.text(function(d){ return d })
}
function renderSlope(data) {
//draw valueLine
var selectedValueLine = plotLayer.selectAll(".valueLine").data(data)
var newValueLine = selectedValueLine.enter().append("line")
.attr("class", function(d){ return "valueLine " + d["Country"]})
var valueLine = selectedValueLine.merge(newValueLine)
valueLine
.attr("x1", xScale(slopeColumns[0]))
.attr("y1", function(d){ return yScale(d[slopeColumns[0]])})
.attr("x2", xScale(slopeColumns[1]))
.attr("y2", function(d){ return yScale(d[slopeColumns[1]])})
.attr("stroke", "black")
//draw circle
var selectedLeftCircle = slopeLeft.selectAll(".leftCircle").data(data)
var selectedRightCircle = slopeRight.selectAll(".rightCircle").data(data)
var newLeftCircle = selectedLeftCircle.enter().append("circle").attr("class", function(d){ return "leftCircle " + d["Country"]})
var newRigthCircle = selectedRightCircle.enter().append("circle").attr("class", function(d){ return "rightCircle " + d["Country"]})
var leftCircle = selectedLeftCircle.merge(newLeftCircle)
var rightCircle = selectedRightCircle.merge(newRigthCircle)
leftCircle.attr("cy", function(d){ return yScale(d[slopeColumns[0]]) }).attr("r", 4)
rightCircle.attr("cy", function(d){ return yScale(d[slopeColumns[1]]) }).attr("r", 4)
}
function renderLabel(data) {
//draw label
var selectedLeftLabel = slopeLeft.selectAll(".leftLabel").data(data)
var selectedRightLabel = slopeRight.selectAll(".rightLabel").data(data)
var newLeftLabel = selectedLeftLabel.enter().append("text").attr("class", function(d){ return "leftLabel " + d["Country"] })
.attr("text-anchor", "end")
.attr("dominant-baseline", "middle")
var newRigthLabel = selectedRightLabel.enter().append("text").attr("class", function(d){ return "rightLabel " + d["Country"] })
.attr("text-anchor", "start")
.attr("dominant-baseline", "middle")
var leftLable = selectedLeftLabel.merge(newLeftLabel)
var rightLable = selectedRightLabel.merge(newRigthLabel)
leftLable.text(function(d){ return d["Country"] })
.attr("x", "-0.5em")
.attr("y", function(d){
var y = yScale(d[slopeColumns[0]])
if (d["Country"] === "China" || d["Country"] === "Mexico") y -= 6
if (d["Country"] === "Italy" || d["Country"] === "Brazil") y += 6
return y})
rightLable.text(function(d){ return d["Country"] })
.attr("x", "0.5em")
.attr("y", function(d){
var y = yScale(d[slopeColumns[1]])
if (d["Country"] === "Italy") y -= 6
if (d["Country"] === "Brazil") y += 6
return y})
}
function setReSizeEvent() {
var resizeTimer;
var interval = Math.floor(1000 / 60 * 10);
window.addEventListener('resize', function (event) {
if (resizeTimer !== false) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function () {
setSize()
rendring(data)
}, interval);
});
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment