By now, you’ve set up so many Canvases that, at worst, this code just bores you:
var hiddenCanvas = d3.select('#canvas-container').append('canvas')
.attr('id', 'canvas-hidden')
.attr('width', width)
.attr('height', height);
var hiddenContext = hiddenCanvas.node().getContext('2d');
The only thing we want to make sure of here is to apply the same width and height that we applied to the main Canvas.
Next, we will draw the world to it. In order to do so, we have to build a projection and path generator and then loop through all countries to draw each country to the Canvas; let's do that:
var hiddenProjection = d3.geoEquirectangular()
.translate([width / 2, height / 2])
.scale(width / 7);
var hiddenPath = d3.geoPath()
.projection(hiddenProjection)
.context(hiddenContext);
We, of course, need a new path generator, as we need to feed our now hidden drawing context to the .context() method. However–hold on–we already have a projection for the main Canvas. Shouldn’t we use it for the hidden Canvas also? Especially, as we said above that ideally the objects on our hidden Canvas should be in the exact same position as the objects on our main Canvas to query the hidden positions easily? However, here, we use an equi-rectangular projection, which will draw the world in a rather different way to our orthographic projection on the main Canvas. Don’t we need the same projection to produce the same globe?
The answer is no, we don’t need the same projection. When our mouse is on a specific position on the main Canvas, we just need to find the same position on the hidden Canvas. No doubt, the easiest way to do this is to use the exact same coordinates. However, we can also use the main projection’s projection.invert([x,y]) function to retrieve this position’s longitude and latitude values. We will then use the hidden projection to convert the geo-coordinates to pixel coordinates on the hidden Canvas. Long-winded? Yes, a little. However, with a moving object such as a zooming and rotating globe, this saves us from re-drawing the hidden Canvas. We shall see this in action very soon when we build the handler in the third step.
First, let’s draw the hidden Canvas.