https://jsfiddle.net/Goulu/gyf74p9q/ shows a reusable D3js class implementation of http://bl.ocks.org/tommct/8047063, where a svg layer is superimposed over a canvas to handle the pan & zoom event
constructor(div,width,height) {
this.width = width;
this.height = height;
// Canvas is drawn first, and then SVG over the top.
this.canvas = div.append("canvas")
.attr("width",width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.style("left", margin.left + "px")
.style("top", margin.top + "px")
.style("width", width + "px")
.style("height", height + "px")
.style("position", "absolute")
.style("z-index",0)
.on('click', () => {
// Get coordinates of click relative to the canvas element
let pos = d3.mouse(this.canvas.node());
console.log('canvas click ' + pos);
});
this.svg = div.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.style("position", "absolute")
.style("z-index",1)
.on('click', () => {
// Get coordinates of click relative to the canvas element
let pos = d3.mouse(this.svg.node());
console.log('svg click ' + pos);
});
// We make an invisible rectangle to intercept mouse events
this.rect=this.svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "000")
.style("opacity", 1e-6)
.style("position", "absolute")
.style("z-index",2)
.on("click", () => {
let pos = d3.mouse(this.rect.node());
console.log('rect click '+pos);
})
console.log('Figure created')
}
When run in JSfiddle it runs perfectly (well, the zoom isn't ok yet...) but when clicking on the image, the console shows that events are intercepted by the svg and the rect, not the canvas, as it should be.
Now when running exactly the same code on my machine, by opening an html document with the following content (and the JSFiddle script in image.js), the log shows that the clicks are handled by the canvas only !!!
How is this possible ? I just lost hours on this ...
<!DOCTYPE html>
<meta charset="utf-8">
<title>Canvas image zoom</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
<body>
<h1>D3 zoomable image class</h1>
<div id="figure" style="float:left; position:relative;"></div>
</body>
<script src="image.js" type="text/javascript"></script>
<script>
let masterImg = new Image();
let figure = new Figure(d3.select("div#figure"), 640, 480);
masterImg.onload = function() {
figure.loaded(masterImg)
};
masterImg.src = "http://www.dieselstation.com/wallpapers/albums/Lincoln/Mark-X-Concept-2004/Lincoln-Mark-X-Concept-2004-widescreen-03.jpg";
</script>
</html>
BTW, why did the original author add a svg rect over the canvas instead of handling the events and zoom directly by the canvas ?