I have a set of data that I am plotting in a scatter. When I mouseover one of the circles I would like it to popup with data (like x, y values, maybe more). Here is what I tried using:
vis.selectAll(\"circle\")
.data(datafiltered).enter().append(\"svg:circle\")
.attr(\"cx\", function(d) { return x(d.x);})
.attr(\"cy\", function(d) {return y(d.y)})
.attr(\"fill\", \"red\").attr(\"r\", 15)
.on(\"mouseover\", function() {
d3.select(this).enter().append(\"text\")
.text(function(d) {return d.x;})
.attr(\"x\", function(d) {return x(d.x);})
.attr(\"y\", function (d) {return y(d.y);}); });
I suspect I need to be more informative about what data to enter?
I assume that what you want is a tooltip. The easiest way to do this is to append an svg:title
element to each circle, as the browser will take care of showing the tooltip and you don\'t need the mousehandler. The code would be something like
vis.selectAll(\"circle\")
.data(datafiltered).enter().append(\"svg:circle\")
...
.append(\"svg:title\")
.text(function(d) { return d.x; });
If you want fancier tooltips, you could use tipsy for example. See here for an example.
A really good way to make a tooltip is described here: Simple D3 tooltip example
You have to append a div
var tooltip = d3.select(\"body\")
.append(\"div\")
.style(\"position\", \"absolute\")
.style(\"z-index\", \"10\")
.style(\"visibility\", \"hidden\")
.text(\"a simple tooltip\");
Then you can just toggle it using
.on(\"mouseover\", function(){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\");});
d3.event.pageX
/ d3.event.pageY
is the current mouse coordinate.
If you want to change the text you can use tooltip.text(\"my tooltip text\");
Working Example
There is an awesome library for doing that that I recently discovered. It\'s simple to use and the result is quite neat: d3-tip.
You can see an example here:
Basically, all you have to do is to download(index.js), include the script:
<script src=\"index.js\"></script>
and then follow the instructions from here (same link as example)
But for your code, it would be something like:
define the method:
var tip = d3.tip()
.attr(\'class\', \'d3-tip\')
.offset([-10, 0])
.html(function(d) {
return \"<strong>Frequency:</strong> <span style=\'color:red\'>\" + d.frequency + \"</span>\";
})
create your svg (as you already do)
var svg = ...
call the method:
svg.call(tip);
add tip to your object:
vis.selectAll(\"circle\")
.data(datafiltered).enter().append(\"svg:circle\")
...
.on(\'mouseover\', tip.show)
.on(\'mouseout\', tip.hide)
Don\'t forget to add the CSS:
<style>
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: \"\\25BC\";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
You can pass in the data to be used in the mouseover like this- the mouseover event uses a function with your previously enter
ed data as an argument (and the index as a second argument) so you don\'t need to use enter()
a second time.
vis.selectAll(\"circle\")
.data(datafiltered).enter().append(\"svg:circle\")
.attr(\"cx\", function(d) { return x(d.x);})
.attr(\"cy\", function(d) {return y(d.y)})
.attr(\"fill\", \"red\").attr(\"r\", 15)
.on(\"mouseover\", function(d,i) {
d3.select(this).append(\"text\")
.text( d.x)
.attr(\"x\", x(d.x))
.attr(\"y\", y(d.y));
});
This concise example demonstrates common way how to create custom tooltip in d3.
var w = 500;
var h = 150;
var dataset = [5, 10, 15, 20, 25];
// firstly we create div element that we can use as
// tooltip container, it have absolute position and
// visibility: hidden by default
var tooltip = d3.select(\"body\")
.append(\"div\")
.attr(\'class\', \'tooltip\');
var svg = d3.select(\"body\")
.append(\"svg\")
.attr(\"width\", w)
.attr(\"height\", h);
// here we add some circles on the page
var circles = svg.selectAll(\"circle\")
.data(dataset)
.enter()
.append(\"circle\");
circles.attr(\"cx\", function(d, i) {
return (i * 50) + 25;
})
.attr(\"cy\", h / 2)
.attr(\"r\", function(d) {
return d;
})
// we define \"mouseover\" handler, here we change tooltip
// visibility to \"visible\" and add appropriate test
.on(\"mouseover\", function(d) {
return tooltip.style(\"visibility\", \"visible\").text(\'radius = \' + d);
})
// we move tooltip during of \"mousemove\"
.on(\"mousemove\", function() {
return tooltip.style(\"top\", (event.pageY - 30) + \"px\")
.style(\"left\", event.pageX + \"px\");
})
// we hide our tooltip on \"mouseout\"
.on(\"mouseout\", function() {
return tooltip.style(\"visibility\", \"hidden\");
});
.tooltip {
position: absolute;
z-index: 10;
visibility: hidden;
background-color: lightblue;
text-align: center;
padding: 4px;
border-radius: 4px;
font-weight: bold;
color: orange;
}
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js\"></script>