Simple example to show dynamically computed chart based on the data in another chart. TODO: add better computation than a slice of 10 original elements :)
Created
October 12, 2013 19:30
-
-
Save alexr/6953905 to your computer and use it in GitHub Desktop.
Dynamic computation chart sample
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> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font: 10px sans-serif; | |
} | |
.axis line, | |
.axis path { | |
fill: none; | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
.bar { | |
fill: #3080c0; | |
shape-rendering: crispEdges; | |
} | |
.x.axis path { | |
display: none; | |
} | |
</style> | |
<body> | |
<div id="data"></div> | |
<div id="result"></div> | |
</body> | |
<script src="http://d3js.org/d3.v2.min.js"></script> | |
<script> | |
function o(f, g) { return function(x) { return g(f(x)) } } | |
function getx(d) { return d.x } | |
function gety(d) { return d.y } | |
// Generates array of n data elements of form | |
// [{x:0, y:?}, {x:1, y:?}, ..., {x:n-1, y:?}] | |
// where y represents random function f(x) forming several bumps. | |
// Inspired by Lee Byron's test data generator. | |
function randomData(n) { | |
function bump(a) { | |
var x = 1 / (.1 + Math.random()), | |
y = 2 * Math.random() - .5, | |
z = 10 / (.1 + Math.random()); | |
for (var i = 0; i < n; i++) { | |
var w = (i / n - y) * z; | |
a[i] += x * Math.exp(-w * w); | |
} | |
} | |
var a = [], i; | |
for (i = 0; i < n; ++i) a[i] = 0; | |
for (i = 0; i < 10; ++i) bump(a); | |
return a.map(function(d, i) { return {x: i, y: Math.max(0, d)}; }); | |
} | |
// Implements conventional margins concept http://bl.ocks.org/3019563. | |
// container - is a d3 selection of the element to contain chart's svg element, | |
// dims - defines chart area configuration, | |
// returns function to update chart's data | |
function chartArea(container, dims) { | |
var svg = container.append('svg') | |
.attr('width', dims.width + dims.left + dims.right) | |
.attr('height', dims.height + dims.top + dims.bottom), | |
g = svg.append('g') | |
.attr('transform', 'translate(' + dims.left + ',' + dims.top + ')'), | |
xaxis = g.append('g') | |
.attr('class', 'x axis') | |
.attr('transform', 'translate(0,' + dims.height + ')'), | |
yaxis = g.append('g') | |
.attr('class', 'y axis'); | |
var ch = { | |
left: dims.left, top: dims.top, right: dims.right, bottom: dims.bottom, | |
width: dims.width, height: dims.height, | |
chart: g, svg: svg, xaxis: xaxis, yaxis: yaxis | |
} | |
return function (data) { | |
var x = d3.scale.linear() | |
.range([0, ch.width]) | |
.domain([d3.min(data, getx), d3.max(data, getx) + 1]), | |
y = d3.scale.linear() | |
.range([ch.height, 0]) | |
.domain([0, d3.max(data, gety)]), | |
xAxis = d3.svg.axis().scale(x).orient("bottom"), | |
yAxis = d3.svg.axis().scale(y).orient("left"); | |
ch.xaxis.call(xAxis); | |
ch.yaxis.call(yAxis); | |
var sel = ch.chart.selectAll('.bar') | |
.data(data) // only 'y' and 'height' needs to change on update | |
.attr('y', function(d) { return y(d.y) }) | |
.attr('height', function(d) { return ch.height - y(d.y) }); | |
sel.enter() | |
.append('rect') | |
.attr('class', 'bar') | |
.attr('x', function(d) { return x(d.x) }) | |
.attr('y', function(d) { return y(d.y) }) | |
.attr('width', dims.barWidth || 1) | |
.attr('height', function(d) { return ch.height - y(d.y) }); | |
sel.exit().remove(); | |
} | |
} | |
// data | |
var N = 500, | |
D = randomData(N); | |
// Raw data chart | |
var dataChart = chartArea( | |
d3.select('#data'), | |
{ | |
top: 20, right: 20, bottom: 40, left: 40, | |
width: N * 2, height: 100 | |
})(D); | |
// Dynamic computation result chart | |
var resChart = chartArea( | |
d3.select('body'), | |
{ | |
top: 20, right: 20, bottom: 40, left: 40, | |
width: 10 * 21, // 10 bars of 10+1 pix each | |
height: 100, | |
barWidth: 20, | |
}); | |
resChart(D.slice(0, 10)); // initial data | |
// This is hacky, see how can implrove... | |
d3.select('body').on("mousemove", function() { | |
var svg = d3.select('body svg g'); | |
var mouse = d3.mouse(svg[0][0]); | |
if( mouse[1] > 0 && mouse[1] < 100 && //dataChartDimensions.height && | |
mouse[0] > 0 && mouse[0] < N*2) { //dataChartDimensions.width) { | |
var shift = ~~(mouse[0]/2); | |
if(shift + 10 > N) return; // not full range | |
resChart(D.slice(shift, shift + 10)); | |
} | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment