0

I am trying to have a mouse hover event where the circle radius gets bigger, and the corresponding data label increases font size. The data labels are on the circle, in the graph itself. So my idea was to have two functions, one to style the circles nice and smooth with a transition, and use a separate function with tweening to style the text. I want to call both functions at the same time and have them only style objects with data binding matching its 'id'. Id is just an index that I parsed from the .tsv. The idea is both the text and the circle have the same 'id'.

!boring circle svg code above
.on('mouseenter', function(d) {circle_event(this); text_event(this);})

function circle_event(id) {
    if (d3.select(this).data==id) {
        d3.select(this)
        .transition()
        .attr('r', radius*1.5)
        .duration(500);
    }
}

function text_event(id) {
    if (d3.select(this).data==id) {
        d3.select(this)
        .transition()
        .styleTween('font', function() {return d3.interpolate('12px Calibri', '20px Calibri' )
        .duration(500);
    }
}

For some reason when I hover over the circles, nothing happens. Dev tools didn't have any errors. If I had to guess, I have misunderstood how to use d3's select functions.

Thank you

EDIT

Please note I need to call the circle and text style functions simultaneously I will accept the answer that shows how to style the circle and its corresponding data_label text JUST by mousing over the CIRCLE. It seems this cannot be used as a circle and a text object concurrently. Other solutions aside from this-based are welcome.

Arash Howaida
  • 2,575
  • 2
  • 19
  • 50

3 Answers3

2

It looks like you edited your question which changes things considerably. Here is one approach that could work or be modified to make it work:

// Assumes circle & text objects have the same .x, .y and .id data bound to them and that 
// when created, they each have classes "circle-class" and "text-class" respectively

!boring circle svg code above
.on('mouseenter', function(d) {circle_event(d.x, d.y, d.id); text_event(d.x, d.y, d.id);})

function circle_event(x, y, id) {
    d3.selectAll(".circle-class")
    .filter(function (d) {
      return (d.x === x) && (d.y == y) && (d.id == id);
    })
      .transition()
      .attr('r', radius * 1.5)
      .duration(500);
}

function text_event(x, y, id) {
  d3.selectAll(".text-class")
    .filter(function (d) {
      return (d.x === x) && (d.y == y) && (d.id == id);
    })
      .transition()
      .styleTween('font', function() {return d3.interpolate('12px Calibri', '20px Calibri' )
      .duration(500);
}

Alternatively, if you structure the creation of the circle and text DOM elements such that they have a sibling relationship, you could get a reference to the text selection using d3.select(this.previousElementSibling) where this is the circle node that is being moused over (See here - How to access "previous sibling" of `this` when iterating over a selection?). Such an approach could use the code in my previous reply above.

Community
  • 1
  • 1
HamsterHuey
  • 1,223
  • 10
  • 11
  • Well actually its still the exact same question. In the original post I said I didn't know how to style two objects at the same time. It was just one sentence though, and most people probably glossed over it -- hence the confusion. That's my fault, my edits to the post were to make the key problems clearer. – Arash Howaida Jan 11 '17 at 01:49
  • I also tried you solution, it worked perfectly once I changed my `.attr('class',...)` to match. I actually only needed to pass `d.id` for it to work. Thank you so much for the great explanation too. – Arash Howaida Jan 11 '17 at 01:50
  • Glad it worked. I answered originally at 4am, so I could very well have misread/misunderstood your original question! Cheers. – HamsterHuey Jan 11 '17 at 03:03
0

Your primary issue is that this is not what you want it to be in your nested function. It is no longer bound to your circle DOM node that was being hovered over but instead is referencing the global window.

More info on the scoping of this in javascript can be found here:

Javascript "this" pointer within nested function

http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/

Try changing to this:

!boring circle svg code above
.on('mouseenter', function(d) {circle_event(this, d.id)})

function circle_event(selection, id) {
    if (d3.select(selection).data==id) {
        d3.select(selection)
        .transition()
        .attr('r', radius*1.5)
        .duration(500);
    }
}

function text_event(selection, id) {
    if (d3.select(selection).data==id) {
        d3.select(selection)
        .transition()
        .styleTween('font', function() {return d3.interpolate('12px Calibri', '20px Calibri' )
        .duration(500);
    }
}
Community
  • 1
  • 1
HamsterHuey
  • 1,223
  • 10
  • 11
  • You dont need `d.id` as `this` is already the selected circle – Tim B Jan 10 '17 at 09:54
  • @Tim B - While that is true, it seems simpler to pass it in while you have it handy rather than relying on something like `d3.select(this).datum().id` within the function. – HamsterHuey Jan 10 '17 at 17:07
0

You should pass this in the function :

.on('mouseenter', function(d) {circle_event(this)})

function circle_event(item) {
        d3.select(item)
        .transition()
        .attr('r', radius*1.5)
        .duration(500);
}

function text_event(item) {
        d3.select(item)
        .transition()
        .styleTween('font', function() {return d3.interpolate('12px Calibri', '20px Calibri' )
        .duration(500);
}

You dont need d.id as this is already the selected circle

Tim B
  • 1,983
  • 1
  • 20
  • 21
  • 1
    so I do not need any if statements, since `this` already discerns which item. That's interesting. – Arash Howaida Jan 10 '17 at 10:00
  • My hover event- `.on('mouseenter', function(d) {circle_event(this); text_event(this);})` stops working when I try to call two functions at the same time, what should I do? I thought adding semi colons lets you call more than one function. Error throws a d3.js undefined computed style. – Arash Howaida Jan 10 '17 at 13:48
  • `this` is a circle, you can't use `.styleTween('font', ...)` on it – Tim B Jan 10 '17 at 14:02
  • I suppose that makes sense, I should have made it clearer in my question. I'm actually trying to style both circles and the circle's label simultaneously with one mouse event, that's why I originally tried to use the d.id technique, since that is one thing the text and the circles had in common. Is there any way to use `this` across different object classes? If not, can you tweak your answer in some other way to make it robust to multiple object classes if it's not too much trouble? – Arash Howaida Jan 10 '17 at 14:36
  • I will be more than happy to accept your answer, again once we straighten that out. I will take the blame for not making the important information clear enough. I added some bold face and caps in the post for clarity. Thank you for your continued patience and tips. – Arash Howaida Jan 10 '17 at 16:21