Skip to content

Instantly share code, notes, and snippets.

@tcuongtran
Last active February 24, 2017 20:54
Show Gist options
  • Select an option

  • Save tcuongtran/f812e7dd7f4a77227fe9727aeb898a6b to your computer and use it in GitHub Desktop.

Select an option

Save tcuongtran/f812e7dd7f4a77227fe9727aeb898a6b to your computer and use it in GitHub Desktop.
D3 Multi-lines Chart
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3 Multi-lines Graph</title>
<style>
#vis > svg {
overflow: visible;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
</head>
<body>
<div id="vis"></div>
<script>
var self = this,
margin = {
top: 20,
right: 10,
bottom: 20,
left: 30
},
width = 400 - margin.left - margin.right,
height = 175 - margin.top - margin.bottom,
formatPercent = d3.format('.0%'),
x = d3.scaleBand()
.rangeRound([0, width]),
y = d3.scaleLinear()
.range([height, 0])
.domain([0, 1]),
xAxis = d3.axisBottom()
.scale(x),
yAxis = d3.axisLeft()
.scale(y)
.tickFormat(formatPercent)
.tickSize(width)
.ticks(3),
svg,
dataNodes = [{
degree: 'Degree1',
values: [{
fy: 2015,
rate: 0.1
}, {
fy: 2016,
rate: 0.3
}]
}, {
degree: 'Degree2',
values: [{
fy: 2015,
rate: 0.2
}, {
fy: 2016,
rate: 0.4
}]
}, {
degree: 'Degree3',
values: [{
fy: 2015,
rate: 0.3,
}, {
fy: 2016,
rate: 0.8
}]
}, {
degree: 'Degree4',
values: [{
fy: 2015,
rate: 0.5
}, {
fy: 2016,
rate: 0.6
}]
}],
i,
j,
valueline = d3.line()
.x(function (d) {
return x(d.fy) + x.bandwidth() / 2;
})
.y(function (d) {
return y(d.rate);
}),
fillColor = d3.scaleOrdinal()
.domain(['degree1', 'degree2', 'degree3', 'degree4'])
.range(['#d84b2a', '#7aa25c', '#1f67af', '#0a7470']),
tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.direction('e')
.html(function (d, el) {
return 'fiscal year: ' + d.fy + ' <br /> valu: ' + d.rate;
}),
legend;
/* Wrap legend text */
function wrap(text, width) {
text.each(function () {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr('y'),
x = text.attr('x'),
dy = parseFloat(text.attr('dy')),
tspan = text.text(null).append('tspan').attr('x', x).attr('y', y).attr('dy', dy + 'em');
while (word = words.pop()) { //eslint-disable-line
line.push(word);
tspan.text(line.join(' '));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(' '));
line = [word];
tspan = text.append('tspan').attr('x', x).attr('y', y).attr('dy', ++lineNumber * lineHeight + dy + 'em').text(word);
}
}
});
}
x.domain(['2015', '2016']);
svg = d3.select('#vis')
.append('svg:svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + width + ',0)')
.call(yAxis);
svg.selectAll('.series')
.data(dataNodes)
.enter().append('g')
.attr('class', 'series')
.style('fill', function (d, i) {
return fillColor(d.degree);
})
.selectAll('.point')
.data(function (d) {
return d.values;
})
.enter().append('circle')
.attr('class', 'point')
.attr('r', 0)
.attr('cx', function (d) {
return x(d.fy) + x.bandwidth() / 2;
})
.attr('cy', function (d) {
return y(d.rate);
})
.on('mouseover', function (d) {
tip.show(d);
})
.on('mouseout', tip.hide)
.transition()
.duration(400)
.ease(d3.easeLinear)
.attr('r', 4.5);
svg.selectAll('.series')
.append('path')
.attr('class', 'line')
.attr('id', function (d, i) {
return 'line-' + i;
})
.attr('d', function (d) {
return valueline(d.values);
})
.attr('fill', 'none')
.style('stroke', function (d) {
return fillColor(d.degree);
});
svg.selectAll('.line').each(function (d, i) {
var totalLength = d3.select('#line-' + i).node().getTotalLength();
d3.selectAll('#line-' + i)
.attr('stroke-dasharray', totalLength + ' ' + totalLength)
.attr('stroke-dashoffset', totalLength)
.transition()
.duration(400)
.ease(d3.easeLinear)
.attr('stroke-dashoffset', 0);
});
svg.call(tip);
legend = svg.selectAll('.legend')
.data(dataNodes)
.enter().append('g')
.attr('class', 'legend')
.attr('transform', function (d, i) {
return 'translate(' + width / 4 + ',' + (i * 20) + ')';
});
legend.append('rect')
.attr('x', width - 18)
.attr('width', 18)
.attr('height', 18)
.style('fill', function (d) {
return fillColor(d.degree);
});
legend.append('text')
.attr('x', width - 24)
.attr('y', 9)
.attr('dy', '.35em')
.style('text-anchor', 'end')
.style('font-size', '12px')
.text(function (d) {
return d.degree;
})
.call(wrap, 100);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment