I created a multi line graph by d3.
I'm trying to create a handler for each line (path) but it doesn't work.
Here is the code creating the path:
var line2 = d3.svg.line()
.x(function(d, i){return x(AXValues[i])})
.y(function(d, i){return y(AYValues[i])});
p2 = svg.append("path")
.datum(ArticleData)
.transition()
.delay(1100)
.attr("id", "p"+i)
.attr("class", "p"+i)
.attr("d", line2(AXValues, AYValues))
.style("stroke", "Brown")
.style("stroke-width", 2)
.style("fill", "none");
Im trying to do something like this:
.on("mouseover", this.style("stroke-width", 5));
You'll need to attach the listener to the appended object:
p2.on("mouseover", function () {
d3.select(this).style("stroke-width", 5);
});
Thanks to #Lars Kotthoff for the correction
You can do this through css with the 'hover' event, for instance for the p2 class you are applying you can have some css that looks like this.
p2:hover {
stroke-width: 5;
}
hovering over would change the stroke-width to 5, and once the hover event is over the element will go back to its original stroke-width
Related
SOLVED
I am generating a hexbin plot in d3.js, where hexbins will be assigned different classes. I would like to change some attributes of the hexbins of a certain class on click. I would like to click on one hexbin (belonging to a class "class1"), and e.g. change the color of all the hexbins of that class to red. Here is the code I have written, which makes sense to me but it doesn't work:
svg.append("g")
.attr("clip-path", "url(#clip)")
.selectAll("path")
.data(hexbin(inputForHexbinFun))
.enter().append("path")
.attr("class", "km1")
.attr("d", hexbin.hexagon())
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; })
.attr("fill", function (d) { return color(d.length); })
.attr("stroke", "black")
.attr("stroke-width", "0")
.on("click", click)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave);
})
here I have assigned the same class "km1" to all hexbins for the sake of simplicity. I have inspected the result on Chrome and I can see that the class is successfully assigned to each hexbin. The function click, defined above the generation of the plot, is as follows:
var click = function () {
d3.selectAll("class", ".km1")
.style("fill", "red")
}
as a result, on click nothing happens, and no errors appear in console.
Thank you in advance for your help!
Solution
It was a silly mistake:
.selectAll does not require that you specify the type of selector, so instead of
.selectAll("class",".km1")
it is sufficient to write
.selectAll(".km1")
I want to implement a list on right-click of a data node. In order to do so I came across d3-context-menu plugin of d3.js. The problem I am facing is that the div element is getting appened outside the body tag.
I have never seen such an issue before.
I am following the plugin example given here:
http://plnkr.co/edit/hAx36JQhb0RsvVn7TomS?p=preview
This is the link to the library documentation:
https://github.com/patorjk/d3-context-menu
I have no clue why it is behaving in such manner. My code structure looks like this :
eventGroup = focusClip.selectAll(".event").data(data);
// Enter phase ---
eventGroupEnter = eventGroup.enter().append("svg");
eventGroupEnter.append("rect");
eventGroupEnter.append("circle");
eventGroupEnter.append("text");
// Event Group
eventGroup
.attr("class", "event")
.attr("x", function(d) {
return parseInt(x(d.time)) - 10;
}) // offset for the bg and center of dot
.attr("y", function(d) {
return parseInt(y(d.plotY));
})
.attr("width", function(d) {
return parseInt((d.label.length / 2)) + 60 + "em";
})
.attr("height", "20");
// Background
eventGroup.select("rect")
.attr("x", 0) // removes the "<rect> attribute x: Expected length, 'NaN'" Error
.attr("y", 4)
.attr("width", "100%")
.attr("height", "12")
.attr("fill", "url(#event-bg)");
menu = [{
title: "Item #1"
}];
// Dot
eventGroup.select("circle")
.attr("class", "dot")
.attr("r", 4)
.attr("cx", 10)
.attr("cy", 10)
.attr("fill", function(d) {
return d.evtColor ? d.evtColor : "#229ae5";
})
.attr("stroke", function(d) {
return d.evtColor ? d.evtColor : "#229ae5";
})
.attr("stroke-width", 2)
.on("contextmenu", d3.contextMenu(menu, function() {
console.log("Quick! Before the menu appears!");
}))
.on("mouseenter", tooltip.mouseover)
.on("mouseleave", tooltip.mouseout)
.on("click", annotateBox.click);
In order to explain it well I am adding the image of the chart:
The right click event is being called on the "dot" part of the event. Why would div element get appended outside the body?
This seems to be by design. If you look at the source code of that plugin, you'll see:
d3.selectAll('.d3-context-menu').data([1])
.enter()
.append('div')
.attr('class', 'd3-context-menu');
Since selectAll is called on the root, the div will be appended to the <html>, not to the <body>.
So, the author either did this intentionally or she/he forgot that d3.selectAll is different from selection.selectAll.
Here is a basic demo, click "Run code snippet", open your browser's dev tools and inspect the snippet window.
d3.selectAll("foo")
.data([1])
.enter()
.append("div")
.attr("class", "test")
<script src="https://d3js.org/d3.v3.min.js"></script>
You're gonna see this:
<html>
<head>...</head>
<body>...</body>
<div class="test"></div>
</html>
A part of my code which draws the d3 treemap nodes is given below:
var node = svg.datum(data).selectAll(".tree_rect")
.data(treemap.nodes)
.enter().append("rect")
.attr("class", "tree_rect")
.call(position)
.style("background", function(d) { return d.children ? null:color_scale(d.Percentage, d['Planned Date'], d['Actual Date']); })
.on("mousemove", mousemove)
.on("mouseout", mouseout)
Now, how can I get the color of that particular node, so that I could reuse it for a different function.
May be by giving each node an id something like this:
var node = svg.datum(data).selectAll(".tree_rect")
.data(treemap.nodes)
.enter().append("rect")
.attr("class", "tree_rect")
.attr("id", function(d) {/*SOME ID FOR THE NODE*/ return d.id;})
..
later on get the node's color using its id something like below:
var color = d3.select("#" ID)
.style("background")
Hope this helps!
Maybe try using the .style attribute.
Example
var t = node.append("text")
.style("color", function(d){ //your function definition for color here//});
I am creating a force-layout graph using d3 and I am trying to make the name of a specific node appear when I mouse over that node. I know how to add the text before any mouse over effect and thought that I could just move that part of the code into the mouseover function but that did not work. I will also need to make the text disappear when I move the mouse off of the node. Here is the mouseover function where I attempt to add the name to the node:
function mouseover() {
d3.select(this).transition()
.duration(750)
.attr("r", function(d) {return d.size + 10;});
var labels = gnodes.append("text")
.text(function(d) { return d.name;})
console.log(labels);
}
Here is a link to a fiddle of the complete code as well:
http://jsfiddle.net/ohiobucks23/QvVU6/
If not using a tooltip per good recommendation by Bhatt, you will need to:
1) declare gnodes outside the drawGraph() function so that it is visible to the mouse functions, and
2) make the following changes to the mouse functions:
function mouseover(d) {
d3.select(this).transition()
.duration(750)
.attr("r", function (d) {return d.size + 10;});
// locate node and append text; add class to facilitate subsequent deletion
gnodes.filter(function (o) {return o.index === d.index;})
.append("text")
.attr("class", "nodetext")
.text(d.name);
}
function mouseout(d) {
d3.select(this).transition()
.duration(750)
.attr("r", function (d) {return d.size;});
// delete text based on class
d3.selectAll(".nodetext").remove();
}
Here is the complete FIDDLE. I changed the text of the root node element so that you can see that the mouseover function is really acting on the selected node.
Ok so I have the following code example where I have circles in an svg element. Each circle has a click event and I'm trying to animate the circle that was clicked. Currently all circles animate because I'm referring to the bubble object. What I want is to refer to the clicked object its self and not the other ones:
var data_items=[100,200,300];
var svg = d3.select("#chart")
.append("svg").attr("width", 800).attr("height", 600);
var g = svg.selectAll(".bubbleContainer")
.data(data_items)
.enter().append("g")
.attr("class","bubbleContainer");
var bubble = g.append("circle")
.attr("class","bubble")
.attr("cx", function(d) {
return d;
})
.attr("cy", function(d) {
return d
})
.attr("r", function(d) {
return d/2
})
.on("click",function(d){
bubble
.transition()
.duration(1000)
.attr("r",1000)
})
Any help is much appreciated
Thanks!
What Lars Kotthoff wrote would work. Alternatively – and I'm not sure which is more idiomatic:
Inside the click handler, the this context refers to the clicked DOM element.
So the following would do it too:
.on("click",function(d){
d3.select(this)
.transition()
.duration(1000)
.attr("r",1000)
});
You can use d3.event.target to access the element that is being clicked in the event handler. See for example this jsfiddle.