interwebjill
interwebjill

Reputation: 950

d3: combining canvas + svg for retina

This question is particular to using D3 on a retina canvas, which is the target platform. I have a chart created using the canvas. I created the axes for the chart using svg. I am calling the d3 zoom function on an svg rectangle because I am trying to find a workaround to d3 zoom issues on retina canvas: https://github.com/d3/d3-zoom/issues/133

Here is my result so far: https://bl.ocks.org/interwebjill/cc5361ca1d1c5538fab19999785c6d01

I can capture the zoom event with an overlapping svg rectangle. The only adjustment that needs to be made is to reset the zoom center of the canvas to half that of the rectangle. But d3 v4 no longer has zoom.center() as v3 did.

Upvotes: 0

Views: 307

Answers (1)

Wouter Verweirder
Wouter Verweirder

Reputation: 606

You should use the width and height instead of the canvasWidth and canvasHeight values for the ranges:

var xSVG = d3.scaleTime()
    .range([0, width]);

var x = d3.scaleTime()
    .range([0, width]);

var x2 = d3.scaleTime()   // for zooming
    .range([0, width]);

var ySVG = d3.scaleLinear()
    .range([height, 0]);

var y = d3.scaleLinear()
    .range([height, 0]);

In the draw logic, you can add a context.scale(2, 2) to draw everything twice as big. Again, swap all canvasWidth & canvasHeight values with width & height, as the context.scale will take care of the rest

function draw() {
  context.save();
  context.scale(2, 2);
  context.clearRect(0, 0, width, height);

   // clip path
   context.beginPath()
   context.rect(0, 0, width, height);
   context.clip();

   for (i=0; i<len; i++) {
     context.beginPath();
     area(sources[i].values);
     context.fillStyle = color(sources[i].id);
     context.fill();
   }

   context.restore();
}

Upvotes: 1

Related Questions