Unable to get node datum on mouseover in D3 v6
D3v5 and earlier
In d3v5 and earlier we could use the pattern:
selection.on("eventType", function(d,i,nodes) { .... })
Where d
is the datum of the element triggering the event, i
is its index, and nodes
the current group of elements. Event information could be accessed within the event listener with d3.event
.
D3v6
In d3v6 the pattern has been changed:
selection.on("eventType", function(event, d) { .... })
Now the event is passed directly to the listener as the first parameter, the datum is now the 2nd parameter passed to the listener. As part of this change d3.event
has been removed.
As stated in the documentation:
D3 now passes events directly to listeners, replacing the d3.event global and bringing D3 inline with vanilla JavaScript and most other frameworks. (source)
This change applies to brush.on
, transition.on
, and drag.on
, zoom.on
as well as selection.on
.
this
You can still use d3.select(this)
in the event listener function as you did prior to d3v6. However, if using arrow functions, this
will have a different scope. In d3v5 and earlier you could use:
(d,i,nodes) => d3.select(nodes[i])...
In d3v6+ you can use (for selection.on()
):
(event,d) => d3.select(event.currentTarget)...
Positioning
To get the x,y position of the triggering event, where you would have used d3.mouse(this)
, you can now use:
d3.pointer(event);
Where you would have used d3.event.x
and d3.event.y
, in d3v5, you would now use:
event.x, event.y
Example
Below is a simple example of passing the event and the datum to the listener function in D3v6. The snippet uses d3.pointer() to get the x,y properties of the click relative to the SVG. Click on a rectangle to get the rectangle's datum and the x and y properties of the event logged to console:
var svg = d3.select("body")
.append("svg");
svg.selectAll("rect")
.data([1,2,3])
.enter()
.append("rect")
.attr("width",30)
.attr("height",30)
.attr("x", function(d) { return d*50; })
.on("click", function(event, d) {
console.log(d);
console.log(d3.pointer(event));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.0.0/d3.min.js"></script>
D3.js v6.2 - get data index in listener function - selection.on('click', listener)
The Observable notebook on the new features in d3-selection 2.0 suggests using a local variable to preserve the index:
Listeners are no longer passed the selected element’s index (i) or siblings (nodes). These were rarely used, had confusing behavior if elements were re-selected, and could cause memory leaks. If you need them, bake them into the element’s data or use a local variable instead.
This can be done with little effort along the following lines:
let data = [2,5,8,9]
const index = d3.local(); // Local variable for storing the index.
d3.select("body").selectAll("p")
.data(data)
.enter()
.append("p")
.text(d=>d)
.each(function(d, i) {
index.set(this, i); // Store index in local variable.
})
.on("mouseover", function(e,d,i){
console.log(d);
console.log(index.get(this)); // Get index from local variable.
});
<script src="https://d3js.org/d3.v6.min.js"></script>
Hover on data point returns undefined in D3.js line chart
I think you need to adjust your event listeners.
As an example, in the "mouseover" function, the first argument is the mouse event, and there is a second argument which is the data attached to the element that dispatched that event...
.on("mouseover",(event, d)=>{
//check what we're passing to the m_over function
console.log('data:', d);
m_over(d);
})
Here's a really simple example illustrating the concept
https://codepen.io/tomp/pen/wveRNmV
D3 event listeners returning MouseEvent instead the datum
In the latest version, d3 v6, the API for events has changed:
selection.on("mouseenter", function(event, d) {
const e = selection.nodes();
const i = e.indexOf(this);
console.log(d, i, e);
})
If you want to use the v5 API, use in your HTML:
<script src="https://d3js.org/d3.v5.min.js"></script>
d3.js undefined data value in callback function click event
Replace
group1.on("click",d => console.log(d.value));
with
group1.on("click",(e, d) => console.log(d.value));
Since D3 V6, event is passed as the first argument to the mouse event callbacks
d parameter returns undefined in a .on event
It's because the "click" event gives you the event
param first, then the datum
:
When a specified event is dispatched on a selected element, the specified listener will be evaluated for the element, being passed the current event (event) and the current datum (d), with this as the current DOM element (event.currentTarget). Listeners always see the latest datum for their element.
Related docs
I think you're looking for this:
const countries = [
{
location: 'USA',
},
{
location: 'Canada',
}
];
const buttons = d3.select("body")
.selectAll('button')
.data(countries)
.enter()
.append("button")
.text((d) => { return d.location; }) // returns name location
.attr("value", (d) => { return d.location; }) // returns name location
.on("click", (e, d) => { console.log(d.location) }); // returns name location
Related Codepen
d3 why on mousehover field is undefined and d3.event is undefined too?
There are a couple of problems. First, you have the order of the parameters swapped in your event listener. The first parameter is the event and the second parameter is the datum. Second, rather than d3.event.pageX
and d3.event.pageY
, you can use event.pageX
and event.pageY
.
Here's an example:
.on("mouseover", (event, d) => {
tooltip.style("opacity", .7)
.style("left", (event.pageX + 3) + "px")
.style("top", (event.pageY + 5) + "px")
.html(d.area + "%");
})
.on("mouseout", (event, d) => {
tooltip.style("opacity", 0)
})
D3 Tooltip issues with displaying d on hover
Try below:
chart.selectAll("rect").on("mouseover", function(event, d){
return tooltip.style("visibility", "visible")
.text(d.name + " - " + d.calories + " cal");
})
I see two mistakes:
- When you assign
mouseover
event, you need to do it on eachrect
, not onchart
. Sochart.selectAll("rect").on
part fixes it. mouseover
handler function's first argument isevent
notdata
. The second one isdata
. So you need to dofunction(event, d)
instead offunction(d)
Here is the updated example: https://codepen.io/cypark/pen/NWrdpzd
Related Topics
Iframe Src Change Event Detection
Advantages of Createelement Over Innerhtml
Seedable JavaScript Random Number Generator
Maximum Size of an Array in JavaScript
Preserving a Reference to "This" in JavaScript Prototype Functions
Async/Await Always Returns Promise
Selecting Null: What Is the Reason Behind Selectall(Null) in D3
Most Efficient Way to Convert an HTMLcollection to an Array
How to Use Async/Await at the Top Level
When to Use Setattribute VS .Attribute= in JavaScript
How to Call a JavaScript Function on Page Load
Invariant Violation: Objects Are Not Valid as a React Child
How to Avoid Bind or Inline Arrow Functions Inside Render Method
Are There Performance Concerns with 'Return Await'
Primitive Value VS Reference Value
Why Avoid Increment ("++") and Decrement ("--") Operators in JavaScript