I'm using d3-tip for tooltips on my graph. And am trying to work out if there's an easy way to keep the tooltips open for a brief period of time?
Once I mouseout on the node, it fires the .hide() method, I can never actually hover over the tooltip.
I think I need a way to mouseover the tooltip element so I can fire the .show() method, like so:
tip.on('mouseover', function(d) {
tip.show(d);
}
But I'm not sure how to do this...
I've set up a JSFiddle here.
Any ideas if this is possible?
Thanks in advance!
Here's the result: http://jsfiddle.net/hx8pjwdu/9/
.on('mouseover', function(d) {
d3.select(".d3-tip").transition().style("opacity", "1");
tip.show(d);
})
.on('mouseout', function(d) {
d3.select(".d3-tip").transition().duration(1000).style("opacity", "0").each("end", tip.hide);
});
d3.select(".d3-tip").on('mouseover', function(d) {
d3.select(".d3-tip").transition().style("opacity", "1");
}).on('mouseout', function(d) {
d3.select(".d3-tip").transition().duration(1000).style("opacity", "0").each("end", tip.hide);
});
I added a mouseover event for your d3-tip and made its hide event a fadeout.
Related
I have simple d3 code binding data with circles. An event is fired when mouse hover over the circles. The mouseOver function is also very simple. It just makes tooltip div visible.
It's a client work so I cannot share the full code. But it has the simple structure like below:
function mouseOver() {
tooltip.style("visibility", "visible")
.style("top", d3.event.pageY + "px")
.style("left", d3.event.pageX +"px")
.html('<p>'+'</p>')
}
var circles = g
.selectAll('.circles')
.data(data)
.join('circle')
.attr('class', 'circles')
.attr('cx', d => x(d))
.attr('cy', d => y(d))
.attr('r', r)
.attr('fill', d => colour(d.type))
.attr('fill-opacity', 0.6)
.on('mouseover', mouseOver)
.on('mouseleave', mouseLeave)
circles.exit().remove()
It works well on desktop. But for some reasons, the tooltip doesn't show up on mobile.
I changed the 'mouseover' into 'touchstart' in case it's the reason. To capture if the window ontouchstart, I made like this.
var hover = ('ontouchstart' in window) ?
'touchstart click' : 'mouseover';
Then, in the selection, I changed as below:
.on(hover, mouseOver)
But it still doesn't trigger the event on mobile.
On a side note, I also have bars(rect) with the same setting as circles above but the mouseover event is trigerred on mobile as well as desktop.
I really have no idea why one event works well on mobile although it's fired by 'mouseover' event handler while the other doesn't work at all despite the same setting as the other.
Does anyone have ideas??
I wrote a D3 widget a while back based on the sunburst example on the D3 site - http://bl.ocks.org/kerryrodden/7090426.
The widget was fine and I even submitted it to an open source project (several other people viewed it and tested it). However now, when I try to view the same widget with a different computer (same browser version), I am experiencing an inconsistent behavior with mouseover and mouseenter. When I hover over items, only the first item I hovered over has the opacity set, when I move the mouse within the widget, opacity is not updated.
Here is the broken version:
http://jsfiddle.net/wrdrvr/f5tvsv5v/
var path = svg.datum(data).selectAll("path")
.data(partition.nodes)
.enter().append("path")
.attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring
.attr("d", arc)
.attr('id',function(d) {
return d.name+"-"+d.value;
})
.style("stroke", "#fff")
.style("fill", function(d) {
if (d.depth > 0) {
return color(d.name);
}
}) .each(stash)
.on("mouseover", mouseover)
//.on("mouseenter",mouseover)
.on("mouseleave", mouseleave)
I was able to get it to work as it was supposed to by including a mouseenter, however I did not use it previously and it was not used in the example and I am not sure why I need it here. Can someone please help clarify this?
Updated http://jsfiddle.net/f5tvsv5v/2/
.on("mouseleave", mouseleave)
//.on("mouseover", mouseover)
.on("mouseenter",mouseover)
You should use mouseenter instead of mouseover since mouseover does not buble (http://www.quirksmode.org/dom/events/mouseover.html)
I am making an interactive D3.js visualization with popup/tooltips to the data points so that on a mouseover event, a popup will appear next to the selected point with some information
Currently I have achieved this with the code below - the tooltip appears on mouseover. When the user moves the mouse to another point, the original tooltip disappears and the correct tooltip appears next to the new data point.
However, the mouseout event is not functioning as it should - the tooltip is not disappearing once the mouse leaves the datapoint. If the user does not move the mouse over a new data point, for example, the old tooltip remains there.
Relevant bits of code:
svg.selectAll("path")
//other stuff here
.on("mouseover", function(d) {
div.transition()
.duration(200) //mouseover transition does not seem to work, but that's minor
.style("opacity", .8);
div .html(d.datetime.substring(0,10) )
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 24) + "px")
.attr("display", display);
})
.on("mouseout", function(d) {
div.attr("display", none);
})
//bit of code where I append the tooltip to the right element
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", .8);
});
What am I doing wrong?
Thanks!
none is a string. So you have to enclose it in quotes. Also note that display is a css style attribute. So it should be applied as shown below.
div.style("display","none");
Other alternative options for implementing the same are the following.
Option 2:
div.attr("hidden",true);//to hide
div.attr("hidden",null);//to show
Option 3:
div.style("opacity",0);//to hide
div.style("opacity",1);//to show
Here is a working code snippet.
var button = d3.select("body")
.append("button")
.text("Mouse Over Me");
button.on("mouseover",function(){
div.style("display","block");
});
button.on("mouseout",function(){
div.style("display","none");
});
var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("display", "none")
.text("Hello This is a sample");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
display is not an HTML attribute, this is CSS. You need to change your code to something like this if you want to hide the element:
div.css({ "display": "none" });
Or just use the jQuery shortcut: div.hide();.
I would like to use hide() or show(). change from
div.attr("display", display);
to
div.hide();
here is the comments from .hide() or display: none? jQuery
"The matched elements will be hidden immediately, with no animation. This is roughly equivalent to calling .css('display', 'none'), except that the value of the display property is saved in jQuery's data cache so that display can later be restored to its initial value. If an element has a display value of inline, then is hidden and shown, it will once again be displayed inline."
This looks like you are following the tutorial here, right down to the extra space before the .html in the mouseover event. (Which is fine...the only reason I recognized that little syntax is because I spent all day staring at it!)
http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html
You post the relevant code above, but are you also selecting the div that you want to operate on using the select method? This may be why your transition isn't working the way you want it to.
eg:
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
otherwise or in addition the proper way to get the tooltip to go away is as Gilsha answered above with this line on mouseout:
div.style("display","none");
I need some help with my d3.js. Could someone help me in implementing a feature that on mouse over your cursor turns into the "click" cursor form? For example when you click hover over a button on stack overflow the cursor changes.
.on("mouseover", function() {
d3.select(this)
.style("fill", "#3b6887");
})
See the different cursors available you can use cursor CSS | MDN
Try the following
.on('mouseover', function() {
d3.select(this)
.style('fill', '#3b6887')
.style('cursor', 'pointer');
});
I have some code that adds a mouseover event handler to svg circles to display tooltips. Should I remove/unbind these handlers when I remove the circle elements? I do not know if these handlers are attached to the svg object and I am afraid it may lead to shadow dom or memory leaks. See code below :
circles.enter().append("svg:circle")
.on("mouseenter", function(d) {
// show tooltip
});
circles.exit()
.on("mouseenter", null) // necessary?
.remove();
I think you have your answer already but I was interested in how you show that this is true, at least in latest Chrome.
This is the section of the D3 code that removes DOM nodes:
function remove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
export default function() {
return this.each(remove);
}
So as you can see it's depending on the browser to do cleanup of any associated listeners.
I created a simple stress test of adding/removing lots of circle nodes with D3:
var circles = svg.selectAll("circle")
.data(data, function(d) { return d.id; } );
circles.exit().remove();
circles.enter().append("circle")
.attr("id", function(d) { return d.id; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr( { r: 5, fill: 'blue' })
.on("mouseenter", function(d) { console.log('mouse enter') });
Live version here: http://bl.ocks.org/explunit/6413685
Open the above with latest Chrome
Open the Developer Tools
Click the Timeline tab
Click the Record button at the bottom
Let it run for a couple minutes, then click the button again to stop recording
Drag the selector in the top timeline view to cover several of the garbage collection sawtooth patterns
You will notice that the DOM node garbage collection counts correspond with the event listener garbage collection counts. In fact, you can't really tell them apart in the below screenshot since the lines are superimposed:
Note that for Internet Explorer, things are a little more complicated.
See also this article for more tips on tracking memory usage in Chrome tools.