I am trying to add an OnClick event to the nodes of my force layout graph but when I try to click on them, nothing happens. I believe that it is because I am not using an svg element and the .on("click", click) only works with svg elements I think but I am not entirely sure. Here is the code that I am trying to implement:
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("circle")
.attr("r",function(d) {return d.size})
.style("fill",function(d) {return color(d.type);})
.on("click", click)
.call(force.drag);
node.append("title")
.text(function(d){return d.name;});
force.on("tick", function(){
node.attr("cx", function(d){return d.x;})
.attr("cy", function(d) {return d.y;});
link.attr("x1", function(d){return d.source.x;})
.attr("y1", function(d){return d.source.y;})
.attr("x2", function(d){return d.target.x;})
.attr("y2", function(d) {return d.target.y;});
});
function click() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 30)
.style("fill", "lightsteelblue");
}
When I try and click on a node, nothing happens. I am not sure what to do. I think the problem has to do with the:
.enter().append("circle")
I think it needs to be an svg element like ("g") or ("svg") but I couldn't figure that out. Any advice or suggestions would be appreciated. Thanks!
You have an extra .select("circle") in click(). Instead, it should start with just:
function click(){
d3.select(this).transition()...
}
Related
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.
I found no direct answer for this, please forgive me if this has been covered differently in another topic.
I draw a bar chart which appears with a transition. I also want to add a tooltip which displays the value of data on mousehover.
Using the code below I have managed to obtain either the tooltip or the transition, but never the 2 together, which is my objective.
chart.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", function(d) {return colorscale(colorize(d.age));})
.attr("x", function(d) {return xscale(d.name);})
.attr("y", height - 3)
.attr("height", 3)
.attr("width", xscale.rangeBand())
.append("title")
.text(function(d){return d.age;})
.transition()
.duration(1600)
.attr("y", function (d) {return yscale(d.age);})
.attr("height", function (d) {return height - yscale(d.age);}) ;
If I remove
.append("title")
.text(function(d){return d.age;})
Then my transition works fine. If I but those 2 lines back I can see my tooltip but I lose my transition.
Any suggestion would be appreciated!
You can see the result here
Thank you
You need to add the transition to the rect and not the title element:
var sel = chart.selectAll(".bar")
.data(data)
.enter()
.append("rect");
sel.append("title")
.text(function(d){return d.age;});
sel.transition()
.duration(1600)
.attr("y", function (d) {return yscale(d.age);})
.attr("height", function (d) {return height - yscale(d.age);}) ;
I have some circles that I want to change fill when I hover over them. I give them "pins" class and here's the CSS for them:
.pin {
fill: #9ecae1;
stroke:#3182bd;
}
.pin:hover{
fill:steelblue;
}
Each pin has a value and I want to include some transition so that if there is a change in that value, the circles will momentarily flash some other color, green for instance. They work fine without the update. After the update, the hover no longer works.
Here is my code for the transition:
d[2] is just some key name.
svg.selectAll("circle").data(points, function(d) {return d[2];})
.transition()
.duration(500)
.style("fill", "green")
.attr("r", function(d) {return 5 + 10*Math.ceil(radius(d[3]));})
.each("end", function(d){
d3.select(this).transition()
.style("fill", "#9ecae1");
});
I was able to pinpoint that setting style("fill", xxx) disables the hover but why? And is there a way to get the momentary transition while still maintaining the hover?
I understood the problem, that is in the below code
svg.selectAll("circle").data(points, function(d) {return d[2];})
.transition()
.duration(500)
.style("fill", "green")
.attr("r", function(d) {return 5 + 10*Math.ceil(radius(d[3]));})
.each("end", function(d){
d3.select(this).transition()
.style("fill", "#9ecae1");
});
we are applying the color by using inline style, this inline is more priority than external css, So don't apply the color by using inline style instead use the attribute(fill) to fill the color, the line of code we have to change is remove .style("fill", "green") and replace it with attr("fill", "green")
and .style("fill", "#9ecae1") with .attr("fill", "#9ecae1")
Below is the modified code
svg.selectAll("circle").data(points, function(d) {return d[2];})
.transition()
.duration(500)
.attr("fill", "green")
.attr("r", function(d) {return 5 + 10*Math.ceil(radius(d[3]));})
.each("end", function(d){
d3.select(this).transition()
.attr("fill", "#9ecae1");
});
:)
Here's the code I am running http://jsfiddle.net/a7as6/14/
I know that I can use this code to change node to image:
node.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px");
But when I use it and my nodes are still not images. Any idea why?
And I am wondering how to change each nodes with different images?
Thx.
You've got the right idea for appending the images, but you need to operate on node.enter() as in:
node.enter().append("image")
.attr("class", function (d) {
return "node " + d.id;
})
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("width", "16px")
.attr("height", "16px");
You then need to get your tick function to place the images, as in:
function tick() {
node.attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y;
})
And here's the working fiddle. Not that you'll need to move the images around so they look right, you can use the dx and dy properties to bump them.
This is a very basic question, but how do I access the value of attributes in d3?
I just started learning today, so I haven't figured this out yet
Suppose I have this as part of my code here
http://jsfiddle.net/matthewpiatetsky/nCNyE/9/
var node = svg.selectAll("circle.node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function (d) {
if (width < height){
return d.count * width/100;
} else {
return d.count * height/100;
}
})
.on("mouseover", animateFirstStep)
.on("mouseout",animateSecondStep)
.style("fill", function(d,i){return color(i);})
.call(force.drag);
For my animation the circle gets bigger when you mouse over it, and I want the circle to return to its normal size when you move the mouse away. However, i'm not sure how to get the value of the radius.
i set the value here
.attr("r", function (d) {
if (width < height){
return d.count * width/100;
} else {
return d.count * height/100;
}
I tried to do node.r and things like that, but i'm not sure what the correct syntax is
Thanks!
You can access an attribute of a selection with:
var node = svg.selectAll("circle.node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function (d) { return rScale(d.count); })
.on("mouseover", function(d) {
d3.select(this)
.transition()
.duration(1000)
.attr('r', 1.8 * rScale(d.count));
})
.on("mouseout", function(d) {
d3.select(this)
.transition()
.duration(1000)
.attr('r', rScale(d.count));
})
.style("fill", function (d, i) {
return color(i);
})
.call(force.drag);
in this context, this points to the DOM element binded with d. Normally, the area of a circle must be proportional to the quantities that you are showing, take a look at the documentation of Quantitative Scales. A fork of your fiddle is here.