Canvas vs SVG

by IPWright83

HTML

<svg width="500" height="500" />
<canvas id="c1" width="500" height="500"></canvas>
<canvas id="c2" width="500" height="500"></canvas>
<canvas id="c3" width="500" height="500"></canvas>

CSS

circle {
  fill: red;
}

svg { position: absolute; opacity: 0.5; }
canvas { position: absolute; opacity: 0.5;  }

JavaScript

const width = 500;
const height = 500;

const measure = (title, func) => {
	const start = performance.now();
  func();
  const end = performance.now();
  console.log(`${title}: ${end - start} ms`);
};

const max = 2500;
const data = d3.range(0, max, 1);

measure("enter", () => {
	d3.select("svg")
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("r", 5)
    .attr("cx", d => d)
    .attr("cy", d => d);
});

measure("enter-virtual", () => {
	const context = d3.select("#c1").node().getContext("2d");
  const detachedContainer = document.createElement("custom");
  
  context.clearRect(0, 0, width, height);
  
	d3.select(detachedContainer)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("r", 5)
    .attr("cx", d => d)
    .attr("cy", d => d)
    .each(d => {
      const r = 5;
      const cx = d;
      const cy = d;
      context.beginPath();
      context.arc(cx, cy, r, 0, 2 * Math.PI);
      context.fillStyle = "steelblue";
      context.fill();
    })   
});

measure("enter-virtual-no-attrs", () => {
	const context = d3.select("#c1").node().getContext("2d");
  const detachedContainer = document.createElement("custom");
  
  context.clearRect(0, 0, width, height);
  
	d3.select(detachedContainer)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    /* .attr("r", 5)
    .attr("cx", d => d)
    .attr("cy", d => d) */
    .each(d => {
      const r = 5;
      const cx = d;
      const cy = d;
      context.beginPath();
      context.arc(cx, cy, r, 0, 2 * Math.PI);
      context.fillStyle = "steelblue";
      context.fill();
    })   
});

measure("virtual-no-join", () => {
	const context = d3.select("#c2").node().getContext("2d"); 
  context.clearRect(0, 0, width, height);
  
	data.forEach(d => {
      const r = 5;
      const cx = d;
      const cy = d;
      context.beginPath();
      context.arc(cx, cy, r, 0, 2 * Math.PI);
      context.fillStyle = "green";
     ...