D3.js Node specific rectangle image placed in node circle - javascript

How do I place a header image above the center text in a node?
Can I give each node a different header image? HOW?
Will the header image beable to scale according to node size?
The nodes/text are defined by size of node category/power and are scaled by:
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d) { return color(d.packageName); })
.attr("transform", function(d) { return "translate(" + d + ")"; });;
node.append("text")
.attr("dy", ".2em")
.style("text-anchor", "middle")
.text(function(d) { return d.className; })
.style("font-size", "1px")
.each(getSize)
.style("font-size", function(d) { return d.scale + "px"; });
If I need to create individual background images to fill the circles; What would be my options for distributing the individual images to the appropriate nodes?
If more information is needed please notify me below...

1. How do I place a header image above the center text in a node?
Exactly like you did it with the text. You need to insert an image at the correct place (you will need to calculate the offset)
2. Can I give each node a different header image? HOW?
I would suggest adding an imageUrl property to your source data and then bind to it in the same way that you bind to d.packageName in your code snippet above.
3. Will the header image be able to scale according to node size?
Yes you can scale the image according to node size, have a look at svg:transform https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform. Specifically the "scale" attribute.
An alternative and perhaps simpler approach would be to always draw the nodes the same size but wrap each node in a "g" (group). Then you only need to scale the whole group once.

Related

d3.js dendogram how to add links to leaf nodes and change colors [duplicate]

I am trying to add a link to the text elements of this D3 visualisation:
http://bl.ocks.org/1093025
I would like to be able to click on "flare", "analytics" and navigate to another page or click in the rectangle and perform the normal action, which is expanding the sub-trees.
I tried a few things that didn't work:
on event
I tried to add an on event to the svg:text element:
nodeEnter.append("svg:text")
.attr("dy", 3.5)
.attr("dx", 5.5)
.text(function(d) { return d.name; })
.on("click",function(d,i) { alert("Clicked on the text");});
foreignObject element
I tried to add the foreignObject element like this:
nodeEnter.append("svg:foreignObject")
.style("float","right")
.attr("height", 100)
.attr("width", 100)
.append("div")
.html("<a href='#'>link</a>")
Even though it creates the link, it is an extra link, though (not the text element in the rectangle).
link with xlink:href attribute
Finally, I also tried the following (in some combinations):
<a xlink:href="/svg/index.html">
<text x="10" y="20">/svg/index.html</text>
</a>
But it didn't work either.
Any suggestions?
I agree with Matt's answer re: pointer-events... change this to pointer-events: all in the css.
And this is how I made the link in the force directed graph:
svg = d3.select("body").append("svg");
svg.selectAll(".node")
.append("svg:a").attr("xlink:href", function(d){ return "generic.php?url=" + d.url })
.append("svg:text")
.text(function(d) { return d.name; })
.attr("dy", 3.5)
.attr("dx", 5.5)
.attr("text-anchor", "middle");
//The End ;-)
.on('click', function () {}) should work as long as you
have selected the right nodes
haven't disabled pointer events on text elements with css
The pointer events seems to be catching people out as quite a lot of the examples have pointer-events: none for the text nodes.

d3.js is not showing icons

i have been trying to insert an icon using d3.js.but i am not getting any icon when i am running it .here is my code snippet.
node = svg.selectAll('g.node')
.data(svg_nodes, function (d) {
return (d && d.svg_id) || d3.select(this).attr("id");
})
node.select('polygon:nth-of-type(8)')
.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
It appears you are appending an <image> to a <polygon>. An image is not a valid child of an SVG polygon, only animation elements or descriptive elements are valid children (MDN).
Permissible children include:
<animate>, <animateColor>, <animateMotion>, <animateTransform>, <discard>, <mpath>, <set>, <desc>, <metadata>, <title>
As you can't add an image to a polygon, you'll need to add it to a different parent, this also means positioning it separately.
Generally speaking, a useful approach here is often to use a parent g to position each polygon and image pair - this might remove the need to position image and polygon separately, but also keeps these elements paired as siblings of a common parent.
As it appears you already have a parent g, we only need to access it in order to append to it:
node.select('polygon:nth-of-type(8)')
.each(function() {
d3.select(this.parentNode)
.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
})
Without seeing more of your code it is not possible to say how this will position the image relative to what you want, but should at least append the image

d3.js path dom element

I am creating a streamgraph, having used the example code from http://bl.ocks.org/mbostock/4060954 as a template.
I draw the streamgraph:
var svg = d3.select("#graph_area").append("svg")
.attr("width", width)
.attr("height", height)
....
svg.selectAll("path")
.data(layers)
.enter().append("path")
.attr("d", function (d) {return area(d.layer);})
Now it seems that I am not allowed to choose a different name from "path" for the DOM element here. If I do, then streamgraph no longer plots. Why is that?
Then I want to add a legend with bullets, but they don't plot. The elements show up in my web inspector (firebug), but their graphical representation is just not there. I figured it might be a similar problem with the DOM element name, but I don't actually know. Here is the code for my bullets:
//draw all the legend bullets and effects
svg.selectAll("bullets")
.data(layers)
.enter().append("bullets")
.attr("cx", 200)
.attr("cy", function(d, i) { return 20 + i*10; })
.style("fill", function(d) { return d.color; })
.attr("r", 5)
I briefly looked at API's for paths here and here, but I didn't find my answers there.
The element names you can use are defined in the SVG specification. This is a specific set (e.g. path, circle) -- using anything else will work in terms of appending the element to the DOM, but the browser won't know how to interpret and render it.
It's the same way in HTML -- there's a specific set of defined element names that browsers know how to render.

CSS-Sprites + D3.js

I'm trying to append HTML elements within a <circle> and then use CSS-Sprite to fill them, but so far I can't see them!
Here's what im doing:
//Create the node in order to use the Force Layout
var node = svg.selectAll(".container")
.data(data)
.append("circle")
.attr("class", "dot")
.attr("r", radius)
.attr("cx", function(d) { return x(d[xVar]); }) //xAxis position
.attr("cy", function(d) { return y(d[yVar]); }) //yAxis position
.append("xhtml:i")
.attr('class', function(d) {
return 'sprite '+ d['css-code'];
});
And my css:
.sprite{
position: absolute;
background:url(sprite.png) no-repeat;
}
.ad{background-position:0 -704px;}
.ae{background-position:0 -736px;}
.etc
They are being generated and I can see them on my browser inspector with the correct css atributes but they just won't appear.
How do I use CSS-Sprites with D3's Force Layout?
You're inserting the <i> elements directly within the SVG <circle> elements, which is not legal SVG markup. There are at least a couple of alternatives that you could use.
Make the nodes <g> elements which would contain both the <circle> elements and a different element for the sprite.
Insert the HTML sprites directly in the HTML container for the graph and absolutely position them to correspond with the node positions.

Display icons/image instead of circle/path on map made with d3.js

I can successfully display some points on a openlayers basemap using d3.js however I want to actually display icons (at the moment maki png icons) instead of an svg point.
is it possible to load a png/jpg/svg image to a map using d3.js?
So far I can load the icon directly onto the svg but all the markers locate on the same spot so I think I'm having a problem converting the coordinates properly.
var feature = svg.selectAll("path")
.data(amenities.features)
.enter()
.append("svg:image")
.attr("xlink:href", "maki/renders/post-18#2x.png")
.attr("x", function(d, i) {return amenities.features[i].geometry.coordinates[0]})
.attr("y", function(d, i) {return amenities.features[i].geometry.coordinates[1]})
.attr("width", "20")
.attr("height", "20")
.attr("class", "amenity");
Previously I have been able to create an svg with image background inside it using a 'pattern' to show the image so that is also a possibility but I couldn't translate the code to use it with the geographic aspect of d3.
I know I'm writing the icons at the moment to the 'svg' div, so they don't transform correctly when I zoom in and out. I'm aiming to write the images to the 'g' div, as in have code like:
var feature = g.selectAll("path")
but when I use this line, the elements appear on the document but the icons don't actually render on the map.
Thanks in advance.
There a few issues here. First, I'm not sure you fully grasp how d3 selections works, as indicated by the fact that you are binding amenities.features to your selection and then accessing it for the x and y attributes via an index. See How Selections Work for more details on this. In addition, you need to translate the geographic coordinates of the features to screen coordinates by passing them through your geographic projection function. This should get you close:
// more projections: https://github.com/d3/d3-geo-projection/
var projection = d3.geoAlbers();
var amenities = svg.selectAll('.amenities')
.data(amenities.features);
amenities.enter().append('image');
amenities
.attr("class", "amenities")
.attr("xlink:href", "maki/renders/post-18#2x.png")
// The data is already bound so use it instead of the index. Als,
// you need to translate geo coordinates to screen coordinates by
// passing them through your projection function.
.attr("x", function(d,i) {return projection(d.geometry.coordinates)[0];})
.attr("y", function(d,i) {return projection(d.geometry.coordinates)[1];})
.attr("width", "20")
.attr("height", "20")
I don't think I appropriately used groups but I think the key is having the transform then translate thing in there.
So my example is http://bl.ocks.org/mpmckenna8/b87df1c44243aa1575cb.
But because I didn't use groups properly I don't know that the icons would handle zooming like you seem to want. In my example I just append the images to the circles I've created.
.attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr('opacity',.3)
.attr('fill', '#fad959')

Categories

Resources