This page (full source & demo) displays a 2-channel horizontal d3.js Streamgraph that takes realtime mouse coordinates as data inputs for the graph.
However, it tends to gradually use up an increasing amount of memory until there's none left, both on Chrome and Firefox (on Ubuntu 12.04 x64). Data is being collected but not released, yet the arrays that hold the incoming mouse coord data are being popped for every push, and I'm missing where the problem is occuring.
I'm working on profiling it, but wondering if any JS experts can eyeball it and see it. The only dependencies are JQuery and D3.js v3.
<body>
<div id="chart"></div>
<script>
var l = 2; // number of stream channels (layers)
var n = 100; // number of samples per layer
var random = d3.random.normal(0, .2);
var a = [];
var b = [];
/* Normalize mouse coords to a 0:1 range for d3. */
var denom = { x: $(window).width(), y: $(window).height() };
var currentMouseCoord = { x: 1, y: 1 };
/* While mouse is moving over the streamgraph iframe, replace data stream with realtime normalized mouse coords */
$(document).mousemove(function(e) {
currentMouseCoord.x = e.pageX/denom.x;
currentMouseCoord.y = e.pageY/denom.y;
}).mouseover();
/* When mouse leaves the streamgraph iframe, reset data stream to constant 1 */
$(document).mouseout(function(e) {
currentMouseCoord.x = 1;
currentMouseCoord.y = 1;
}).mouseout();
function stream_layers(l, m, o) {
return d3.range(l).map(function(d,i) {
if (i == 0) {
for (idx = 0; idx < m; idx++) a[idx] = currentMouseCoord.x;
return a.map(stream_index);
} else if (i ==1) {
for (idx = 0; idx < m; idx++) b[idx] = currentMouseCoord.y;
return b.map(stream_index);
}
});
}
function update_layers(l, m, o) {
return d3.range(l).map(function(d,i) {
if (i == 0) {
a[m] = currentMouseCoord.x;
return a.map(stream_index);
} else if (i == 1) {
b[m] = currentMouseCoord.y;
return b.map(stream_index);
}
});
}
function stream_index(d, i) {
return {x: i, y: Math.max(0, d)};
}
var data0 = d3.layout.stack().offset("wiggle")(stream_layers(l,n,0));
var data1 = d3.layout.stack().offset("wiggle")(stream_layers(l,n,0));
//var color = d3.interpolateRgb("#aad", "#556");
var color = d3.interpolateRgb("#f30", "#fdb");
var w = $(window).width();
var h = 150;
var mx = n - 1;
var my = d3.max(data0.concat(data1), function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
});
var area = d3.svg.area()
.x(function(d) { return d.x * w / mx; })
.y0(function(d) { return h - d.y0 * h / my; })
.y1(function(d) { return h - (d.y + d.y0) * h / my; });
var vis = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
vis.selectAll("path")
.data(data0)
.enter().append("path")
.style("fill", function() { return color(Math.random()); })
.attr("d", area);
function transition() {
a.push(.01 + .01*Math.random());
b.push(.01 + .01*Math.random());
data0 = d3.layout.stack().offset("wiggle")(update_layers(l,n,0));
vis.selectAll("path").data(data0).attr("d", area).attr("transform", null).transition().duration(40).ease("linear").attr("transform", "translate(" + -w/n + ")").each("end", function (d,i) { if (i==0) transition();});
a.shift();
b.shift();
}
$(document).ready(transition());
</script>
$(window)
and$(document)
quite a bit, so you might want to wrap with an IIFE and passdocument
andwindow
into to it. \$\endgroup\$