Having problems using images as nodes in a force-directed graph. Everything I've looked at so far seems to be v3 code and I haven't been able to get any images at all so far, whether using xlink:href or svg:image or both.
What's the right way to use an img as a node with v4?
Here's what I'm trying, and a jsfiddle.
As you can see in the CSS, I'm trying to get images from a spritesheet for each node.
var defs = d3.append("svg:defs");
defs.append("svg:pattern")
.attr("width", 48)
.attr("height", 48)
//.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", "http://placekitten.com/g/48/48")
.attr("width", 48)
.attr("height", 48)
.attr("x", 0)
.attr("y", 0);
var nodesDrawn = svg
.selectAll("node")
.data(nodesData)
.enter()
.append("g")
//.append("xhtml:i")
.append('circle')
.attr('r', 10);
The problems so far:
There is no d3.append in D3. You probably meant svg.append.
Set the width and the height of the <pattern> to 1.
Set an ID to the <pattern> and use that to fill the circles.
Here are the code with that changes (I'm increasing the circles' radii, so you can better see the image): https://jsfiddle.net/ppk23hnz/
By the way, none of those changes are related to D3 version: they are the same in v3.x and v4.x.
PS: Don't mix jQuery and D3. you don't need that (and it's quite disturbing).
Related
Still being rather inexperienced in using d3.js I have hit a road block.
Hoping anybody out there can help me.
I am trying to display a picture upon mouse click on a node in a graph.
Ideally, I'd like to click on several nodes and display images. Double click on a node should remove the image. And clicking on the background removes all displayed images. But one step at a time.
What I have done so far is:
Succeeded in using tooltips. I was also able to change the size of a circle node upon mouse clicking on it.
I used as toy project Mike Bostock's force-directed graph example: https://bl.ocks.org/mbostock/4062045 .
I am using d3.js v4
Based on an example on the web I was able to add pictures to all nodes:
Add different images for nodes in d3 v4 network graph
I tried to tailor this example to my needs. First I added:
var defs = svg.append('defs');
Further more:
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(node_drag)
.on("click", function(d){
defs.append("pattern")
.attr("x", 0)
.attr("y", 0)
.attr("width", 12)
.attr("height", 12)
.append("image")
.attr("xlink:href", 'https://assets-cdn.github.com/images/modules/open_graph/github-octocat.png')
.attr("width", 12)
.attr("height", 12)
.attr("x", 0)
.attr("y", 0);
})
In my browser the html indicates that the image is added:
But the image is not showing in the browser.
At this point I am turning to you and hope for some hints how I can accomplish displaying an image as node upon clicking with my mouse cursor on it.
Any input is highly appreciated,
Markus
Your inspector is showing that the image was appended to the pattern, but it was never linked to the circle element.
Instead of appending the pattern to the defs inside the click function, you should just append the pattern with a given ID...
var defs = svg.append('defs');
defs.append("pattern")
.attr("x", 0)
.attr("y", 0)
.attr("id", "myPattern")//ID here
.attr("width", 12)
.attr("height", 12)
.append("image")
.attr("xlink:href", 'https://assets-cdn.github.com/images/modules/open_graph/github-octocat.png')
.attr("width", 12)
.attr("height", 12)
.attr("x", 0)
.attr("y", 0);
... and then, inside the click, just change the fill of the circle according to that ID:
.on("click", function() {
d3.select(this).attr("fill", "url(#myPattern)")
})
Here is Bostock's bl.ocks with those changes (I made the circles bigger so you can better see the image): https://bl.ocks.org/anonymous/0e653b6d21c8d57afa234d5d1765efe0/78ba15e533a2b8f8e6575a30d97b27d156ce2faf
I'm trying to change the size of dots on a map in D3. Basically, just want to re-size the circle SVG in D3. I just want all the circles to be smaller, not trying to create proportional symbols. Here's my circles:
var centroid = map.selectAll(".centroid")
.data(centroid.features)
.enter()
.append("path")
.attr("d",path)
.attr("r", 100)
.attr("class", function(d){
return "centroid "+d.properties.info_city;
})
It's not working. I know that I can't do this in CSS, any thoughts on how to accomplish this in javascript as I'm trying to do? Thanks all!
Take a look at this plunker and let's move on from there: http://plnkr.co/edit/lKtCBKFS764MThajrqxX?p=preview
This map has similar centroids like yours. These are defined in:
g.selectAll(".centroid").data(centroids)
.enter().append("circle")
.attr("class", "centroid")
.attr("fill", fill)
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("r", radius)
.attr("cx", function (d){ return d[0]; })
.attr("cy", function (d){ return d[1]; });
By changing .attr("r", radius) line (which is 6 in the config) to .attr("r", 2) you will get smaller circles
Here's the changed one: http://plnkr.co/edit/JUpMlnhZvZNacAIzI502?p=preview
I think you are trying to change the wrong part of the code since you should change the "r" of the circle elements not the "path" element ( I don't think path element even has a "r" attribute).
If your circles are drawn by a path then you must change the algorithm that draws those circles.
You are using the centroid coordinates to append a path as if it was a circle. This is not usual, the most common choice would be using a SVG circle, but it's OK... actually, Bostock does the same here.
The only problem is, as these are paths, not circles, changing the radius (r) will have no effect. So, to change the size of these "circles", this is what you have to do: find your d3.geo.path and add pointRadius to it.
var path = d3.geo.path()
.projection(projection)
.pointRadius(someValue);
Where someValue is, of course, some numeric value that fits your needs.
PS: for this to work properly, the types in your TopoJSON have to be "Point" or "MultiPoint".
I've just started using D3 V4 and I'm having trouble getting a pan and zoom function working. The problem is that I want the initial scale value to be something over than 1 so I set this using
zoom.scaleTo(svg, 2);
However as soon as I pan or zoom the scale resets back to 1.
Here's an example of this behavior on JSFiddle, what am I doing wrong?
JSFiddle
Here's the problem:
var svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600)
.call(zoom)
.append("g");
You are assigning the group element instead of the svg element to the variable svg.
The zoom is correctly applied to the svg element, but then when you call zoom.scaleTo(svg, 2) you are zooming the group element, not the svg element.
This can be fixed by first creating and assigning the svg element to the svg variable and only then creating and assigning the group element.
var svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600)
.call(zoom);
var mainContainer = svg.append("g");
Here's the fixed JSFiddle: https://jsfiddle.net/skgktrcu/2/
I would like to add header to my nodes in d3. But instead of appending it as text I want to append it as image so that in graph scenario all lines will be below header and picture will look cleaner.
Currently because of many links picture looks messy which I want to avoid.
node.append('text')
.attr("class","label")
.attr("style","font-size:12px;")
.html(function(d){
return d.name;
}
})
.attr("x",0)
.attr("y",-radius);
Is there any way how to do this. I read about hidden canvas but not sure exactly how to use here as I am beginner in D3.
Thanks
You can append an image as well.
I've set up a fiddle here, to showcase a working example of appending an image(icon) inside a circle.
node.append("circle")
.attr("cursor","pointer")
.attr("cx", 200)
.attr("cy", 200)
.attr("r", 25)
.style("fill","white")
.style("stroke", "black")
.style("stroke-width", 2);
node.append("image")
.attr("xlink:href", "http://i.stack.imgur.com/bZXWH.png")
.attr("x", 185)
.attr("y", 185)
.attr("width", 32)
.attr("height", 32);
You might also find this tutorial helpful.
I'm using d3.js to generate some rects which are directly above one another, in this fashion:
var greenRed = d3.select(".green-red").append("svg")
.attr("height", 120);
greenRed.append("rect")
.attr("fill", "green")
.attr("x", 0)
.attr("y", 0)
.attr("height", 50)
.attr("width", 300);
greenRed.append("rect")
.attr("fill", "red")
.attr("x", 0)
.attr("y", 50)
.attr("height", 50)
.attr("width", 300);
I've noticed that depending on which colours are stacked on top of one another, there is either a very thin whitespace present between the rectangles, or a sort of "overlap" of the two colours.
You can see what I mean in this fiddle: http://jsfiddle.net/ysim/PrC7X/
You can see that for .green-green and .green-grey there's no issue (to the naked eye, anyway); but for .green-blue and .red-blue, there is an overlap, and for .green-red, there is an extra whitespace.
I've tried adding .attr("stroke-rendering", "crispEdges") (suggested here) and .attr("stroke", "none") to the rect elements, as well as wrapping both the rect elements in a g element within the svg and adding .attr("stroke-rendering", "crispEdges") to that (suggested here), but neither of those solutions work.
What's causing this extra whitespace/overlap, and how do I go about fixing it so that the colours are neatly aligned, like in the first two cases?
try setting the stroke-width property to 0
That's antialiasing. Add style="shape-rendering: crispEdges" to the <div> elements and it will go away. You could add it to the shapes themselves instead if you want either as an attribute or a style.
The other thing to do is to add 0.5 to the y co-ordinates of your shapes There's more information about why that works here