Trying to build simple time travel for data displayed via d3 (with Ramda for data generation); very much still a work in progres...
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <link type="text/css" rel="stylesheet" href="style.css"/> | |
| </head> | |
| <body> | |
| <input id="time-slider" type="range" min="0" max="1" step="0.01" value="1"></input> | |
| <div id="table-target"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Series</th> | |
| <th>Value</th> | |
| <th>Time</th> | |
| </tr> | |
| </thead> | |
| <tbody id="data-table"></tbody> | |
| </table> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.18.0/ramda.min.js"></script> | |
| <script src="src.js"></script> | |
| </body> | |
| </html> |
| // construct keys, start and end time; currently using 1 hour as baseline | |
| var keys = ["a", "b", "c", "d", "e"] | |
| , now = new Date().valueOf() | |
| , duration = 1000 * 60 * 60 | |
| , start = now - duration | |
| , end = now | |
| , min = 1 | |
| , max = 100 | |
| , sample_count = 20 | |
| ; | |
| // generate some data | |
| var data = generateData(keys, sample_count, start, end, min, max); | |
| // need the time range for the slider | |
| var t = d3.scale.linear().domain([0, 1]).rangeRound([start, end]); | |
| // start with the last known values | |
| var cursor = R.map(R.last, data); | |
| // draw the table | |
| var $table = d3.select("#data-table"); | |
| $table.selectAll("tr") | |
| .data(cursor) | |
| .enter().append("tr").selectAll("td") | |
| .data(function(d) { return [d.series, d.value, d.iso_time]; }) | |
| .enter().append("td") | |
| .text(function(d) { return d; }); | |
| // setup the range slider; update when the value changes | |
| $slider = d3.select("#time-slider").on("input", function() { | |
| updateTable($table, select(t(this.value), data)); | |
| }); | |
| // debugging table | |
| var $debugging = d3.selectAll("div.series") | |
| .data(data) | |
| .enter().append("div").classed("series", true); | |
| $debugging.append("h3").text(function(d) { return d[0].series; }); | |
| $debugging.append("table") | |
| .selectAll("tr") | |
| .data(function(d) { return d; }) | |
| .enter().append("tr") | |
| .selectAll("td") | |
| .data(function(d) { return [d.series, d.step, d.value, d.time, d.iso_time]; }) | |
| .enter().append("td") | |
| .text(function(d) { return d; }); | |
| // update the table values | |
| function updateTable($target, data) { | |
| $target.selectAll("tr") | |
| .data(data) | |
| .selectAll("td") | |
| .data(function(d) { return [d.series, d.value, d.iso_time]; }) | |
| .text(function(d) { return d; }); | |
| } | |
| function select(time, data) { | |
| // var predicate = R.compose(R.gte(time), R.prop("time")); | |
| // return R.map(R.find(predicate), data); | |
| // ugh | |
| return R.map(function(d) { | |
| return R.findLast(function(v) { | |
| return v.time <= time; | |
| })(d) || R.head(d); | |
| })(data); | |
| } | |
| /** | |
| * data generation | |
| * | |
| */ | |
| function generateData(keys, count, start, end, min, max) { | |
| var generateFn = R.curry(generateDataForKey)(R.__, count, start, end, min, max); | |
| return R.map(generateFn, keys); | |
| } | |
| /** | |
| * generate data for a single key | |
| */ | |
| function generateDataForKey(key, count, start, end, min, max) { | |
| // setup ranges | |
| var timeRange = d3.scale.linear().domain([0, 1]).rangeRound([start, end]) | |
| , valueRange = d3.scale.linear().domain([0, 1]).rangeRound([min, max]) | |
| ; | |
| // sample function | |
| var sampleFn = R.curry(makeSample)(timeRange, valueRange, key); | |
| // generate samples | |
| return R.sortBy( | |
| R.prop("time"), | |
| R.map(sampleFn, R.range(0, count)) | |
| ); | |
| } | |
| /** | |
| * generate a single random sample | |
| */ | |
| function makeSample(timeRange, valueRange, key, step) { | |
| var t = timeRange(Math.random()) | |
| , isoTime = new Date(t).toISOString() | |
| ; | |
| return { | |
| series: key | |
| , step: step | |
| , time: t | |
| , iso_time: isoTime | |
| , value: valueRange(Math.random()) | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment