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.
Related
I have been trying to append a set of SVGs inside SVG. So, in inside SVG, I want to create a function to make plot. However, this doesn't work in the way I expected as the inside SVGs don't have the dimension according to my specification. So, I'd like to know what went wrong.
svg_g_g = svg_g.append("g")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + xScale(d.key) + "," + lift + ")"
})
.append("svg")
.attr("width", function(d) { return xScale(d.key) })
.attr("height", height)
.append("line")
.style("stroke", "black")
.attr("x1", function(d) { return xScale(d.key) })
.attr("y1", height-100)
.attr("x2", function(d) { return xScale(d.key) + 50 } )
.attr("y2", height-100);
This is the output.
While if I bind data to g (without appending svg), the result looks more promising.
svg_g_g = svg_g.append("g");
svg_g_g.selectAll("line")
.data(data)
.enter()
.append("line")
.style("stroke", "black")
.attr("x1", function(d) { return xScale(d.key) })
.attr("y1", height-100)
.attr("x2", function(d) { return xScale(d.key) + 50 } )
.attr("y2", height-100);
and this is the result. (notice: the lines were shown in this case)
Any help will be appreciated.
edit: what I intended to do was I wanted to create a box-plot, I used "iris" dataset here as I can compared it against other data visualisation libraries. The current state I tried to create a SVG with an equal size for each category which I would use to contain box-plot. In other words, after I can create internal SVGs successfully, I will call a function to make the plot from there. Kinda same idea Mike did here.
I am trying to do the following:
Click a node
Enlarge the image of that node according to its current width and height
The idea is to determine x,y position based on its own width and height so it does not run wild.
My code for force tick
function render(){
force.on("tick", function() {
node.attr("x", function(d) {return d.x-d.width/2})
.attr("y", function(d) {return d.y-d.height/2});
Declaration of node
var node = container.append("g").selectAll(".node")
.data(graph.nodes)
.enter()
.append("image")
.attr("xlink:href",function(d){return d.type+ ".svg" ;})
.attr("class", "node")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("width", "24px")
.attr("height", "24px")
.attr("isChosen", "no")
.on("click",click);
Sample of data
"nodes":[
{"id":"0", "name":"ETCO I","type":"Company","trust":50},
{"id": "1","name":"PINKERTON Eidel ","type":"human","trust":50}
],
"links":[
{"source":1,"target":0,"linktype":"Secretary"},
{"source":1,"target":0,"linktype":"Director"},
Click handle
function click(node)
d3.select(this)
.attr("isChosen", "yes")
.transition()
.duration(750)
.attr("x", function(d) {return d.x-24})
.attr("y", function(d) {return d.y-24})
.attr("width", "35px")
.attr("height", "35px")
but it does not work, the image is all on left conner. Where does my logic go wrong?
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've brought some of my code to match D3 standards. But now I'm having issues with my update function working. I'm trying to follow the General Update Pattern.
When I run the function, I get an error in the console: "TypeError: gbars.enter(...).attr is not a function"
function updateBars()
{
xScale.domain(d3.range(dataset.length)).rangeRoundBands([0, w], 0.05);
yScale.domain([0, d3.max(dataset, function(d) { return (d.local > d.global) ? d.local : d.global;})]);
var gbars = svg.selectAll("rect.global")
.data(dataset);
gbars.enter()
.attr("x", w)
.attr("y", function(d) {return h - yScale(d.global); })
.attr("width", xScale.rangeBand())
.attr("height", function(d) {return yScale(d.global);});
gbars.transition()
.duration(500)
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d.global);
})
.attr("width", xScale.rangeBand())
.attr("height", function(d) {
return yScale(d.global);
});
gbars.exit()
.transition()
.duration(500)
.attr("x", -xScale.rangeBand())
.remove();
}
I understand, I probably have a lot of errors with the update function in general, but it's hard to troubleshoot when hung-up at the beginning.
My goal for the update will be to remove/add series from the chart. They can choose to display Global, Local, or both (default). I'd actually prefer that when they hover over the legend it shows only that series. On mouseout, it would go back to default.
Working Fiddle here.
You need to say what you want to do for new nodes. Yes it's almost always append but you still have to tell it:
gbars.enter()
.append("rect")
.attr("class", "global")
.attr("x", w)
Other than that error, your structure for general update pattern looks correct on the surface.
I am trying to modify this D3.js example (Dynamic Node-Link Tree) by adding a specific label (SVG text) to each node, but unsucessfully.
If I understand correctly, after a brief look at SVG specs and D3 documentation, the best way would be to create SVG groups and move them around.
Unfortunately, this is not working, as the transitions have no effect on the groups.
Is there a simple(r) way I am not aware of?
Many thanks.
If you're looking for an effect where you switch the circles for text labels, you can do the following:
// Enter any new nodes at the parent's previous position.
node.enter().append("svg:text")
.attr("class", "node")
.attr("x", function(d) { return d.parent.data.x0; })
.attr("y", function(d) { return d.parent.data.y0; })
.attr("text-anchor", "middle")
.text(function(d) { return "Node "+(nodeCount++); })
.transition()
.duration(duration)
.attr("x", x)
.attr("y", y);
See the fiddle here: http://jsfiddle.net/mccannf/pcwMa/4/
Edit
However, if you're looking to add labels alongside the circles, I would not recommend using svg:g in this case, because then you would have to use transforms to move the groups around. Instead, just double up on the circle nodes and text nodes like so in the update function:
// Update the nodes…
var cnode = vis.selectAll("circle.node")
.data(nodes, nodeId);
cnode.enter().append("svg:circle")
.attr("class", "node")
.attr("r", 3.5)
.attr("cx", function(d) { return d.parent.data.x0; })
.attr("cy", function(d) { return d.parent.data.y0; })
.transition()
.duration(duration)
.attr("cx", x)
.attr("cy", y);
var tnode = vis.selectAll("text.node")
.data(nodes, nodeId);
tnode.enter().append("svg:text")
.attr("class", "node")
.text(function(d) { return "Node "+(nodeCount++); })
.attr("x", function(d) { return d.parent.data.x0; })
.attr("y", function(d) { return d.parent.data.y0; })
.transition()
.duration(duration)
.attr("x", x)
.attr("y", y);
// Transition nodes to their new position.
cnode.transition()
.duration(duration)
.attr("cx", x)
.attr("cy", y);
tnode.transition()
.duration(duration)
.attr("x", x)
.attr("y", y)
.attr("dx", 4)
.attr("dy", 4); //padding-left and padding-top
A fiddle that demonstrates this can be found here: http://jsfiddle.net/mccannf/8ny7w/19/