In my Rails app I have D3.js circles that are created dynamically from data in my Rails app. I'd like to hyperlink the circles so when you click on one, it loads a partial associated to the model that the circle is visualizing.
Here's my D3 code:
d3JSON = function(){
d3.json("/folders/<%= #folder.id %>.json", function(error, data) {
if (error) return console.warn(error);
var folderChildren = [],
circle;
var svg = d3.select("body").selectAll("svg");
circle = svg.selectAll("circle")
.data(data.submissions, String);
circle.enter().append("svg:a")
.attr("xlink:href", function(d){
return "http://localhost:3000/submissions/" + d.id;
})
.append("circle")
.attr("cy", function(d) {return d.content.length * 5 + "px";})
.attr("class", "floating")
.attr("cx", function(d){
return (d.content.length / 2) * 10 + "px";
})
.attr("r", function(d){ return (d.content.length / 2) * 1.2;});
circle.exit().remove();
});
};
Everything works great except for when the the circle enter's and has an a attribute appended. As you can see, right now I have the circle just linking directly to the submission model associated to it. I've tried using this:
circle.enter().append("svg:a")
.attr("xlink:href", function(d){
return "<%= link_to submission_path(" + d + "), remote: true %>";
})
But that fails to work. Also replacing "d" with "d.id" doesn't work. Any ideas? I'm new to D3.
What you are trying to do is writing Ruby in JavaScript strings, which obviously wouldn't work.
You can simply put these links in the json.
Related
I have two d3 visualizations, and when I click on a link on the sankey diagram (defined by an email), I want to change the radius of the corresponding node (with the same email) on the force directed network graph. No matter what I try or search on the internet I cannot find a way to adjust the attribute of one individual node without selecting all the circles.
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.on("click", function (d,i){
svg2.selectAll("circle").each(function (f,i){
if (f.id == d.email)
{
//CHANGE RADIUS OF F or color or anything
//svg2.select(f).attr("r",10); DOESNT WORK
//f.attr("r",10) DOESNT WORK
}
});
})
.attr("d", path)
.style("stroke-width", function(d)
{ return Math.max(0.2, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
So I have a visualization and I'm trying to use d3.tip() - https://github.com/Caged/d3-tip/blob/master/docs/initializing-tooltips.md#d3tip
This is my code-
this.svg = d3.select(".timechart").append("svg")
.attr("width", this.width + this.margin.left + this.margin.right)
.attr("height", this.height + this.margin.top + this.margin.bottom)
.append("g")
.attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
svg.selectAll('.point')
.data(newData)
.enter()
.append("svg:circle")
.attr("cx", function(d,i){
var date = d["date"].match(/(\d+)/g);
date = new Date(date[2], date[0], date[1]);
return xScale(date);
})
.attr("cy", function(d,i){
var quantitySold = yScale(d["quantity-sold"]);
return quantitySold;
})
.attr("fill", "red")
.attr("r", 4)
.on("mouseover", function(d){
tooltip.show();
})
.on("mouseout", function(d){
tooltip.hide();
});
var tooltip = d3.tip()
.attr("class", "tooltip")
.offset([0,5])
.html(function(d){
console.log(d);
return "<strong> 20 </strong>";
});
svg.call(tooltip);
The console.log(d) gives me undefined, when it should give me the datum.
Why?
I also realize - I'm not sure what code I should post here to help - just let me know what would be useful.
The tooltip library that you're using (d3.tip) creates a single html tooltip for the entire visualization. The data for a particular element is passed to the tooltip using the tooltip's .show(d,i) method.
This example from the plug-in's creator shows how it is supposed to work. In particular, note that the show and hide methods are given directly as parameters to the .on(event, function) method of the rectangle selection:
svg.selectAll(".bar")
/* ... */
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
When the event occurs, d3 will therefore call these methods and pass the data object to them as a parameter.
In contrast, in your code:
.on("mouseover", function(d){
tooltip.show();
})
.on("mouseout", function(d){
tooltip.hide();
});
d3 will pass the data to your anonymous function, but you do not pass it on to the show/hide functions. So the data is undefined when the tooltip's show function tries to set the html content of the tooltip.
If you find that all confusing still, you might appreciate this write-up about passing functions as parameters.
Finally, although it isn't your main problem right now, you should be defining the tooltip before assigning its functions to an event handler. If you tried to do .on('mouseover', tooltip.show) before defining tooltip, you would get an error. You only avoided it by wrapping that function call in another function.
I'm working on building a molecule creator in D3 using the original example created by Mike Bostock: http://bl.ocks.org/mbostock/3037015
I'm using a force layout just like in the example. My problem is when I add a new Node/atom dynamically, it doesn't move with the rest of the graph. I've read other questions and implemented everything that is suggested and have made sure that I'm following the proper update/join procedure that D3 requires and yet still the added carbon refuses to move with the rest of the graph.
Here is my update/create function:
function buildMolecule () {
// Update link data
link = link.data(links);
// Create new links
link.enter().append("g")
.attr("class", "link")
.each(function(d) {
d3.select(this)
.insert("line", ".node")
.style("stroke-width", function(d) { return (d.bond * 2 - 1) * 2 + "px"; });
d3.select(this)
.filter(function(d) { return d.bond > 1; }).append("line")
.attr("class", "separator");
d3.select(this)
.on("click", bondClicked);
});
// Delete removed links
link.exit().remove();
// Update node data
node = node.data(nodes);
// Create new nodes
node.enter().append("g")
.attr("class", "node")
.on("click", atomClicked)
.each(function(d) {
console.log('d:', d);
// Add node circle
d3.select(this)
.append("circle")
.attr("r", function(d) { return radius(d.size); })
.style("fill", function(d) { return color(d.atom); });
// Add atom symbol
d3.select(this)
.append("text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.atom; });
d3.select(this).call(force.drag);
});
// Delete removed nodes
node.exit().remove();
force.start();
}
JsFiddle: http://jsfiddle.net/2dPMF/1/
Any help would be greatly appreciated!
You're modifying the data structures of the nodes and links beyond adding and deleting nodes, which messes up the force layout. I'm talking about these lines in particular.
function bigBang () {
links = links.concat(linksList);
nodes = nodes.concat(nodesList);
buildMolecule();
}
The first two lines in that function are what I'm talking about. Working jsfiddle here.
I am a newbie in d3.js
I am trying to add labels to my nodes.
But whatever I tried is not working..
My code is here:
http://jsfiddle.net/Ymtg5/1/
Its a mash up between http://bl.ocks.org/christophermanning/4208494
and force directed graphs.
Basically I am reading a json file and creating the said graph.
Now I want to add labels to node exactly like http://bl.ocks.org/mbostock/950642
I tried adding these lines
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
But its not working.
Any help. suggestions..
Thanks
Most probably the problem is that your JSON classes don't have a "name".
Right, this was not the problem
The relevant part of your code is as follows:
var node = svg.selectAll("path.node")
.data(nodes)
.enter().append("path").attr("class", "node")
.style("fill", function(d) { return fill(d.value); })
.style("stroke", function(d) { return d3.rgb(fill(d.value)).darker(); })
.call(force.drag);
// HERE should go node manipulation to add the text
force
.nodes(nodes)
.links(links)
.on("tick", tick)
.start();
function tick() {
//node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; );
node.attr("d", function(d) { return clip({"type":"F {"type":"Point","coordin...
link.attr("d", function(d) { return clip({"type":"Feature","geometry":{ ...
I have inserted a comment line where your node manipulation should go, if you want to add labels to the nodes. You are doing that inside the tick function (well, I think you are trying to do it there, the code isn't in the fiddle), and that function should be only for manipulation of the attr of the nodes. The place to create the text and append it to the node is outside of the function.
I made a scatter plot, and want to add a link to each dot.
chart.selectAll("scatter-dots")
.data(data)
.enter().append("circle")
.attr("cx", function (d) { return x(d.position[0]); } )
.attr("cy", function (d) { return y(d.position[1]); } )
.attr("r", 4)
.style("fill", "#666")
.style("opacity", 0.5)
.on("click", function(){
var url = "http://somelink.com/link.php?id=";
url += d.link_id;
//$(location).attr('href', url);
//window.location = url;
});
It works if I just put the pure String link such as
window.location = "http://stackoverflow.com"
However, if I add queries to the end of the URL from a variable, the page does not redirected.
Neither jquery nor javascript worked (as commented.)
I also tried an external js file, still fail.
This is in a PHP file, if this helps.
If it works with a static string then something is wrong with d.link_id. Try seeing what's inside either by doing alert(d.link_id) or if you use a firebug or similars do console.log(d.link_id).
Alternatively, you should use real anchors for linking your nodes instead of setting click events. This would go something like...
chart.selectAll("scatter-dots")
.data(data)
.enter()
.append("a")
.attr("xlink:href", function(d) {return "http://somelink.com/link.php?id=" + d.link_id})
.append("circle")
.attr("cx", function (d) { return x(d.position[0]); } )
.attr("cy", function (d) { return y(d.position[1]); } )
.attr("r", 4)
.style("fill", "#666")
.style("opacity", 0.5)
(I can't seem to recall if this is the exact way of doing it, you might need to save the anchors in a variable and then append the circles to them.)