D3 tooltip or mouseover on bar chart - javascript

var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate("+barWidth*i+",0)";
})
.on("mouseover", function() {
d3.select(this)
.attr("fill", "red");
})
.on("mouseout", function(d, i) {
d3.select(this)
.attr("fill", "blue");
});
I am trying to do a mouseover to show data. I am starting by trying to change the colour on a mouseover as per code above.
http://codepen.io/JohnnyBizzel/pen/xqbjVQ

I updated your codepen
A couple of things wrong here:
You are trying to apply the transition to the g and not the rect
Instead of attr you want to use style

Here is the solution:
.on("mouseover", function() {
d3.select(this).select('rect').style('fill', 'red');
})
.on("mouseout", function(d, i) {
d3.select(this).select('rect').style('fill', 'blue');
});
You need to select the shape that is into your element and his style function to change the color.

Related

Why is label not getting added to all my paths?

Plunker: https://next.plnkr.co/edit/17t5ujwC71IK3PCi
Why is following not adding a "test" label to all my polygons?
/* NOT Working code */
groups.selectAll('.path_placeholder')
.enter()
.append('text')
.text("test")
Update
.enter() wasn't required as mentioned by Xavier. Removing it showed "test" for all nodes. But why then its not working when I do provide data and use enter() as following:
groups.selectAll('.path_placeholder')
.data(groupIds, function(d) {
return d;
})
.enter()
.append('text')
.text(function(d){
console.log(d);
return d;
})
I am trying to be able to show label for each of my polygon and for now just trying to add a dummy label to each of them.
Your problem here is the paths is a <path> selection, not a <g> one:
paths = groups.selectAll('.path_placeholder')
.data(groupIds, function(d) { return +d; })
.enter()
.append('g')
.attr('class', 'path_placeholder')
.append('path')//this makes the selection pointing to <path> elements
.attr('stroke', function(d) { return color(d); })
.attr('fill', function(d) { return color(d); })
.attr('opacity', 0);
Because of that, when you do...
groups.selectAll('.path_placeholder')
.data(groupIds, function(d) {
return d;
})
.enter()
//etc...
... your "enter" selection is empty, because you already have data associated to that paths selection.
Besides that, it makes little sense using a proper "enter" selection for the texts, since the data is the same data bound to the groups.
Solution: the solution here, which is the idiomatic D3 for this situation, is creating an actual <g> selection.
We can do that by breaking the paths selection, and giving it another name:
pathGroups = groups.selectAll('.path_placeholder')
.data(groupIds, function(d) {
return +d;
})
.enter()
.append('g')
.attr('class', 'path_placeholder');
Then you can just do:
paths = pathGroups.append('path')
.attr('stroke', function(d) {
return color(d);
})
.attr('fill', function(d) {
return color(d);
})
.attr('opacity', 0)
texts = pathGroups.append('text')
.text(function(d) {
return d;
});
Here is the forked Plunker: https://next.plnkr.co/edit/31ZPXIvSI287RLgO

D3: .transition() not working with events

I'm busy plotting a bar chart using D3 in Angular4.
// Enter Phase
this.chart.selectAll('.bar')
.data(this.barData)
.enter()
.append('rect')
.attr('class', 'bar');
// Update Phase
let bars = this.chart.selectAll('.bar').transition()
.attr('x', (d) => {return this.x(this.parseTime(d.date.toUpperCase()));})
.attr('y', (d) => {return this.y(d.point)})
.attr('width', 15)
.attr('height', (d) => {return this.charDimensions.height - this.y(d.point);})
.on("mouseover", function (d) {D3.select(this).style('opacity', 0.5);})
.on("mouseout", function (d) {D3.select(this).style('opacity', 1);})
.on("click", (d) => {this.barClicked.emit(d);});
// Exit phase
this.chart.selectAll('.bar')
.data(this.barData)
.exit().remove();
In my plotting method, when I call animate() I get an error: Error: unknown type: mouseover. Which makes sense, since I'm probably trying to call the on("<event>") on a the transition returned by D3, the transition effect is there, however, everything after the transition breaks, i.e: The animation works, but the plotting is broken ofc.
However when I attempt to do the following:
// Update Phase
let bars = this.chart.selectAll('.bar');
bars.transition();
bars.attr('x', (d) => {return this.x(this.parseTime(d.date.toUpperCase()));})
.attr('y', (d) => {return this.y(d.point)})
.attr('width', 15)
.attr('height', (d) => {return this.charDimensions.height - this.y(d.point);})
.on("mouseover", function (d) {D3.select(this).style('opacity', 0.5);})
.on("mouseout", function (d) {D3.select(this).style('opacity', 1);})
.on("click", (d) => {this.barClicked.emit(d);});
No errors occur, but nothing happens, there is no transition effect to the new data set.
The problem here is a confusion between two different methods that use the same name:
selection.on(typenames[, listener])
transition.on(typenames[, listener])
Since you have a transition selection, when you write...
.on(...
The method expects to see three things (or typenames):
"start"
"end"
"interrupt"
However, "mouseover", "mouseout" or "click" are none of them. And then you get your error...
> Uncaught Error: unknown type: mouseover
Solution:
Bind the event listeners to a regular selection. Then, after that, create your transition selection.
Therefore, in your case, bind all the on listeners to the "enter" selection (which, by the way, makes more sense), removing them from the update selection.
Have a look at this little demo. First, I create a regular, enter selection, to which I add the event listener:
var bars = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
//some attr here
.on("mouseover", function(d) {
console.log(d)
});
Then, I add the transition:
bars.transition()
.duration(1000)
etc...
Hover over the bars to see the "mouseover" working:
var svg = d3.select("svg");
var data = [30, 280, 40, 140, 210, 110];
var bars = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("x", 0)
.attr("width", 0)
.attr("y", function(d, i) {
return i * 20
})
.attr("height", 18)
.attr("fill", "teal")
.on("mouseover", function(d) {
console.log(d)
});
bars.transition()
.duration(1000)
.attr("width", function(d) {
return d
})
.as-console-wrapper { max-height: 25% !important;}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

D3.js / Javascript Node-Lines pop-up window and color change

I am working on D3.js and I have a map with lines and nodes. When I come on them with mouse I want them to change color and get thicker and I want a small pop-up window which shows their IDs.
On HTML for the pop-up there is a function onmouseover.
First question: Is there any function in javascript like onmouseover?
Second question: Is there any way me to change the color and make the lines or nodes thicker when the mouse are on that specific node or line. (I can use JQuery if there is a way in JQuery)
For the tooltip I have this fiddle : http://jsfiddle.net/reko91/7NReF/36/
Firstly, create the container for the toolip :
var tooltip = d3.select("body")
.append("div")
.attr('class','tooltipdiv')
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
Then on mouseover set the text to what you want, mousemove, move the tooltip, and mouseout, hide the tooltip :
circles.on("mouseover", function(d){return tooltip.style("visibility", "visible").text(d);})
.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");});
As for the nodes, you can either style it directly or add a class and do it all in one. So you only need to change the CSS. So with the above being said, I have implemented both in this fiddle : http://jsfiddle.net/reko91/7NReF/37/
Source code :
var w = 500;
var h = 50;
var dataset = [ 5, 10, 15, 20, 25 ];
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
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;
});
var tooltip = d3.select("body")
.append("div")
.attr('class','tooltipdiv')
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
circles.on("mouseover", function(d){
d3.select(this).classed('hovernode', true)
return tooltip.style("visibility", "visible").text(d);})
.on("mousemove", function(){return tooltip.style("top",
(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){
d3.select(this).classed('hovernode', false)
return tooltip.style("visibility", "hidden");});
.tooltipdiv{
background:white;
}
.hovernode{
fill:red;
stroke:blue;
stroke-width:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
</body>
I have added the ability to change the border of the nodes
var node = svg.selectAll(".node")
.data(Data.nodes)
.on("mouseover", function(){
d3.select(this).style("stroke","thick"); // sample CSS operation.
})
this is the element a node in your case which you want to work on.
I would suggest against using jquery. I somehow feel d3 is faster than jquery and can implement similar functionality with greater control.
Okay I wrote a piece of code as an answer to change the color and it works:
.on("mouseover", function(){
d3.select(this)
.attr("fill", "orange");
})
.on("mouseout", function(d){
d3.select(this)
.attr("fill", "rgb(0, 0, " +(d*10) + ")");
});
first .on function makes it orange(you can change the color however you want, second .on makes the original color when you're not on the element anymore.
For pop-up window:
.append("title")
.text(function(d){return d;});

D3js - Multiple Instances of Single External SVG File

This is somewhat of an abstract question. I'm referencing Mike Bostock's code for importing an external svg file: http://bl.ocks.org/mbostock/1014829
My plan is to use an external SVG as an icon (or sprite) that will be used multiple times in one interface. Is there a method for creating a copy of the xml.documentElement below? In summary, how does one create multiple instances of one svg file without loading the file for each instance?
d3.xml("rect01.svg", "image/svg+xml", function(xml) {
document.body.appendChild(xml.documentElement);
});
The end goal is to add an external svg to each cell in the grid created from this example: http://bl.ocks.org/bunkat/2605010
Referencing the link above, how does one work the xml.documentElement data into the grid in the code below, so that the external svg is visible, rather than a rectangle?
var col = row.selectAll(".cell")
.data(function (d) { return d; })
.enter().append("svg:rect")
.attr("class", "cell")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("width", function(d) { return d.width; })
.attr("height", function(d) { return d.height; })
.on('mouseover', function() {
d3.select(this)
.style('fill', '#0F0');
})
.on('mouseout', function() {
d3.select(this)
.style('fill', '#FFF');
})
.on('click', function() {
console.log(d3.select(this));
})
.style("fill", '#FFF')
.style("stroke", '#555');
}
Referencing this jsfiddle, the line of code I needed is cloneNode(true):
.each(function(d, i){
var plane = this.appendChild(importedNode.cloneNode(true));
d3.select(plane).select("path").attr("fill", "blue");
})

Is there a javascript command for 'only run when the mouse is over but stop when its not over'

I know about onmouseover but I have a circle on a page that lights up when the mouse hovers over it. But it stays lit when the mouse comes off it until it hovers again, when it turns off again. Its really irritating. Is there a one instruction to trigger only when hovering? Here's the code, mostly not relevant though
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.group * 3; })
.style("fill", function(d) { return color(d.group); })
.call(force.drag)
.on('mouseover', connectedNodes)
.on("click", function(d) { getprofile(d); });
You need to define on mouse out event.
So your code will be like this:
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.group * 3; })
.style("fill", function(d) { return color(d.group); })
.call(force.drag)
.on('mouseover', connectedNodes)
.on('mouseout', doSomethingCallback)
.on("click", function(d) { getprofile(d); });
function doSomethingCallback(){
fill your circle with the original color
}
You're looking for mouseleave. Here's a D3 demo of it: http://bl.ocks.org/mbostock/5247027
You can use .on('mouseout', function(){}); to stop the function started whit mouseover.

Categories

Resources