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.
Related
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 building a muti-series line chart which is very similar like this https://jsfiddle.net/xn1sLbf4/9/.
Now, I want to change the tooltips showing event. I want to have the tooltips show only when the vertical line is moving on the x-axis ticks instead of showing the tooltips on the entire line. For example, in my jsfiddle, when the vertical line locates at 'Mon 03', the tooltips show. If vertical line is moving between 'Mon 03' and 'Tue 04', tooltips hide. Can anyone give ideas how to accomplish this?
Thanks a lot!!
UPDATE
This is the change I made. See updated fiddle: https://jsfiddle.net/xn1sLbf4/10/
I changed the line 192-196 to
var mouseRect = mouseG.selectAll('.work-rect')
.data(newCities[0].values)
.enter()
.append("g")
.attr("class", "work-rect");
mouseRect.append('svg:rect')
.attr('x', function(d) { return x(d.date);})
.attr('width', 5)
.attr('y', function(d) { return 0;})
.attr('height',height)
.attr('fill', 'none')
The tooltips are showing only when the vertical line is on the ticks. But the vertical line also hide... How can I make the vertical line show all the time following the mouse across the chart?
If .style("opacity", "1") in mouseRect.append('svg:rect').on('mouseout', function() { is changed from 0 to 1 the mouse movement can be seen:
I understand your problem. You can just remove the following code from CSS file.
.x.axis path {
display: none;
}
Or
x.axis path { display: inline; }
In the process of learning D3.js.
Is it possible using a force layout to place a circle within another circle shape as per the picture. I am hoping to transition between a single circle per node to a display showing two circles per node. The size of the effective donut is used to illustrate another variable in the data.
Is this possible?
You don't even need to use anything other than a basic svg circle, as you find in most examples. Just bind the data to it, apply a stroke, and set the stroke-width attr to your other variable. Or r - otherVar, I'm sure you can figure that part out.
If this doesn't satisfy, build your own shape. The 'g' svg element is a container element, and lets you build whatever you like. Add two circles to a g, fill them how you like. Make sure to add them in the right order, since svg has no concept of 'on top', things just get painted in the order that you add them.
edit: okay, quick demo so you can learn some syntax. I didn't add any comments but hopefully the code is very verbose and straightforward. Find it here.
d3/svg is something that you have to just bash your head against for a while. I highly recommend spending some time creating a sandbox environment where you can quickly test new things, save, refresh browser to see results. Minimizing that turnaround time is key.
Thanks to roippi I was able to create a group containing two circle shapes.
var nodeCircles = svg.selectAll("g")
.data(nodes);
// Outer circle
var outer = nodeCircles
.enter()
.append("circle")
.attr("class", "node_circle")
.attr("r", function(d) { return d.radius_plus; })
.style("fill", function(d) { return d.color_plus; })
.style("opacity", 0);
// Inner circle
var inner = nodeCircles
.enter()
.append("circle")
.attr("class", "node_circle")
.attr("r", function(d) { return d.radius; })
.style("fill", function(d) { return d.color; })
.style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
.on("mouseover", mouseOver)
.on("mouseout", mouseOut)
.call(force.drag);
Outer circle visibility is toggled via a button.
As mentioned, I use a desktop based IDE to run/test visualisation languages. Currently the IDE supports studies written in D3.js, Raphael, Processin.js, Paper.js and Dygraphs. Picture below...
After fiddling around for several hours now, I still cannot make labels work in my D3 Sunburst layout. Here's how it looks like:
http://codepen.io/anon/pen/BcqFu
I tried several approaches I could find online, here's a list of examples I tried with, unfortunately all failed for me:
[cannot post link list because of new users restriction]
and of course the coffee flavour wheel: http://www.jasondavies.com/coffee-wheel/
At the moment i fill the slices with a title tag, only to have it displayed when hovering over the element. For that I'm using this code:
vis.selectAll("path")
.append("title")
.text(function(d) { return d.Batch; });
Is there something similar I could use to show the Batch number in the slice?
--
More info: Jason Davies uses this code to select and add text nodes:
var text = vis.selectAll("text").data(nodes);
var textEnter = text.enter().append("text")
.style(...)
...
While the selection for his wheel gives back 97 results (equaling the amount of path tags) I only get one and therefore am only able to display one label (the one in the middle)
Needs some finessing but the essential piece to get you started is:
var labels = vis.selectAll("text.label")
.data(partition.nodes)
.enter().append("text")
.attr("class", "label")
.style("fill", "black")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.text(function(d, i) { return d.Batch;} );
You can see it here
The trick is that in addition to making sure you are attaching text nodes to the appropriate data you also have to tell them where to go (the transform attribute with the handy centroid function of the arc computer).
Note that I do not need vis.data([json]) because the svg element already has the data attached (when you append the paths), but I still have to associate the text selection with the nodes from each partition.
Also I class the text elements so that they will not get confused with any other text elements you may want to add in the future.