This visualisation is made of two web workers. Both calculates each term of the fibonnaci sequence. One worker memoize its result, thus has a constant complexity. Other worker does not memoize its result, and go quadratic. You can notice the difference by watching the graphic, X-axis is the nth term of the sequence, Y-axis the time in milliseconds that the calculation took
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<title>Fibonacci</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<style>
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
font: 10px sans-serif;
}
.axis .grid-line{
stroke: black;
shape-rendering: crispEdges;
stroke-opacity: .2;
}
.line{
fill: none;
stroke: steelblue;
stroke-width: 2;
}
text {
font: bold 48px monospace;
}
.enter {
fill: green;
}
</style>
<body>
</body>
<script>
var myWorker = new Worker("worker1.js");
var myWorkerB = new Worker("worker2.js");
var timeSeries = [{x:0,y:0}];
var timeSeriesB = [{x:0,y:0}];
var width = "400px";
var height = "500px";
var chart = lineChart()
.x(d3.scale.linear().domain([0, 300]))
.y(d3.scale.linear().domain([0, 3000]));
chart.addSeries(timeSeries);
chart.top(0);
chart.left(10);
var chartB = lineChart()
.x(d3.scale.linear().domain([0, 300]))
.y(d3.scale.linear().domain([0, 3000]));
chartB.addSeries(timeSeriesB);
chartB.top(260);
chartB.left(450);
myWorker.postMessage({what:"start"});
myWorker.onmessage = function (oEvent) {
timeSeries.push({x:oEvent.data.current,y:oEvent.data.time});
myWorker.postMessage({what:"next"});
chart.render();
};
myWorkerB.postMessage({what:"start"});
myWorkerB.onmessage = function (oEvent) {
timeSeriesB.push({x:oEvent.data.current,y:oEvent.data.time});
myWorkerB.postMessage({what:"next"});
chartB.render();
};
function lineChart() {
var _chart = {};
var _width=600, _height=300,
_margins = {top:30, left:60, right:30, bottom:30},
_x, _y,
_data = [],
_colors = d3.scale.category10(),
_svg,
_bodyG,
_line,
_top = 0;
_left = 0;
var _xAxis, _yAxis;
//define SVG element
_chart.render = function() {
if (!_svg) {
_svg = d3.select("body").append("svg").attr("height",_height).attr("width",_width);
// little cheat
_svg.style("position","absolute").style("left",_left+"px");
_svg.style("position","absolute").style("top",_top+"px");
renderAxes(_svg);
defineBodyClip(_svg);
}
renderBody(_svg);
}
_chart.updateAxis = function () {
updateAxis(_svg);
}
function updateAxis() {
//var t = svg.transition().duration(10);
d3.select("g .x.axis").call(_xAxis);
}
function renderAxes(svg) {
var axesG = svg.append("g").attr("class","axes");
renderXAxis(axesG);
renderYAxis(axesG);
}
function renderXAxis(axesG) {
_xAxis = d3.svg.axis()
.scale(_x.range([0, quadrantWidth()]))
.orient("bottom");
axesG.append("g")
.attr("class", "x axis")
.attr("transform", function () {
return "translate(" + xStart() + "," + yStart() + ")";
})
.call(_xAxis);
d3.selectAll("g.x g.tick")
.append("line")
.classed("grid-line",true)
.attr("x1",0)
.attr("y1",0)
.attr("x2",0)
.attr("y2", - quadrantHeight());
}
function renderYAxis(axesG) {
_yAxis = d3.svg.axis()
.scale(_y.range([quadrantHeight(), 0]))
.orient("left");
axesG.append("g")
.attr("class", "y axis")
.attr("transform", function () {
return "translate(" + xStart() + "," + yEnd() + ")";
})
.call(_yAxis);
d3.selectAll("g.y g.tick")
.append("line")
.classed("grid-line", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", quadrantWidth())
.attr("y2", 0);
}
//SVG clip path defines the drawing zone
// defs define shapes that an be later used with <use> tag
function defineBodyClip(svg) {
var padding = 5;
svg.append("defs")
.append("clipPath")
.attr("id","body-clip")
.append("rect")
.attr("x",0-padding)
.attr("y",0)
.attr("width",quadrantWidth()+2*padding)
.attr("height",quadrantHeight());
}
function renderBody(svg) { // <-2D
if (!_bodyG)
_bodyG = svg.append("g")
.attr("class", "body")
.attr("transform", "translate("
+ xStart() + ","
+ yEnd() + ")") // <-2E
.attr("clip-path", "url(#body-clip)");
// the body of the graph has clip path defined
// padding of the clip path is used to let the point overflows the quadrant
// they would be clipped if they was nothing
renderLines();
renderDots();
}
function renderLines() {
_line = d3.svg.line() //<-4A
.x(function (d) { return _x(d.x); })
.y(function (d) { return _y(d.y); });
_bodyG.selectAll("path.line")
.data(_data)
.enter() //<-4B
.append("path")
.style("stroke", function (d, i) {
return _colors(i); //<-4C
})
.attr("class", "line");
_bodyG.selectAll("path.line")
.data(_data)
.transition() //<-4D
.attr("d", function (d) { return _line(d); });
}
function renderDots() {
_data.forEach(function (list, i) {
_bodyG.selectAll("circle._" + i) //<-4E
.data(list)
.enter()
.append("circle")
.attr("class", "dot _" + i)
.attr("r",0);
_bodyG.selectAll("circle._" + i)
.data(list)
.style("stroke", function (d) {
return _colors(i); //<-4F
})
.transition(1000) //<-4G
.attr("cx", function (d) { return _x(d.x); })
.attr("cy", function (d) { return _y(d.y); })
.attr("r", 2);
});
}
function xStart() {
return _margins.left;
}
function yStart() {
return _height - _margins.bottom;
}
function xEnd() {
return _width - _margins.right;
}
function yEnd() {
return _margins.top;
}
//quadrant is where graph is draws
function quadrantWidth() {
return _width - _margins.left - _margins.right;
}
function quadrantHeight() {
return _height - _margins.top - _margins.bottom;
}
//accessor
_chart.width = function (w) {
if (!arguments.length) return _width;
_width = w;
return _chart;
};
_chart.height = function (h) { // <-1C
if (!arguments.length) return _height;
_height = h;
return _chart;
};
_chart.margins = function (m) {
if (!arguments.length) return _margins;
_margins = m;
return _chart;
};
_chart.colors = function (c) {
if (!arguments.length) return _colors;
_colors = c;
return _chart;
};
_chart.x = function (x) {
if (!arguments.length) return _x;
_x = x;
return _chart;
};
_chart.y = function (y) {
if (!arguments.length) return _y;
_y = y;
return _chart;
};
_chart.top = function(top) {
if (!arguments.length) return _top;
_top = top;
return _chart;
}
_chart.left = function(left) {
if (!arguments.length) return _left;
_left = left;
return _chart;
}
_chart.addSeries = function (series) { // <-1D
_data.push(series);
return _chart;
};
return _chart; // <-1E
}
</script>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js