D3.js v4: Access current DOM element in ES6 arrow function event listener

北战南征 提交于 2019-11-27 04:46:03

问题


In D3.js v4, when registering an event listener through a traditional callback function, this references the current DOM element:

d3.select("div").on('mouseenter', function() {
  d3.select(this).text("Yay");
});

ES6 offers arrow functions, which IMHO make D3.js code a lot more readable because they are very concise. However, traditional callbacks cannot blindly be replaced with arrow functions:

d3.select("div").on('mouseenter', () => {
  d3.select(this); // undefined
});

The article "On D3 and Arrow Functions" gives a very good explanation of why this is not bound as expected. The article suggests using traditional callbacks for code that needs access to the current DOM element.

Is it possible to access the current DOM element from an arrow function?


回答1:


There is an idiomatic way of doing this in D3: just use the less famous third argument:

selection.on("mouseenter", (d, i, nodes) => {
    d3.select(nodes[i]);
});

And that's the same of:

selection.on("mouseenter", function() {
    d3.select(this);
});

I wrote an example here: d3 v4 retrieve drag DOM target from drag callback when `this` is not available

Here is a demo:

d3.selectAll("circle").on("mouseover", (d, i, p) => {
        d3.select(p[i]).attr("fill", "maroon")
    })
    .on("mouseout", (d, i, p) => {
        d3.select(p[i]).attr("fill", "seagreen")
    });
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
	<circle cx="50" cy="50" r="20" fill="seagreen"></circle>
	<circle cx="125" cy="50" r="20" fill="seagreen"></circle>
	<circle cx="200" cy="50" r="20" fill="seagreen"></circle>
</svg>

Actually, if you look at the end of the article you linked, he gives the same solution.

Your proposed solution, d3.event.target, despite working for event listeners, does not work in several situations. For instance:

d3.selectAll("circle").each(()=>d3.select(d3.event.target).attr("fill", "red"))
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
	<circle cx="50" cy="50" r="20" fill="seagreen"></circle>
	<circle cx="125" cy="50" r="20" fill="seagreen"></circle>
	<circle cx="200" cy="50" r="20" fill="seagreen"></circle>
</svg>

But the same code works using the third argument:

d3.selectAll("circle").each((d,i,p)=>d3.select(p[i]).attr("fill", "red"))
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg>
	<circle cx="50" cy="50" r="20" fill="seagreen"></circle>
	<circle cx="125" cy="50" r="20" fill="seagreen"></circle>
	<circle cx="200" cy="50" r="20" fill="seagreen"></circle>
</svg>



回答2:


It is possible to use an ES6 arrow function and access the current DOM element via d3.event.target:

d3.select("div").on('mouseenter', () => {
  d3.select(d3.event.target).text("Yay, this works!");
});


来源:https://stackoverflow.com/questions/41532635/d3-js-v4-access-current-dom-element-in-es6-arrow-function-event-listener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!