Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I add eventListener to every SVG element if I follow normal D3 way?

The normal way of handling onclick in d3 is

selection.append(element)
    .on("click", someFunction)

If I do it this way on 1000 svg elements, does it mean I just attached 1000 different listeners. If this is the case, is there event delegation for d3 specifically?

like image 412
Loredra L Avatar asked Jan 03 '18 14:01

Loredra L


People also ask

How do you make EventListener work only once?

Using the once option We can pass an object as an argument to the addEventListener method and specify that the event is only handled once. This is achieved by passing the property once to the object. If we set once to true, the event will only be fired once.

Can we group SVG elements in d3js?

The <g> SVG element is a container used to group other SVG elements. Transformations applied to the <g> element are performed on its child elements, and its attributes are inherited by its children. We can create a group element with D3. js by appending a g element using any selection.

Can you add an EventListener to a function?

The method addEventListener() works by adding a function, or an object that implements EventListener , to the list of event listeners for the specified event type on the EventTarget on which it's called.

Does SVG support event handlers?

For every event type that the browser supports, SVG supports that as an event attribute, following the same requirements as for HTML event attributes. The global event attributes are available on all SVG elements. Other event attributes are available on a case by case basis for each elements.


2 Answers

@AlexW answer is (partially) correct: there is no event delegation in D3, only event binding.

However, I said partially because it'd be better saying that "there is no native method for event delegation in D3", since in fact it's quite ease to implement it: the ugly alternative to do event delegation with D3 consists in using d3.event.target.

For instance, in this very simple demo, we bind this data...

var data = ["foo", "bar", "baz"];

... to the circles inside an <g> element. Then, we bind an event listener to the group, and get the datum of each circle on click:

g.on("click", function() {
  console.log(d3.select(d3.event.target).datum())
})

Here is it:

var svg = d3.select("svg");
var g = svg.append("g");
var data = ["foo", "bar", "baz"];
var circles = g.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("cy", 40)
  .attr("cx", function(_, i) {
    return 50 + 100 * i
  })
  .attr("r", 20)
  .attr("fill", "teal");

g.on("click", function() {
  console.log(d3.select(d3.event.target).datum())
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

The nice thing about this approach is that, just as a jQuery event delegation, it works with elements created after the listener was defined. In the following demo, the red circle:

var svg = d3.select("svg");
var g = svg.append("g");
var data = ["foo", "bar", "baz"];
var circles = g.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("cy", 40)
  .attr("cx", function(_, i) {
    return 50 + 75 * i
  })
  .attr("r", 20)
  .attr("fill", "teal");

g.on("click", function() {
  console.log(d3.select(d3.event.target).datum())
});

g.append("circle")
  .attr("cy", 40)
  .attr("cx", 275)
  .attr("r", 20)
  .attr("fill", "firebrick")
  .datum("foobar")
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

So, despite D3 not having a native, explicit method for event delegation, the solution is quite simple and straightforward.

like image 192
Gerardo Furtado Avatar answered Nov 08 '22 20:11

Gerardo Furtado


Yes this would add 1000 event listeners:

Adds or removes a listener to each selected element for the specified event typenames.

https://github.com/d3/d3-selection/blob/master/README.md#selection_on

If you have 1000+ elements, you may not want to use SVG, as the DOM gets easily bogged down with that many elements. It may be more efficient to use a canvas, etc.

D3 doesn't do event delegation it only does event binding. So you may want to implement the delegation using jQuery or vanilla JS, if you're still considering using SVG.

like image 28
Alex W Avatar answered Nov 08 '22 20:11

Alex W