I am having a very hard time since there is not much documentation on d34raphael tool.
I am trying to reproduce this example from d3.js: http://bl.ocks.org/d/1249394/ using raphael. The idea is to be able to run this into ie8 which doesn't support svg.
My biggest concern is replacing the "g" svg nodes with raphael code.
For example how to convert these statemetns into d34raphael:
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
or
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
I have read the documentation on d34raphael but it hasn't been useful.
Thanks for the help.
Raphael doesn't use the g element but has some notions of a set. d34raphael uses it directly:
paper.setStart()
...
paper.setFinish().transform(["t", margins.top, margins.left]);
But that's not very useful for a direct translation of d3 code. I suggest you flatten your data and all the logic to position your elements, instead of having your elements has children of a group.
Related
I'm using D3.js for my personal project.
But, I faced with some troubles.
bubble.nodes(root)
svg = d3.select("svg").attr("class", "bubble")
var node = svg.selectAll(".node")
.data(bubble.nodes(root)
.filter(function(d) {
return !d.children;
}))
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
In the picture, I want to get "r" value in the circle.
How can I get this value?
Also, this circle is one part of bubble chart node.
Using vanilla JS... getElementsByTagName('circle'), then getAttribute('r') to find the value of r
let circle = document.getElementsByTagName('circle');
let target = circle[0].getAttribute('r');
console.log(target);
<circle r="0.75847397430597"></circle>
This question already has an answer here:
Creating force layout node labels in d3.js
(1 answer)
Closed 4 years ago.
I have a plnkr which creates node directed graph something like this:
http://plnkr.co/edit/Usru9pGp98ju2d0St6Wz?p=preview
Currently it displays the node title when we hover over it using this function:
.on('mouseover', function(d) {
textTarget = d
text.attr('transform', 'translate(' + d.x + ',' + d.y + ')')
.text(d.id)
.style('display', null)
d3.select(this)
.style('fill', colors.nodes.hover)
d3.selectAll(childNodes(d))
.style('fill', colors.nodes.hover)
.style('stroke', colors.nodes.method)
.style('stroke-width', 2)
d3.selectAll(parentNodes(d))
.style('fill', colors.nodes.dep)
.style('stroke', colors.nodes.method)
.style('stroke-width', 2)
})
But my idea is to show the label everytime.
I found some similar question where they have asked to append label to node, so I tried this:
node.append("text")
.attr('transform', function())
.attr('transform', 'translate(' + d.x + ',' + d.y + ')')
.text(d.id)
.style('display', null)
But doing this breaks my graph.
I am little new to d3 world, so not able to figure out what exactly is going wrong in this case.
Can any one help me to display label always for all the node (either inside the node circle or appended with it)
Approach:
So my approach to that would to to create group elements g with circle and text inside them, and then we can use force layout to position them with transform. This way we only care about group element position and circle with text should follow that position. So the node structure might look like that:
<g transform='translate(30,70)'>
<circle r='3'>/<circle>
<text>sample text</text>
</g>
Code:
You have quite a lot of code in your sample so I'll just focus on having persistent labels over circles. This might break some other things I'm not focusing on but should give you direction and hopefully you'll be able to fix the rest if not fell free to ask.
Using your plunker first thing you have to do it so associate data with g elements instead of circle :
node = vis.selectAll('g.node')
.data(nodes, function(d) { return d.filename })
.enter().append('g');
Then you can append circles to those g elements, and in this case there is no need to define cx and cy as this is taken care of by transform applied to g elements, so all you need to specify is r and any other styles you wan to apply:
node.append('circle')
.attr('class', 'node')
.attr('r', function(d) {
return scale * (d.root ? 8 : d.module && !d.native ? 5 : 3)
})
(...)
Now you can add your labels:
node.append('text')
.text(function(d){return d.id})
.style('text-anchor',middle); // this will center label horizontally
One last step is to update on 'tick' function as before it was updating circle position and now we want it to update g position, so instead of:
node.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; });
you should do:
node.attr('transform', function(d) {
return 'translate('+ d.x + ',' + d.y + ')';
});
And here you have your plunker with my changes, hope thats what you asked for.
http://plnkr.co/edit/Q69DkEH5Z9aOe92UwlOB?p=preview
Fell free to ask any more questions if you have any :)
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click)
.on("mouseover",function (d){
if(d.name=="Purchased"){
jQuery.getJSON("RequestHandler?usercommand=jsoncompany&subcommand=propCount&useraction=d3Tree_frm&mgmtId="+d.id+"&type="+d.name, function(json){
var count=JSON.stringify(json.prop_purchased_count);
result="Purchased Property :"+count;
});
}
var g = d3.select(this);
var info = g.append("text")
.classed('info', true)
.attr('x', 30)
.attr('y', 30)
.text(result); //result="Amount":200\n"Amount":300\n"Amount":400
})
.on("mouseout", function() {
d3.select(this).select('text.info').remove();
});
//result="Amount":200\n"Amount":300\n"Amount":400
i want to display tooltip such that after \n it appears in a new line within that tooltip.
How to achieve it ?
Thanks in advance
I can see result being set in the code you posted, however what we cannot see is where result is being set to get the content you are 'saying' it contains. That way we could help you interpret the application of these proven recommendations a lot better. But in anycase, have a look at these resources to help you in your quest.
http://bl.ocks.org/mbostock/7555321
How to dynamically display a multiline text in D3.js?
In the else part add "Amount:"+ count + "\n" while you are concatenating the newline
I am having trouble with dynamically adding nodes on to a d3.js force directed graph and I was wondering if anyone here could shed some light on the subject.
The problem I am having is that I want the tick function to transform all nodes on the graph and not just the newly added ones.
Below are the functions I use for adding nodes and handling the transformation:
// Function to handle tick event
function tick() {
tick_path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" +
d.source.x + "," +
d.source.y + "L" +
d.target.x + "," +
d.target.y;
});
tick_node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; });
}
/**
* Append nodes to graph.
*/
function addNodes2Graph(){
// define the nodes
// selection will return none in the first insert
// enter() removes duplicates (assigning nodes = nodes.enter() returns only the non-duplicates)
var nodes = viz.selectAll(".node")
.data(g_nodes)
.enter().append("g")
.on("click", nodeClick)
.call(force.drag);
// From here on, only non-duplicates are left
nodes
.append("circle")
.attr("r", 12)
.attr("class", "node");
nodes.append("svg:image")
.attr("class", "circle")
.attr("xlink:href", "img/computer.svg")
.attr("x", "-8px")
.attr("y", "-8px")
.attr("width", "16px")
.attr("height", "16px");
// add the text
nodes.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function(d) { return d.ip; });
return nodes;
}
// Execution (snippet)
// Add new nodes
tick_node = addNodes2Graph();
// Add new paths
tick_path = addPaths2Graph();
// Restart graph
force
.nodes(g_nodes) // g_nodes is an array which stores unique nodes
.links(g_edges) // g_edges stores unique edges
.size([width, height])
.gravity(0.05)
.charge(-700)
.friction(0.3)
.linkDistance(150)
.on("tick", tick)
.start();
I think the problem is that I only get non-duplicated results returned from addNodes2Graph which I then use in the tick function but I'm not sure how I could achieve this without adding duplicated nodes on to the graph.
At the moment, it's either adding duplicated elements on to the graph or transform only the new nodes on tick.
Thank you very much for your help in advance.
It looks like you're adding nodes only to the DOM, not to the force layout. To recap, here's what you need to do to add nodes to the force layout.
Add elements to the array that the force layout uses for its nodes. This needs to be the same array that you passed in initially, i.e. you can't create a new array and pass that it if you want smooth behaviour. Modifying force.nodes() should work fine.
Do the same for the links.
Add the new DOM elements using .data().enter() with the new data.
No change to the tick function should be required as adding the nodes and DOM elements is done elsewhere.
After adding the new nodes/links, you need to call force.start() again to have it take them into account.
I have a force directed graph with different size nodes. I want to display a custom icon in the middle of each path connecting two nodes. From the d3 examples I found the way to display images within the nodes. However, when I try the same technique on the paths, the images are not shown.
var path = svg.append("svg:g").selectAll("path").data(force.links());
var pathEnter = path.enter().append("svg:path");
pathEnter.attr("class", function(d) {
return "link " + d.target.type;
})
pathEnter.append("svg:g").append("image")
.attr("xlink:href","http://127.0.0.1:8000/static/styles/images/add.png")
.attr("x",0).attr("y",0).attr("width",12).attr("height", 12)
.attr("class", "type-icon");
I guess I need a bit more patience before asking a question. The way I solved the problem is:
var icon = svg.append("svg:g").selectAll("g")
.data(force.links()).enter().append("svg:g");
icon.append("image").attr("xlink:href","imagePath")
.attr("x", -20)
.attr("y", -2)
.attr("width", 12).attr("height", 12)
.attr("class", "type-icon");
And then in the tick function:
icon.attr("transform", function(d) {
return "translate(" +((d.target.x+d.source.x)/2) + "," +
((d.target.y+d.source.y))/2 + ")";
});
to get the center point between the two nodes.