Skip to content

Instantly share code, notes, and snippets.

@hironow
Last active October 31, 2015 15:02
Show Gist options
  • Save hironow/53e75d0b7cc254011e48 to your computer and use it in GitHub Desktop.
Save hironow/53e75d0b7cc254011e48 to your computer and use it in GitHub Desktop.
D3 linepoints chart by datasets

Enter, exit and update by datasets. Using as a component (Angular, React, ...).

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<style>
.axis path,
.axis line {
fill: none;
stroke: #333;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
path.line {
fill: none;
stroke: #333;
stroke-width: 2px;
}
text.label {
fill: #333;
stroke: none;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="main.js"></script>
</body>
</html>
var newDataSets = [
{
meta: {
id: 1,
name: 'A'
},
data: [
{x: 10, y: 10},
{x: 20, y: 20},
{x: 30, y: 30},
{x: 40, y: 40},
{x: 50, y: 50}
]
},
{
meta: {
id: 3,
name: 'C'
},
data: [
{x: 100, y: 10},
{x: 200, y: 20},
{x: 300, y: 30},
{x: 400, y: 40},
{x: 500, y: 50}
]
}
];
var newDataSets2 = [
{
meta: {
id: 1,
name: 'A'
},
data: [
{x: 10, y: 10},
{x: 20, y: 20},
{x: 30, y: 30},
{x: 40, y: 40},
{x: 50, y: 50}
]
},
{
meta: {
id: 2,
name: 'B'
},
data: [
{x: 10, y: 1},
{x: 20, y: 2},
{x: 30, y: 3},
{x: 40, y: 4},
{x: 50, y: 5}
]
},
{
meta: {
id: 3,
name: 'C'
},
data: [
{x: 100, y: 10},
{x: 200, y: 20},
{x: 300, y: 30},
{x: 400, y: 40},
{x: 500, y: 50}
]
}
];
var firstDataSets = [
{
meta: {
id: 1,
name: 'A'
},
data: [
{x: 10, y: 10},
{x: 20, y: 20},
{x: 30, y: 30},
{x: 40, y: 40},
{x: 50, y: 50}
]
},
{
meta: {
id: 2,
name: 'B'
},
data: [
{x: 10, y: 1},
{x: 20, y: 2},
{x: 30, y: 3},
{x: 40, y: 4},
{x: 50, y: 5}
]
}
];
var __width = 500;
var __height = 500;
var _margin = {top: 50, right: 50, bottom: 50, left: 50};
var getId = function(dataSet) { return dataSet.meta.id; };
var getLabel = function(dataSet) { return dataSet.meta.name; };
var getData = function(dataSet) { return dataSet.data; };
var getLastData = function(dataSet) { return dataSet.data[dataSet.data.length - 1]; };
var getX = function(data) { return data.x; };
var getY = function(data) { return data.y; };
var _width = __width - _margin.left - _margin.right;
var _height = __height - _margin.top - _margin.bottom;
var xScale = d3.scale.linear().range([0, _width]);
var yScale = d3.scale.linear().range([_height, 0]);
var line = d3.svg.line().interpolate('linear')
.x(function(data) { return xScale(getX(data)); })
.y(function(data) { return yScale(getY(data)); })
var svg = d3.select('#container')
.append('svg')
.attr('width', __width)
.attr('height', __height);
var g = svg.append('g')
.attr('transform',
'translate(' + _margin.left + ',' + _margin.top + ')');
render(firstDataSets);
setInterval(function() {
var dataSetsArray = [newDataSets, newDataSets2, firstDataSets];
var randDataSets = dataSetsArray[Math.floor(Math.random() * dataSetsArray.length)];
render(randDataSets);
}, 2000);
function render(dataSets) {
var xs = _.chain(dataSets).map(getData)
.flatten().map(getX).value();
var ys = _.chain(dataSets).map(getData)
.flatten().map(getY).value();
xScale.domain(d3.extent(xs));
yScale.domain(d3.extent(ys));
var xAxis = d3.svg.axis().scale(xScale).orient('bottom');
var yAxis = d3.svg.axis().scale(yScale).orient('left');
if (g.selectAll('g.x.axis').empty()) {
g.append('g')
.classed('x axis', true)
.attr('transform', 'translate(0,' + _height + ')')
.call(xAxis);
} else {
g.selectAll('g.x.axis')
.transition().duration(1000)
.call(xAxis);
}
if (g.selectAll('g.y.axis').empty()) {
g.append('g')
.classed('y axis', true)
.call(yAxis);
} else {
g.selectAll('g.y.axis')
.transition().duration(1000)
.call(yAxis);
}
// bind dataset
var dataSetContainers = g.selectAll('g.dataset')
.data(dataSets, getId);
// enter
dataSetContainers
.enter().append('g')
.classed('dataset', true)
.style('opacity', 0.0)
.transition().duration(1000)
.style('opacity', 1.0);
dataSetContainers.selectAll('path.line')
.data(function(dataSet) { return [dataSet]; })
.enter().append('path')
.classed('line', true)
.attr('d', function(dataSet) { return line(getData(dataSet)); });
dataSetContainers.selectAll('circle.point')
.data(function(dataSet) { return getData(dataSet); })
.enter().append('circle')
.classed('point', true)
.attr('cx', function(data) { return xScale(getX(data)); })
.attr('cy', function(data) { return yScale(getY(data)); })
.attr('r', 2);
dataSetContainers.selectAll('text.label')
.data(function(dataSet) { return [dataSet]; })
.enter().append('text')
.classed('label', true)
.attr('x', function(dataSet) { return xScale(getX(getLastData(dataSet))); })
.attr('y', function(dataSet) { return yScale(getY(getLastData(dataSet))); })
.text(getLabel);
// exit
dataSetContainers
.exit()
.transition().duration(1000)
.style('opacity', 0.0)
.remove();
// update
dataSetContainers
.selectAll('path.line')
.transition().duration(1000)
.attr('d', function(dataSet) { return line(getData(dataSet)); });
dataSetContainers
.selectAll('circle.point')
.transition().duration(1000)
.attr('cx', function(data) { return xScale(getX(data)); })
.attr('cy', function(data) { return yScale(getY(data)); });
dataSetContainers
.selectAll('text.label')
.transition().duration(1000)
.attr('x', function(dataSet) { return xScale(getX(getLastData(dataSet))); })
.attr('y', function(dataSet) { return yScale(getY(getLastData(dataSet))); });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment