Tooltip doesn't disappear on mouseout - javascript

I'm trying to add a tooltip to a rect. It does pop up on mouse pointer hover over a bar but it doesn't want to disappear on mouseout event. I've also tried to use div.style("display", "none"), but it doesn't work either. For some reason it doesn't want to trigger mouseover event again after mouseout. It just keep displaying a tooltip.
http://bl.ocks.org/edkiljak/dc85bf51a27122380c68909cdd09d388
div.tooltip {
position: absolute;
text-align: left;
padding: 4px;
font-family: Lato, arial, sans-serif;
font-size: 14px;
background: #eee;
border-radius: 2px;
border: 1px solid gray;
pointer-events: none;
}
var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var bars = barGroup.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", function (d) {
return heightScale(d.Vendor);
})
.attr("width", function (d) {
return widthScale(+d.Share2016)
})
.attr("height", heightScale.bandwidth() / 1.1)
.style("fill", function (d, i) {
return color(i);
})
.on("mouseover",function (d){
div.transition()
.duration(200)
div
.style("opacity", .9)
.html("Vendor: " + "<strong>" + d.Vendor + "</strong>" + "<br>" + "Market share in 2016: " + d.Share2016 + "%")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
d3.select(this)
.style("fill", "#93ceff")
})
.on("mouseout", function(){
d3.select(this)
.transition()
.duration(50)
.style("fill", function(d,i){
return color(i);
})
d3.select(div).remove()
})
What am I doing wrong here?

The problem lies here:
d3.select(div).remove()
As div is itself a selection, you're selecting a selection, and that makes little sense.
Instead of that, just use div in the mouseout:
div.remove()
Or, even better, just set its opacity to zero:
div.style("opacity", 0)
Here is the updated bl.ocks with just that change: http://bl.ocks.org/anonymous/raw/13ce2445b248fb9e44dcd33cfc3dff36/dff0c60423927960cab8aaf9e613c2c3ae205808/

Related

Extend D3 Chart to add tooltip from HTML page

I have a D3 graph showing tooltip on mouseover. The graph is currently created from a JS file.
D3 graph code:
var tooltip = d3.select('body')
.append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0);
var svgE = svg
.append("g")
.selectAll()
.data(graph.data)
.join("rect")
.attr("x", xFunc)
.attr("y", yFunc)
.on('mouseover', function (d) {
tooltip.transition().duration(200)
.style('opacity', .9);
var toolTipText = d.x + " - " + d.y;
tooltip.html(toolTipText)
.style('left', (d3.event.pageX - 35) + 'px')
.style('top', (d3.event.pageY - 30) + 'px');
})
.on('mouseout', function (d) {
tooltip.transition().duration(200)
.style('opacity', 0);
tooltip.html("");
});
Is it possible to remove the tooltip code from the JS file and move it to an HTML page so I can add tooltip functionality whenever needed?
D3 code in JS file will be:
var svgE = svg
.append("g")
.selectAll()
.data(graph.data)
.join("rect")
.attr("x", xFunc)
.attr("y", yFunc);
What do I add in the HTML block to add tooltip functionality?
The example you provided creates a tooltip entirely in JavaScript, but if you for whatever reason prefer creating a tooltip in HTML you can do that as well.
const mainSvg = d3.select('svg#mainSvg');
const tooltip = d3.select('div.tooltip');
const aRectangle = mainSvg.append('rect')
.attr('x', 50)
.attr('y', 50)
.attr('height', 100)
.attr('width', 100)
.attr('fill', 'green');
aRectangle.on('mouseover', (d) => {
tooltip.style('visibility', 'visible');
tooltip.html('You are mousing over a rectangle.');
tooltip.style('left', `${d3.event.pageX}px`)
.style('top', `${d3.event.pageY}px`)
});
aRectangle.on('mouseout', (d) => {
tooltip.style('visibility', 'hidden');
});
svg#mainSvg {
height: 200px;
width: 200px;
background-color: gray;
}
div.tooltip {
z-index: 1;
background-color: white;
position: absolute;
padding: 0 10px;
border: 1px solid black;
pointer-events: none;
visibility: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>
<svg id='mainSvg'></svg>
</div>
<div class='tooltip'>
This is a tooltip
</div>

Tooltip not displaying on top of the element using d3.js on Mouseover

I have a tooltip using d3.js
Here's my tooltip declaration
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("background", "white")
.style("text-align", "center")
.style("font-size", "15px")
.attr("class", "shade")
.text("a simple tooltip");
My css:
.shade {
border: 1px solid #e6e6e6;
padding: 10px;
box-shadow: 3px 2px #888888;
width:90px;
height:80px;
text-align:center;
}
The event:
state.selectAll("rect")
.data(function (d) { return d.ages})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function (d) { return x1(d.name); })
.attr("y", function (d) { return y(d.value); })
.attr("height", function (d) { return height - y(d.value); })
.style("fill", function (d) { return color(d.name); })
.on("mouseover", function (d) {
tooltip.text("")
var tooltext = tooltip.append('label')
tooltext.text(d.name).attr("class","middleText")
tooltip.append("br")
var labeltooltip = tooltip.append('label').attr('class', GetColor(d.name))
labeltooltip.text(d.value)
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");
});
This code is working well but my problem is the tooltip displayed beside in the mouse pointer on hover event.
I've tried to change also something like:
.on("mousemove", function () { return tooltip.style("top", d + "px").style("left", d + "px"); })
But same i got no luck.
My question is it possible to move the cursor on top of every element on mouseover event has been fired?
Thanks in Advance
If I understand you correctly, you want something like this:
.on("mousemove", function () {
return tooltip.style("top", this.getBBox().y + "px").style("left", this.getBBox().x + "px");
});

Show tooltip on the D3 map

I've created a basic map using D3 with countries geojson. Here is the demo.
Now when the user clicks on any coordinate on the map, I am showing a weather info within a tooltip with weather icon as a marker.
countries = countriesGroup
.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.attr("id", function(d, i) {
return "country" + d.properties.iso_a3;
})
.attr("class", "country")
// add a mouseover action to show name label for feature/country
.on("mouseover", function(d, i) {
d3.select("#countryLabel" + d.properties.iso_a3).style("display", "block");
})
.on("mouseout", function(d, i) {
d3.select("#countryLabel" + d.properties.iso_a3).style("display", "none");
})
// add an onclick action to zoom into clicked country
.on("click", function(d, i) {
var eventLocation = d3.mouse(this);
var coordinates = projection.invert(eventLocation);
var proxy = "https://cors-anywhere.herokuapp.com/";
var wetherInfoUrl =
"https://api.darksky.net/forecast/c68e9aaf0d467528b9363e383bde6254/" + coordinates[1] + "," + coordinates[0] + "?exclude=minutely,hourly,daily";
$.ajax({
url: proxy + wetherInfoUrl,
success: function(response) {
tooltipDiv
.transition()
.duration(200)
.style("opacity", 0.9);
tooltipDiv
.html('<h3>Dynamic Weather info: '+ response.currently.humidity +'</h3><br/><img src="https://darksky.net/images/weather-icons/' + response.currently.icon + '.png" alt="clear-night Icon" width="50" height="50">')
.style("left", (eventLocation[0] - 250) + "px")
.style("top", (eventLocation[1] - 100) + "px");
}
});
d3.selectAll(".country").classed("country-on", false);
d3.select(this).classed("country-on", true);
boxZoom(path.bounds(d), path.centroid(d), 20);
});
Now the issue is, the tooltip remains at the absolute position relative to the body (It stays at the exact position on the screen which is misleading if we pan and zoom the map) whereas I want the tooltip to be relative to the coordinate clicked on the map and should be fixed to the clicked coordinate no matter where we zoom or pan in the map, similar to this leaflet example (In short I want tooltip to behave similarly to the typical map pin markers).
I was able to do this using CSS and the following snippets:
var tooltipDiv = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
div.tooltip {
position: absolute;
text-align: center;
width: 80px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
... and then in the svgs,
.on("mouseover", function(d) {
tooltipDiv.transition()
.duration(200)
.style("opacity", .9);
tooltipDiv.html(d.vessel_name)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
Definitely an imperfect solution, but hopefully it helps. Full source:
Demo:
http://Ares513.github.io/04-MapsAndViews/
Source:
https://github.com/Ares513/MapsAndViews
You should add the element to the map's SVG, not the body. like this:
svg.select("#map")
.append("text")
.data(json)
.classed("geopath", true);

Defining CSS style for tooltip in d3.js body

I'm wondering if its possible to define a CSS style for a tooltip function displayed by d3.js on mouse over event in the actual body of the definition rather than on top of the page in the style section.
JAVASCRIPT:
var tooltip = d3.select("#scatter-load").append("div")
.attr("class", "tooltip")
//.attr("position", "absolute")
//.attr("width", "200px")
//.attr("height", "30px")
//.attr("pointer-events", "none")
.style("opacity", 0);
chocolateGroup.append("circle")
.attr("r", function(d) {return rScale(d.size);})
.attr("opacity", 0.7)
.style("fill", "steelblue")
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9)
tooltip.html(d.manufacturer + "<br/> (" + xValue(d)
+ ", " + yValue(d) + ")")
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
CSS:
.tooltip {
position: absolute;
width: 200px;
height: 28px;
pointer-events: none;
What I am looking for is something similar to this style where CSS styling is defined when object is created (for example fill):
svg.append("path")
.datum(data)
.attr("d", area)
.attr("fill", "steelblue");
You should be using style to set CSS style like this:
.attr("class", "tooltip")
.style("position", "absolute")
.style("width", "200px")
.style("height", "30px")
.style("pointer-events", "none")
.style("opacity", 0);

Positioning SVG elements with CSS. Having some problems

Ive added 20 SVG squares to a trend graph I made using D3.js. Ech square is a clickable object which toggles lines on and off the graph. In Firefox the squares appear in the right lace, in Chrome, the CSS apparently stops working completely and the squares just drop to the bottom of the page.
Heres a link to the graph, http://www.andkensol.com/dataviz/TrendGraph/trendMov.html
And here is some of the JavaScript and CSS I used to make and then position the squares. Using position:relative is probably the cause. Would anyone have any advice or suggestions?
//JS
//AVENGERS CONTROLS
d3.select(".chart").append("svg")
.attr("class", "AvengeDot")
.on("mouseover", function(d) {
nameInfo.transition()
.duration(100)
.style("opacity", .9);
nameInfo.html("Marvel's The Avengers")
.style("left", (d3.event.pageX + 10) + "px")
.style("top", (d3.event.pageY - 30) + "px");
})
.on("mouseout", function(d) {
nameInfo.transition()
.duration(200)
.style("opacity", 0);
})
//HUNGER GAMES CONTROLS
d3.select(".chart").append("svg")
.attr("class", "HungerDot")
.on("mouseover", function(d) {
nameInfo.transition()
.duration(100)
.style("opacity", .9);
nameInfo.html("Hunger Games")
.style("left", (d3.event.pageX + 10) + "px")
.style("top", (d3.event.pageY - 30) + "px");
})
.on("mouseout", function(d) {
nameInfo.transition()
.duration(200)
.style("opacity", 0);
})
//CSS
.AvengeDot{
position:relative;
left:77%;
bottom:118%;
width:15px;
height:15px;
background-color:#FF9604;
cursor:pointer;
}
.HungerDot{
position:relative;
left:75.5%;
bottom:114%;
width:15px;
height:15px;
background-color:#FF9F18;
cursor:pointer;
}

Categories