I'm new to d3 and coding in general, and I'm making a social network graph with some tooltips. The tooltip is supposed to appear when someone hovers over a node and fade out and hide when the mouse is removed. I managed to get the tip to fade out with a transition, but the tip is actually still there, just invisible, so the box and text sometimes obscure other nodes, making it so that you can't successfully hover over parts of other nodes and trigger other tooltips. When the code is just node.on('mouseout', tip.hide);, it works fine, but it doesn't have the transitions.
Here's the fiddle. The effect I'm talking about doesn't happen there as much as in a normal browser though. http://jsfiddle.net/wPLB5/
node.on('mouseover', tip.show);
node.on('mouseout', function() {
d3.select(".d3-tip")
.transition()
.delay(100)
.duration(500)
.style("opacity",0);
tip.hide;
});
//node.on('mouseout', tip.hide); //This is the original line.
Edit:
I figured it out. I needed to add another style that I didn't know about. Here's the fixed code:
node.on('mouseout', function() {
d3.select(".d3-tip")
.transition()
.delay(100)
.duration(600)
.style("opacity",0)
.style('pointer-events', 'none')
});
I figured it out. I needed to add a pointer-events style. Here's the fixed code:
node.on('mouseout', function() {
d3.select(".d3-tip")
.transition()
.delay(100)
.duration(600)
.style("opacity",0)
.style('pointer-events', 'none')
});
You can try the two approaches using div tooltip or using svg title.
node.append("svg:title")
.text(function(d) { return "Location:" + " " + d.location +
"\nFloruit Date:" + " " + d.floruitDate; });
Also, maybe this answer will be useful for you D3: show data on mouseover of circle.
Related
I am working with react D3 charts, and I have created charts and it is working fine.
What I have done
I have several charts which are updating with in some time intervals, something like live data
So here to achieve this I out use effect and updating my charts every second, and my data in charts updates correctly.
I have given one tooltip on hover over the the bar, so that user can check the data for each bar or line.
Using below code to show the tooltip
.on("mousemove", function (event, d) {
// this whole code is when I hover that perticular bar
d3.select(this)
.transition()
.duration("50")
.attr("opacity", 0.6)
.attr("x", (a) => xScaleBars(a.timeline) - 3)
.attr("width", xScaleBars.bandwidth() + 6)
.style("filter", "url(#glow)");
div.transition().duration(50).style("opacity", 1);
div
.html(
`</text><text"></br> value : ${d.dataToShow}
<br/>
</text><text"></br> Month : ${d.month}
`
)
.style("left", event.pageX - 58 + "px")
.style("top", event.pageY - 140 + "px");
})
.on("mouseout", function (d, i) {
// this is when I move cursor out of that bar
d3.select(this)
.transition()
.duration("50")
.attr("width", xScaleBars.bandwidth())
.attr("x", (a) => xScaleBars(a.timeline))
.style("filter", "none")
.attr("opacity", "1");
div.transition().duration("50").style("opacity", 0);
})
Issue I am facing
The issue is when I hover over one chart component it shows the tooltip, and than when I hover over the other both shows at the same time.
What I am trying to do is to show the tooltip when I hover the one bar of any chart and than hide it,I tried below code
d3.select("svg").selectAll(".tooltipCHart").remove();
But it doesn't resolve my issue, I think I am missing some small part
here is my code sandbox which I tried
The problem is that you're creating a new tooltip div every time you re-render the chart.
A better approach is to have a hidden tooltip div in the beginning (in the render / return from your function component) and then just modify its contents and style (opacity: 1) on mouseover and mouseout. Keep track of the tooltip div using a ref.
See working codesandbox (I only modified chart1, you can make similar changes to chart2)
I am working with D3 Charts, and by all work I have completed the chart and did some enhancement as well.
What I am doing
I have one function which shows tooltip, whenever I hover over any bar I am showing some info to the user.
My chart shows live data, so if any new data is coming it automatically creates a new bar.
SO when I hover over any bar then data is showing fine and perfect
My issue
So as I mentioned above in my case the data comes after some interval continuously, so I am getting data and adding it to previous data
The issue is when i Hover the last bar the tooltip shows fine, and when the new data comes so now two tooltips showing and it goes on and on
But in my coding I am writing code to remove the tooltip on mouseout, but still getting this issue
My code
This is what I am doing
.on("mousemove", function (event, d) {
// this whole code is when I hover that perticular bar
d3.select(this)
.transition()
.duration("50")
.attr("opacity", 0.6)
.attr("x", (a) => xScaleBars(a.timeline) - 3)
.attr("width", xScaleBars.bandwidth() + 6)
.style("filter", "url(#glow)");
div.transition().duration(50).style("opacity", 1);
div
.html(
`</text><text"></br> value : ${d.dataToShow}
<br/>
</text><text"></br> Month : ${d.month}
`
)
.style("left", event.pageX - 58 + "px")
.style("top", event.pageY - 140 + "px");
})
This above code is when I hove rover
Below is the code when I do mouseout
.on("mouseout", function (d, i) {
// this is when I move cursor out of that bar
d3.select(this)
.transition()
.duration("50")
.attr("width", xScaleBars.bandwidth())
.attr("x", (a) => xScaleBars(a.timeline))
.style("filter", "none")
.attr("opacity", "1");
div.transition().duration("50").style("opacity", 0);
})
I have tried display none as well as visibility property, but nothing works
I don't know what I am doing wrong
is My code right or wrong this also I am not getting properly
I have put all of my code in code sandbox Please have a look
PS: I am using use Effect with set Timeout for each 1 second to make it update every second
I have checked all the related suggestion by stack overflow, but none helped me out may be I am wrong but I did not found the solution.
Edit / Update
The answer suggested below is not working, if I have more than once chart
I used d3.selectAll(".tooltipCHart").remove();
So when there are two charts on hover of first chart's bar it shows tooltip, but when I hover over the other chart it is not showing
Please have a look here
here in above code sandbox in first chart it does not show tooltip but in second it is showing
Vivek, I have gone through the code and found out that most of the code written is fine. Besides that the reason of multiple tooltips is that you are rendering everything whenever data changes, so you are appending the tooltip div everytime, it means below code will execute multiple times which display multiple tooltips in case where our code did not perform mouseout execution. You can check this by inspecting elements.
var div = d3
.select("body")
.append("div")
.attr("class", "tooltipCHart")
.style("opacity", 0);
Simple solution will be to remove all the tooltips before appending a new one.
d3.selectAll(".tooltipCHart").remove();
It will resolve the issue of multiple tooltips.
But for your chart my confusion is whether is it a good idea to show tooltip or not as the data is always moving toward left so it will be difficult to keep the tooltip for long time.
I'm searching a solution. I started from this example : http://mbostock.github.io/d3/talk/20111116/airports.html
Here, you can hover the map, and see the lines appearing at same time.
But, lines are appearing even if you aren't on a circle.
I'm actually searching for a solution where lines (or paths) are displaying only when you hover a circle?
That's why I wrote this part of code :
var c = circles.selectAll("circle")
.data(airports)
.enter().append("svg:circle")
.attr("cx", function(d, i) { return positions[i][0]; })
.attr("cy", function(d, i) { return positions[i][1]; })
.attr("r", function(d) { return d.r })
.style("fill", function(d){ return d.color})
.sort(function(a, b) { return countByAirport[b.iata] - countByAirport[a.iata]; });
c.on("mouseover", function(e){
g.select("path.arc")
.style("display", "inherit")
});
});
c.on("mouseout", function(e){
g.select("path.arc")
.style("display", "none");
});
I'm probably far away from the good way to do this. Here, with my code, I can display all paths when I'm hovering each circles. I take others solutions too, I can leave Voronoi (as I don't want to use cells, maybe you know another way more practicable...).
My ultimate goal would be to find this answer, and then, to display paths which is/are only concerned by the circle which is hovered. I need more precision compared to Voronoi, but it seemed good at first, for paths i.e.).
I could add more code, but globally, it is the same as the example above
Thank you!
Here's a solution to your ultimate goal - display paths related to the hovered circle
https://shashank2104.github.io/d3-Voronoi/
Relevant code changes:
Added a class to the <g> containing the arcs
.enter().append("svg:g").attr('class', function(d) { return d.iata; });
Changed mouseover and mouseout events for the circles to display the arcs basedon the class added in the first step.
circles.on("mouseover", function(d){
console.log(d.iata);
cells.select('g.'+d.iata).selectAll("path.arc")
.style("display", "inherit")
}).on("mouseout", function(d){
cells.select('g.'+d.iata).selectAll("path.arc")
.style("display", "none");
});
Took off the CSS that displayed all arcs:
#cells g:hover path.arc {
display: inherit;
}
I could add more code but I'm guessing you can look at the source code on the github page.
Hope this helps.
I am using d3js collapsible tree.
https://bl.ocks.org/mbostock/4339083
How to make link blink(flash)? Can nodes also be made to show/hide at regular interval? I hope it can be done without using setInterval.
Thanks in advance
To make the links "blink" you'll want to use a transition. Honestly there's nothing wrong with setInterval, in fact I'd probably use it for ease.
Firstly you want the animation. It'd difficult to know what you mean by "blink" so I'm going to assume gets brighter for now - but you can change this up however you wish.
d3.select("svg")
.selectAll(".link")
.transition()
.duration(500) // miliseconds
.style("stroke", "white");
This will gradually change the style to white over a period of 500ms. Now you need to revert the color back to the original. You can do this using the end event on the transition object.
.on("end", function() {
d3.select(this).style("stroke", "#CCC");
});
Note that in the above this is the HTMLElement that the transition was running on. You can do this with a lambda (arrow function) if need be but you need to do (d, i, elements) => d3.select(elements[i]);
Now you've got you're transition, which resets. But you want to call it regularly. Honestly, the easiest way to do this is using setInterval... So your final code would look like:
// Create the regular interval
setInterval(() => {
d3.select("svg")
.selectAll(".link")
.transition()
.duration(500) // miliseconds
.style("stroke", "white")
.on("end", function() {
d3.select(this).style("stroke", "#CCC");
});
}, 1000);
I found this is a very helpful example to create tooltip on line charts. I am following this to work on a line chart now. The difference is the tooltip in my chart has a box/background to contain the value showing in the tooltip, so I add append('rect') with attr('fill', 'white').
mousePerLine.append('rect').
attr('width', '38px').
attr('height', '20px').
attr('class', 'tooltipRect').
style('fill', 'white').
attr('transform', 'translate(5,-13)');
To avoid overlapping of text as well as rect, I changed line 292 according to a post here How to select multiple selectors with selectAll?
.select("text")
.attr("transform", function(d,i) {
return "translate (10,"+(3+ypos[i].off)+")";
})
to
.selectAll(".tooltipRect, text")
.attr("transform", function(d,i) {
return "translate (10,"+(3+ypos[i].off)+")";
})
Here's a fiddle of the problem.
However, the tooltips are still overlapping. Can anyone help to figure out what is the cause of the problem? Thanks in advance!
The rects keep overlapping likely because the way you are selecting them.
Why not close the selectiona at the text (keep the text selection above as is) but a make a new selection for the rect:
d3.selectAll(".mouse-per-line")
.select("rect")
.attr("transform", function(d,i) {
return "translate (5,"+(ypos[i].off - 13)+")";
});
This works for me.
I did the translation based on your initial set up of the rect. I adjusted the offset on line 286 from 15 to 20 - it looks a bit better.