I’m working on an application that requires the use of d3.zoom, and I’m bumping into an issue when listening for the mousedown
event. I’ve simplified the problem into the example below.
Basically, I need parent
to act on mousedown
events. However, its grandchild has d3.zoom applied to it. And it appears that d3.zoom prevents mousedown
events from bubbling up. So if I click anywhere inside of grandchild
, parent
won’t receive mousedown
.
One solution I tried that seems to work is to dispatch mousedown
inside of the zoom start
event handler to allow the event to continue bubbling up. But I’m wondering if there is a better solution. Is it considered bad practice to dispatch native JS events? Also, does anyone know if it’s by design for d3.zoom to stop propagation of ‘mousedown’?
.child {
width: 100px;
height: 100px;
background-color: red;
}
.grandchild {
width: 50px;
height: 50px;
background-color: blue;
}
.parent {
width: 200px;
height: 200px;
background-color: yellow;
}
<div class='parent'>
<div class='child'>
<div class='grandchild'></div>
</div>
</div>
<script type="module">
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
const zoom = d3.zoom()
.on('start', function (event) {
// Dispatch 'mousedown' so that it can continue propagating.
if (event?.sourceEvent?.type === 'mousedown') {
d3.select(this.parentNode).dispatch('mousedown', { bubbles: true })
}
console.log('start zoom')
})
.on('zoom', function () {
console.log('zooming')
})
.on('end', function () {
console.log('end zoom')
})
d3.select('.grandchild').call(zoom)
d3.select('.parent').on('mousedown', function () {
console.log('parent received mousedown')
})
</script>