score:2
this is an interesting question, although i have to admit, that i have never come across this problem in a real world application. the reason why this happens is to be found in the inner workings of d3's drag implementation.
first, it is worth mentioning, that, if you remove an element from the dom tree, it can no longer become a target when performing hit-testing for a pointer event. thus, no event listener registered on that element will be executed any more. this is the behavior one would expect and it is the reason for your confusion, because in your jsfiddle the listener seems to executed even though the element was successfully removed.
to understand what is going on, you have to dig into the source code of d3.drag()
. on initialization the drag behavior registers various event handlers on the selection's elements:
function drag(selection) {
selection
.on("mousedown.drag", mousedowned)
//...
}
this handler listening for mousedown
events will not set up the rest of the drag behavior before such an event is fired on the respective element. once an element of the drag behavior receives a mousedown
event, the internal mousedowned()
handler will be executed:
function mousedowned() {
//...
select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
//...
}
within this handler a "mousemove.drag"
and a "mouseup.drag"
listeners are registered on event.view
. this view
property of the mouseevent
is inherited from the uievent
interface and—at least in browsers—points to the window
object the event happened in. those drag handlers on the global window
are used by d3-drag to do its work. and those handlers are responsible for the seemingly confusing behavior you witnessed. we will come to this soon, first let us check how the listeners are subsequently removed.
when the drag gesture eventually ends by firing a mouseup
event, those handlers are removed from the window
object in the function mouseupped()
:
function mouseupped() {
select(event.view).on("mousemove.drag mouseup.drag", null);
}
now, let us have another look at your code. even though you removed the target for the drag behavior triggered by a keydown
event, the aforementioned handlers on the window
still exist because you are keeping the mouse button pressed whereby suppressing a mouseup
event to be fired. hence, the mouseupped()
handler has not yet been executed. this will keep the drag behavior alive as mousemove
events are still captured by the drag's internal handlers on window
. additionally, those internal handlers will also keep delegating to your own dragged
handler causing the console output you are witnessing.
as mentioned at the very beginning of this post, i have never seen this causing any real world trouble. if you nonetheless want to avoid this behavior you could remove the internal handlers once you remove the target:
d3.select(window).on("keydown", function() {
d3.select(".draggable-rect").remove();
d3.select(d3.event.view) // remove global (internal) drag handlers
.on("mousemove.drag", null)
.on("mouseup.drag", null);
})
as is always the case when it comes to fiddling with the inner workings of some library, you have to be cautious not to break other things and to keep in mind that this is in danger of breaking silently with any future release of d3.
have a look at this working demo:
d3.select("svg").append('rect').attr('class', 'draggable-rect');
d3.select(window).on("keydown", function() {
d3.select(".draggable-rect").remove();
d3.select(d3.event.view)
.on("mousemove.drag", null)
.on("mouseup.drag", null);
})
d3.select(".draggable-rect")
.call(d3.drag().on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
console.log("dragging")
d3.select(this).attr("x", d3.event.x - 40).attr("y", d3.event.y - 40);
}
function dragended(d) {
d3.select(this).classed("active", false);
}
.test-area {
width: 400px;
height: 400px;
border: 1px solid black;
}
svg {
width: 400px;
height: 400px;
}
.draggable-rect {
width: 80px;
height: 80px;
fill: green;
}
<script src="https://d3js.org/d3.v4.js"></script>
<div class="test-area">
<svg>
</svg>
</div>
Source: stackoverflow.com
Related Query
- How to remove event listener of an element when I remove the corresponding element in the midst of the event being triggered in D3?
- How to remove the onmouseout event after having assigned a function?
- How to show the value of each element when hovering
- Datamaps: how to show popup on mouseover AND customize the mouseover event listener
- How to properly control the context when using d3.json event handler
- D3.js how to write pop-out box that appears when the user clicks on an element
- How do I find the associated DOM element when I have the Data object in D3?
- How do I pass event variable/place a marker on the map - when binding done events in Datamaps & D3?
- With d3.js, how do you modify corresponding nodes when you have multiple selections for the same data?
- How can I remove drag event on one element in a draggable group?
- How to prevent the on ("click") event from activating when I'm doing drag?
- D3 - How can I show/hide a text element when hovering a circle element created from different attributes of the same data entry?
- D3.js: How to create the pop-up event when moving mouse on the svg?
- How can I toggle the value of an svg text element with D3.js when user clicks the text?
- How to forcefully call the drag event right after the creation of an dom element in d3?
- D3 V4 assigning a listener to d3.brushX when the element is first rendered
- How to remove the border on the hover element in nvd3
- How to access the DOM element that correlates to a D3 SVG object?
- d3.select("#element") not working when code above the html element
- How do I get the width of an svg element using d3js?
- d3.js - How can I set the cursor to hand when mouseover these elements on SVG container?
- How to update elements of D3 force layout when the underlying data changes
- How do you remove the background gridlines in nvd3.js?
- SVG element loses event handlers if moved around the DOM
- How do you make an SVG element mouse event bubble up through another element?
- mouseout/mouseleave gets fired when mouse moves INSIDE the svg path element
- D3: How do I set "click" event and "dbclick" event at the same time?
- D3.js v4: Access current DOM element in ES6 arrow function event listener
- why isn't the checkbox change event triggered when i do it programatically in d3js
- How to show and hides nodes when you move the mouse over a node in D3 Javascript
More Query from same tag
- d3 - how to format date on x-axis
- D3 chart: How to align zero points of dual y axes
- Drag points with Lat/Lng inputs
- In Hierarchical edge bundling how to use json string instead of a json file?
- How to display D3 Color legend horizontally and not vertically
- Redrawing the stack bar chat on click on the toggle legend using D3.js
- How to structure nested nodes that need updating in d3 v4 force layout?
- Multiple d3 charts in the same row
- Difference between js syntax
- Chart in d3js not showing up in react app
- SVG nodes in D3 force layout moves on node scale
- Zooming in a d3js force simulation on a canvas
- Convex hull around D3 Force network graphic
- Increasing the Pseudo-Area of D3 Path Link For Easier D3-Tip Event Trigger
- d3 stacked to grouped bar chart date axis
- Time range selector with resize handles in Vega
- Adding elements from subarrays d3.js
- Referencing parent id in d3 after data()
- Y range origin seems to be off for one point?
- Text and Rectangle not align
- How do I add density or heat map to this scatter plot?
- Populating D3 chart with external JSON file
- How to get SVG child element position relative to SVG position on page, D3.js?
- nvd3.js - show unique text per symbol on user interaction
- D3 stacked graphs issue with bar position on x-Axis
- hide/Show Grid lines using a button D3
- Line Highlights but dots dont
- D3 - display x value data ticks as percentages
- Extract array from one json variable
- Dimple.js bar length