d3.js tooltip doesnt show - d3.js

I am trying to add tooltip, it doesnt show for some reason. Please help. Here's the code https://codepen.io/gladiator_kris/pen/pojgEyQ?editors=0010
var tooltip = svg.append("div")
.attr("id", "tooltip")
.style("opacity", 0.8);
.on("mouseover", function(d) {
tooltip.style("display", "flex")
.html(function() {return 'tooltip'})
.style("left", (d3.event.pageX + 10)+"px")
.style("top", (d3.event.pageY - 28) + "px")
})
.on("mouseout", () => {
tooltip.style("display", "none")
});
Many Thanks!

The problem is caused by the fact that the tooltip is an HTML div, and is being appended to the SVG. div is not a valid SVG tag, so it is not displayed.
This can be fixed by appending the div to div#graph, as shown below:
var tooltip = d3.select("#Graph").append("div")

Related

D3.js, DC.js tooltips - Issue with gridlines

I'm using the following code in a series chart renderlet to get a D3 tooltip.
lines.on('renderlet', function(chart) {
chart.selectAll('g.x text')
.attr('transform', 'translate(-29,30) rotate(315)')
chart.selectAll('circle')
.on("mouseover", function(d) {
d3.select(this)
.transition()
.duration(500)
div.transition()
.duration(200)
.style("opacity", 0.9);
div.html("<table><thead><tr><th colspan='2' class='toolHead'>" + d.data.key[1] +
'</th></tr></thead><tbody>' + '<tr style="margin-top: 100px"><td class="toolHeadCol"><td colspan="2">' +
d.data.key[0] + '</td></tr>' + '<tr style="margin-top: 100px"><td class="toolHeadCol"><b>' + 'value: ' +
'</b></td> <td>' + d.y + '</td></tr></tbody></table>')
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function() {
d3.select(this)
.transition()
.duration(500)
.style('opacity', 0)
div.transition()
.duration(500)
.style("opacity", 0)
})
When hovered on a certain data point in line, tooltip gets displayed. Data point on the line(circle) acts as expected, but there are some problems with the corresponding horizontal and vertical grid lines.
They do not disappear on mouseout and stay until another circle is hovered upon.
Since its a series chart, there are multiple lines, and mouseover on a datapoint in one line does not seem to be affected by mouseover on another line. As shown in the below image:
As shown in image, the gridline on the blue line remains visible even when its is hovered up on orange line.
How do I fix these?
Here is the fiddle

Can't add title to stacked bar graph on D3

I creating a stacked bar chart using this example. The chart works and renders but I can't add a mouseover label.
I tried this...
DATE.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
.append("svg:title")
.text(functino(d){return "foo"});
But this after adding the .append("svg:title... the graph stops rendering. If I remove the .style("fill... line, the graph renders, however it's not stacked and there's no mouseover feature.
I have also tried using the tooltip route. (Source)
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
// Prep the tooltip bits, initial display is hidden
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
But still not luck. Is there a library I need to load? Not sure what's going on.
The graph stop rendering when you try to append the title because you have a typo: it's function, not functino.
Besides that, this is what you need to get the value of each stacked bar:
.append("title")
.text(function(d){
return d[1]-d[0]
});
Here is the demo: https://bl.ocks.org/anonymous/raw/886d1749c4e01e191b94df23d97dcaf7/
But I don't like <title>s. They are not very versatile. Thus, instead of creating another <text>, as the second code you linked does, I prefer creating a div:
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
Which we position and set the HTML text this way:
.on("mousemove", function(d) {
tooltip.html("Value: " + (d[1] - d[0]))
.style('top', d3.event.pageY - 10 + 'px')
.style('left', d3.event.pageX + 10 + 'px')
.style("opacity", 0.9);
}).on("mouseout", function() {
tooltip.style("opacity", 0)
});
And here is the demo: https://bl.ocks.org/anonymous/raw/f6294c4d8513dbbd8152770e0750efd9/

D3 JS appending tooltip to each data circle point and finding on hover event for svg element

I have an array of objects.These objects contain a set of attributes named "x" and "y". Now as i iterate through the array,i append circle for each object into array taking these coordinates as center of the circle.I am trying to attach a tooltip on mouse hover of each circle which displays the x and y coordinate of the circle.
The two problems i am facing is
1.How to append a div element to each circle
2.How to get hover event for the circle?
Please help?
<!doctype html>
<html>
<head>
<title>D3 Basics</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
</head>
<body>
<script>
var data=[
{"x":"100","y":"20"},
{"x":"102","y":"22"},
{"x":"200","y":"30"},
{"x":"500","y":"40"},
{"x":"500","y":"30"}
];
var svgHeight=800;
var svgWidth=800;
var margin=50;
var divelement=d3.select("body")
.append("div")
.attr("height",svgHeight)
.attr("width",svgWidth)
.attr("style","border:1px solid black;");
var svgElement=divelement.append("svg")
.attr("height",svgHeight)
.attr("width",svgWidth);
var boxGroupElement=svgElement.append("g")
.attr("transform","translate("+margin+","+margin+")");
//appending data circle points
for (var a=0; a<data.length; a++) {
boxGroupElement.append("circle")
.attr("cx",data[a].x)
.attr("cy",data[a].y)
.attr("r","3")
.attr("fill","yellow")
.attr("stroke","blue");
}
</script>
</body>
</html>
I have marked this as duplicate but there can be something to learn here.
Where you are creating the circles :
for (var a=0; a<data.length; a++) {
boxGroupElement.append("circle")
.attr("cx",data[a].x)
.attr("cy",data[a].y)
.attr("r","3")
.attr("fill","yellow")
.attr("stroke","blue");
}
This is totally wrong if you are using D3. If you put a mouseover event on this like you normally would with D3 to console log the data like so :
.on('mouseover',function(d){ console.log(d);});
This won't work as there is no data appended to your selection. A work around would be the following :
var circles = boxGroupElement.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
})
.attr("r", "3")
.attr("fill", "yellow")
.attr("stroke", "blue")
Now for the tooltip. I have referenced this above : Show data on mouseover of circle
The second answer precisely. Here is how it works :
Add a div for your tooltip to sit and set visibility to hidden (so it can become visible on mouseover) :
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
And on mouseover a node show data. Here I have shown the position. Bare in mind, this way wouldn't work if you stuck with your original way of creating the circles as you wouldn't be able to find the data :
.on("mouseover", function(d) {
tooltip.text("Pos : " + d.x + ' : ' + d.y);
return tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
return tooltip.style("top",
(d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
.on("mouseout", function() {
return tooltip.style("visibility", "hidden");
});
Working fiddle : https://jsfiddle.net/thatOneGuy/7qt1aoan/2/
EDIT
If you are adamant you want to keep it like you have the following could be a work around :
.on("mouseover", function(d, i) {
tooltip.text("Pos : " + data[i].x + ' : ' + data[i].y);
return tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
return tooltip.style("top",
(d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
.on("mouseout", function() {
return tooltip.style("visibility", "hidden");
});
Updated fiddle for this workaround : https://jsfiddle.net/thatOneGuy/7qt1aoan/3/
Again on the mouseover, you can't use data[a].x as this will always return the last element of the data, closures etc, so I use data[i].x which gives you the current circle you are mousing over :)
You need to add mouseover event to boxGroupElement.append("circle") something like this
boxGroupElement.append("circle")
.attr("cx",data[a].x)
.attr("cy",data[a].y)
.attr("r","3")
.attr("fill","yellow")
.attr("stroke","blue").on("mouseover", function(d) {
div.transition().duration(100).style("opacity", .9);
div.html("My Tooltip" + "<br/>" +d )
.style("left", (d3.event.pageX) + "px")
.style("top",(d3.event.pageY - 28) + "px")
.attr('r', 8);
d3.select(this).attr('r', 8)})
.on("mouseout", function(d) {
div.transition().duration(600).style("opacity", 0)
d3.select(this).attr('r', 3);
});
Here is a working example.

How to add D3 tooltips

Currently I am looking in to D3 sample trying to alter it to add tooltips https://plnkr.co/edit/stHnntCknDUs0Xw6MlQ2?p=preview but cant manage it myself.
I want to add tooltip and pointers to this the way like it is done here http://c3js.org/samples/timeseries.html
//Add tooltips
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Add the scatterplot
countryEnter.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.stat); })
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(formatTime(d.date) + "<br/>" + d.date)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
Just cant get it working
You are putting the hover on the wrong element. You are putting them on the dots (which don't exist as in your data you as you have no date attribute).
What I have done is place them on the path like so :
countryEnter.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); })
.on("mouseover", function(d) {
console.log(d)
divTooltip.transition()
.duration(200)
.style("opacity", .9)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.innerHTML(formatTime(d.date) + "<br/>" + d.close)
})
.on("mouseout", function(d) {
divTooltip.transition()
.duration(500)
.style("opacity", 0);
});
But I still get the error formatTime is not defined. But the problem is solved on getting the tooltip to be viewed. So solving the rest shouldn't be difficult :)
Updated plunkr : https://plnkr.co/edit/zQY0Wen1plIMuwOMq3PE?p=preview

Removing text on mouseout event

Small problem on one viz.
I have a bar chart, and I want it to display some text in the line on 'mouseenter'. That works fine, but I want to remove this text on 'mouseout', and I can't seem to get the hang of it.
Thank you very much for your help!
Attached: the concerned section of the d3.js script
d3.selectAll("div.line")
.append("div")
.attr("class","bar")
.style("width", function(d){return d.occurrence /10 + "px"})
.on("mouseenter", function(d) {
d3.select(this)
.append("text")
.text(function(d){return d.occurrence + " occurences"});
})
.on("mouseout", function(d) {
d3.select(this)
.select(".text").remove();
});
In your code, you're trying to select .text on mouseout. You're selecting nodes with which have the class: "text" rather than text nodes. Remove the dot.
I'd probably also change the mouseout "select" to "selectall" just in case you miss a mouseout event and accidentally add two text nodes.
Edit:
http://jsfiddle.net/QbGRE/
d3.select("div.line").selectAll("div.bar")
.data(data, function(d) { return d.id; })
.enter()
.append("div").attr("class","bar")
.style("width", function(d){return d.occurrence /10 + "px";})
.on("mouseover", function(d) {
d3.select(this)
.append("text").style("pointer-events", "none")
.text(function(d){return d.occurrence + " occurences";});
})
.on("mouseout", function(d) {
d3.select(this)
.select("text").remove();
});
Cleaned up your code.
"mouseover/mouseout" instead of "mouseenter/mouseout"
.select("text") instead of ".text".
style("pointer-events", "none) on the text to stop it causing extra mouse events when it's added.
Added fake data.
The easiest way to do this is to assign a unique ID to the new text element and select by that:
.on("mouseenter", function(d) {
d3.select(this)
.append("text")
.attr("id", "myText")
.text(function(d){return d.occurrence + " occurences"});
})
.on("mouseout", function(d) {
d3.select("#myText").remove();
});

Resources