d3 + canvas, data binding + transitions
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div id="vis"></div>
JavaScript
d3.ns.prefix.custom = "may-as-well-use-me-since-I'm-already-here"
var base = d3.select("#vis");
var chart = base.append("canvas")
.attr("width", 400)
.attr("height", 300);
var context = chart.node().getContext("2d");
// Create an in memory only element of type 'custom'
// Create a d3 selection for the detached container. We won't
// actually be attaching it to the DOM.
var dataContainer = d3.select("body")
.append("custom:container");
// Function to create our custom data containers
function drawCustom(data) {
var scale = d3.scale.linear()
.range([10, 390])
.domain(d3.extent(data));
var dataBinding = dataContainer.selectAll("rect")
.data(data, function(d) { return d; });
dataBinding
.attr("size", 8)
.transition()
.duration(1000)
.attr("size", 15)
.attr("fillStyle", "green");
dataBinding.enter()
.append("custom:rect")
.classed("rect", true)
.attr("x", scale)
.attr("y", 100)
.attr("size", 8)
.attr("fillStyle", "red");
dataBinding.exit()
.attr("size", 8)
.transition()
.duration(1000)
.attr("size", 5)
.attr("fillStyle", "lightgrey");
}
// Function to render out to canvas our custom
// in memory nodes
function drawCanvas() {
// clear canvas
context.fillStyle = "#fff";
context.rect(0,0,chart.attr("width"),chart.attr("height"));
context.fill();
// select our dummy nodes and draw the data to canvas.
var elements = dataContainer.selectAll("rect");
elements.each(function(d) {
var node = d3.select(this);
context.beginPath();
context.fillStyle = node.attr("fillStyle");
context.rect(node.attr("x"), node.attr("y"), node.attr("size"), node.attr("size"));
context.fill();
context.closePath();
})
}
d3.timer(drawCanvas);
drawCustom([1,2,13,20,23]);
drawCustom([1,2,12,16,50]);