D3 call method question

Is it possible to select an element after you have called for it with the call() method? Trying to see if I can select the tip and then apply the attribute, ‘data-year’, to it. I can’t do this in the definition of the tip itself as there is no data being passed into it. Should I be using the ‘this’ keyword somehow? Thank you for reading

This is how I’m currently trying to select the tip.

  .call(tip)
  .on("mouseover", tip.show)
  .on("mouseout", tip.hide)
  .select('tip')
  .attr('data-year', d=>d['Year'])

Adding tooltips to each data item - you can just change the tip onto the data point.

// Bind data
  var dots = chart.selectAll("circle")
    .data(data)
    .enter().append("circle")
    .attr("r", 5)
    .attr("cx", function(d, i) { return xAxisScale(d.Seconds - fastestTime); })
    .attr("cy", function(d, i) { return  yAxisScale(i+1); }) // i+1 is the same as using d.Place
    .style("fill", function(d) { return d.Doping !== '' ? "orange" :  "green" })   
    .on("mouseover", function(d) {
       div.transition()
         .duration(200)
         .style("opacity", 1.0);
      var htmlCode = d.Name + ' ' + '[' + d.Nationality + ']' + '<br/>' +
         'Time: ' + d.Time + ', Year: ' + d.Year + '<br/>' +
          'Doping allegation: ' + (d.Doping !== '' ? d.Doping : 'none');
       div.html(htmlCode)
         .style("left", (d3.event.pageX) + "px")
         .style("top", (d3.event.pageY - 28) + "px");
       })
    .on("mouseout", function(d) {
       div.transition()
         .duration(200)
         .style("opacity", 0);
       });

The show hide effect is done by changing the opacity of the div.

@JohnnyBizzel Thanks you for your post. I should’ve mentioned that I was using the d3-tip library and not doing it this way. I mainly wanted to know how to get attributes onto the tip while still using the library.

link to the library I am talking about: https://github.com/Caged/d3-tip

Hi!

I can’t do this in the definition of the tip itself as there is no data being passed into it. Should I be using the ‘this’ keyword somehow?

I think the problem you are having might be rooted in 3 aspects:

  • JS basics.
  • Functional programming.
  • Declaration order.

The call method is in this case a JS function method. It will assign/lend a function coming to an existing object/class from another function/object argument of the call.

Now, due to the order you are suggesting when declaring the methods, you might have not passed any additional functionality to the borrowing function when making the call for tip.

It is one way. Any additional change you made over the borrower function afterwards won’t modify tip: at that point if you want to change something related to tip, you will have to do it over tip.

That is the same for ANY functionality subject to a call method.

A simple example of an implementation of a call method:

https://www.w3schools.com/js/js_function_call.asp

I think this is the reason? Was that your question?

1 Like

Also, @Siegeprogrammer, if I am not wrong with d3.js it appears that the ons are made over a non-existing selection. I think you have to select before adding behaviour.

@evaristoc. There is actually a selection already being made. It is the circle itself that is currently selected. In my code, i don’t think i can select the tooltip with ‘tip’ because that isn’t a valid tag to be selected. I tried selecting it with the id (#tooltip) but I don’t think it works either.

I am not sure why you want to add behaviour before defining the attribute.

I have stopped a bit with d3 as I am busy with something else now but I would do:

  • the call assigned to a separate variable, as in the github example; otherwise it might be that the whole line runs without creating instances
  • the selection over that new create instances, assigning attributes and then the events.

I also advise you to verify the d3 lifecycle.

Hope this helps?

@evaristoc I can’t define the attribute whenever during the instantiation of the tip, by this I mean

var tip = d3
  .tip()
  .attr("id", "tooltip")
  .style("background-color", "lavender")
  .html(
    d =>
      d.Name +
      " " +
      "[" +
      d.Nationality +
      "]" +
      "<br/>" +
      "Time: " +
      d.Time +
      ", Year: " +
      d.Year +
      "<br/>" +
      "Doping allegation: " +
      (d.Doping !== "" ? d.Doping : "none")
  );

If I were to add a line that says

attr('data-year', d=>d['Year'])

It will not work, I find it a bit odd that the html method call can access my dataSet through d=>‘some function’. But I can’t do the same with the attr method.

d3.tip doesn’t have the attribute data-year defined : https://github.com/Caged/d3-tip/blob/master/index.js. It has what it looks an attr builder though (line 77). After inspecting the code it appears that values for attr in tip are not defined as functors as for html and other methods of tip. It is then likely that functionality that allows that attribute to collect data, like in attr(‘data-year’, d=>d[‘Year’]) is not defined for attr in tip. Not sure if that is the reason though. In my opinion, there should be a way to make it work as you expect. However I don’t know if that is what you want (initializing tip with the data-year attribute)? And if so, why?

It appears that the behaviour assigned to the created data-year attribute is well defined on the calling function.

What I wanted to say in the previous post was to recommend you to follow the example as in the readme of d3.tip repository: https://github.com/Caged/d3-tip. There are reasons for that.

And this affirmation I made:

is NOT TRUE! Now I seem to remember that what happened was that by keeping it joined the attributes that you joined to the d3 instance will stay the same and you won’t be able to modify them. Anyway, as I said I have some time not using d3.