Skip to content

Instantly share code, notes, and snippets.

@mglukhovsky
Created July 24, 2017 23:11
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 mglukhovsky/d6664666953c884c024a7665ac5c251b to your computer and use it in GitHub Desktop.
Save mglukhovsky/d6664666953c884c024a7665ac5c251b to your computer and use it in GitHub Desktop.
Realtime graph with D3
<html>
<head>
<title>Stripe Charts</title>
</head>
<style>
body {
font: 10px sans-serif;
.layer path, .layer line {
fill: none;
stroke: red;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
}
</style>
<svg width="960" height="500"></svg>
</html>
<body>
<!-- D3 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="/realtime-graph-d3.js"></script>
</body>
'use strict'
// Generate random values
let month = new Date(2014, 0, 1)
function randomData() {
let newData = {
month,
apples: Math.random()*3000,
bananas: Math.random()*2000,
cherries: Math.random()*1000,
dates: Math.random()*400
}
month = moment(month).add(30, 'days').toDate()
return newData
}
const data = []
for (let i=0; i < 12; i++) {
data[i] = randomData()
}
const keys = ['apples', 'bananas', 'cherries', 'dates']
// Get the maximum of the total number of event types
let maxEventCount = d3.max(data, (d) => {
// Sum the values for each event type
return d3.sum(keys, (key) => d[key])*1.5
})
const xDomain = () => {
return [data[0].month, data[data.length-2].month]
}
console.log(maxEventCount)
// Build the SVG plot
const margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom
const x = d3.scaleTime()
// Find the largest and smallest dates for the domain
.domain(xDomain())
.range([0, width]),
y = d3.scaleLinear()
// Set the domain to the highest event count
.domain([0,maxEventCount])
.range([height, 0]),
color = d3.scaleOrdinal(d3.schemeCategory10)
const svg = d3.select('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('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', width)
.attr('height', height)
// Use a stack layout to create our stacked area graph
const stack = d3.stack()
.keys(keys)
.order(d3.stackOrderNone)
.offset(d3.stackOffsetNone)
const stackedData = stack(data)
// Build our area graph (using cardinal smoothing to create curves)
const area = d3.area()
.curve(d3.curveCardinal)
// The x axis is based on time
.x((d,i) => x(d.data.month))
// y0 and y1 represent the bottom and top values for each section of the area graph
.y0((d) => y(d[0]))
.y1((d) => y(d[1]))
const xAxis = d3.axisBottom()
.scale(x)
const yAxis = d3.axisLeft()
.scale(y)
// Create a group layer for each event type
const layer = svg.selectAll('.layer')
.data(stackedData)
.enter().append('g')
.attr('class', 'layer')
.attr('clip-path', 'url(#clip)')
// Add the actual area paths for each event type
const path = layer.append('path')
.attr('class', 'areas')
.attr('d', area)
.style('fill', (d, i) => color(i))
// Add our axes to the plot
const xAxisGroup = svg.append('g')
.attr('class', 'x axis')
.attr('transform', `translate(0, ${height})`)
.attr('clip-path', 'url(#clip)')
.call(xAxis)
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
tick()
function tick() {
data.push(randomData())
x.domain(xDomain())
d3.selectAll('.areas')
.data(stack(data))
.attr('d', area)
.attr('transform', null)
const prevDate = moment(data[0].month).subtract(30, 'days').toDate()
console.log(d3.extent(data, d => d.month))
let transitionCount = 0
d3.selectAll('.areas')
.transition()
.duration(1000)
.ease(d3.easeLinear)
.attr('transform', `translate(${x(prevDate)})`)
.on('end', () => {
transitionCount += 1
if (transitionCount === keys.length) {
xAxisGroup.transition()
.duration(1000)
.ease(d3.easeLinear)
.call(xAxis)
tick()
}
})
data.shift()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment