I'm currently building an app that graphs out github repos using Mike Bostock's D3 layout example found here: http://mbostock.github.io/d3/talk/20111018/tree.html
I'm trying to render a font-awesome font instead of the svg circle and I believe this is the code that is rendering the circle:
nodeEnter.append("svg:circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
I found a similar question and when I tried to use that code, it successfully rendered the font-awesome icons, but now the linkable text, though rendered, is hidden for some reason:
I tried manipulating the code but can't figure out how to get the text node and link text to also render.
Also, I have a feeling that this other code may be interfering with my appends and causing this error. Here is it is in full:
nodeEnter.append("svg:a")
// make the links open in a new page
.attr("target", "_blank")
.attr("xlink:href", function(d) {
console.log('d.name -->', d.name);
// d.data.path "" + d.name
var url = "https://" + URLtoArr[0] + "/" + URLtoArr[1] + "/" + URLtoArr[2] + "/" + "tree/master" + "/";
// if path is set (if it is NOT the root node), add it on to the end
if(d.data !== undefined) {
url += d.data.path;
}
return url;
// https://github.com/AndyLampert/repository-file-tree-generator/blob/master/public/css/main.css
})
.append("svg:text")
.text(function(d) { return d.name; })
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.style("fill-opacity", 1e-6);
Finally, here is my current working app on heroku:
http://github-file-tree-generator.herokuapp.com/
Thanks in advance!
The text icons are showing up, as you could tell from the DOM and from selecting text, but they are nearly completely transparent.
.style("fill-opacity", 1e-6); == almost invisible although not technically hidden
Some examples recommend using an almost-zero opacity to create clickable but invisible content (although you should really use the pointer-events property for that). You must have copied it over by accident.
Related
I'm quite new to web programming and its more or less like searching for a funcion and trying until stuff works. So you have an idea of my skill ;)
I'm trying to build a d3 visualization (after Mike Bostocks dendrogramm: http://bl.ocks.org/mbostock/4063570).
Within the tree I want to use internal links to a hidden div (with id='test') that uses a lightbox script (fancyBox: http://fancyapps.com/fancybox/).
So far, my d3 script produces following code for the link (copied from firebug):
<a class="fancybox" x="10" href="#test"><text class="nodeText" dy=".35em" text-anchor="start" style="fill-opacity: 1;" x="10"test</text>
When I'm using this code anywhere else (even in the d3-div) it works fine opening the lightbox div. But when I click on it within the d3 canvas it doesn't work.
The code for setting up the nodes and their properties (to create the code above) is as following:
nodeEnter.append("svg:a")
.attr("x", function(d) {
return d.children || d._children ? -10 : 10;
})
.attr("xlink:href", function(d){return d.url;}) // <-- reading the new "url" property
.attr('class', 'fancybox')
.append("text")
.attr("dy", ".35em")
.attr('class', 'nodeText')
.attr("text-anchor", function(d) {
return d.children || d._children ? "end" : "start";
})
.text(function(d) {
return d.name;
})
.style("fill-opacity", 0);
Furthermore, when I set an external url this works also fine. But when url is '#test' it doesn't.
I cannot find any articles for such an issue (maybe I have to spcial desires? O.o). Is there another way to setup internal links or did I missed any sign? I'm wondering why this works outside d3 but not within.
Thanks for help!
I solved this problem, building my own lightbox after Jim Nielsons tutorial (https://webdesign.tutsplus.com/articles/super-simple-lightbox-with-css-and-jquery--webdesign-3528). Watch out for the comments on recent versions of jquery.
The solution after having a working lightbox as desired is, to include the code into the d3 script somewhere (I put it to the end). Et voila!
It's not good to have blackboxes in your own code :)
Done.
nodeEnter.append("image")
.attr("xlink:href", function(d) { return d.icon; })
.on("click", function(d){
var link=document.createElement("a");
link.id="lightLink";
link.href= d.url;
link.rel="lightbox";
this.appendChild(link);
document.getElementById("lightLink").click();
})
.attr("x", "-12px")
.attr("y", "-12px")
.attr("width", "24px")
.attr("height", "24px");
I'm trying to create a Sankey diagram based off the example shown here: https://bost.ocks.org/mike/sankey/
While I am able to recreate the diagram, I'd like to write the tooltip text directly onto the links themselves (so they can be read as a static image). I've attempted to add a .append("text") call to the links just like I saw done for the nodes, but it doesn't seem to be working. Below is the code I added to the example above:
link.append("text")
.attr("x", 25)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); });
.attr("text-anchor", "start");
Yet this doesn't show display anything in the diagram.
UPDATE: I pasted Mike Bostock's code into a gist to make recreating the issue easier: http://bl.ocks.org/almsuarez/50eab68a645d7fc12183384000ea8c82
As was said in the comments you can't append text to SVG elements. So say at the moment you append your link to a container. For example :
var link = container.append('path')....//and so on
You have to do the same for text. So, for example :
var linkText = container.append('text')
You say you can't keep track of the x and y positions ?
Basically as your link is in between two points, you need to find the centre. Here is how I would do it :
.attr("x", function(d) { console.log(d); return d.source.x + (d.target.x - d.source.x) / 2; })
.attr("y", function(d) { return d.source.y + (d.target.y - d.source.y) / 2; })
So you get the source' x position then add half the difference of targetX - sourceX and do the same for y.
I have put this in a fiddle for you to see : https://jsfiddle.net/thatOneGuy/8ayq5nwa/2/
You can hover over the links to see the title that way you can check it's all correct :)
This question already has answers here:
clicking a node in d3 from a button outside the svg
(2 answers)
Closed 7 years ago.
I'm trying to link interactions on a bar chart with related data in a line chart using d3.js. I have it working now so hovering over a line highlights the associated bar, but am having trouble getting the reverse to work (i.e. hovering over a bar to highlight the related line).
I am relatively new at this, but I'm guessing it has something to do with how I'm trying to access the underlying data in the line chart to identify a match.
I've searched through stackoverflow answers and elsewhere but can't figure out what I am missing. Suggestions?
The code on bl.ocks.org
And here's the code snippet for the bar chart mouseover that's not working.
barchart.selectAll("rect")
.on("mouseover", function(d) {
activeState = d.state;
linechart.selectAll("line")
.classed("pathLight", function(d) {
if ( d.state == activeState) return true;
else return false;
});
console.log(activeState);
})
.on("mouseout", function() {
d3.selectAll("path")
.attr("class", "pathBase");
});
Edit:
Found another answer that it is helpful for questions like mine:
clicking a node in d3 from a button outside the svg
Hope below code will work for you.
Keep below code in mouseover of barChart
linechart.selectAll("g")
.each(function(d) {
if(d){
if ( d.state == activeState){
console.log(d3.select(this).select("path"));
d3.select(this).select("path").classed("pathLight", true);
return true;
}
else{
return false;
}
}
});
//Below Code is to show the highlighted region name, and don't forget to remove this in mouseout of barChart
var xPosition = xLabel + 8;
var yPosition = h/2;
linechart.append("text")
.attr("id", "hoverLabel")
.attr("x", xPosition)
.attr("y", yPosition)
.attr("text-anchor", "start")
.attr("font-family", "ff-nuvo-sc-web-pro-1,ff-nuvo-sc-web-pro-2, sans-serif")
.attr("font-size", "14px")
.text( activeState);
remove below code from that mouseouver
linechart.selectAll("line")
.classed("pathLight", function(d) {
if ( d.state == activeState) return true;
else return false;
});
If it's not working ask me, for more.
I am trying to add labels to the bilevel sunburst / partition shown here - http://bl.ocks.org/mbostock/5944371:
I have added labels to the first 2 levels and rotated them correctly. But I cant now add the new level's labels during a transition. To get started I have put ...
text = text.data(partition.nodes(root).slice(1), function(d) { return d.key; });
straight after the ...
path = path.data(partition.nodes(root).slice(1), function(d) { return d.key; });
line but it throws the following error ...
Uncaught TypeError: Cannot read property '__data__' of undefined
What am I doing wrong?
I used bilevel partition to add labels via a mouseover, and found that in this version (unlike the other sunburst partition), there are two different sections where "path" is defined and updated. The first is here:
var path = svg.selectAll("path")
and then again below the transition you highlighted in your code:
path.enter().append("path")
When i added my mouseover labels, I needed to reference my text function in both places or it wouldn't work after transition.
If you can post your code to JSFiddle or bl.ocks.org we can try to play with it and see, but that was where I got tripped up at first.
Hope that helps.
*NOTE: Comment didn't post:
I'm sorry I'm not able to help more, but I'm also a newbie at D3. Here's where I got:
copy and paste your svg.selectAll("text") snippet after the second "path.enter().append("path") snippet. This will cause it to appear on subsequent zooms as well.
Problems I see: there's no "g" element so you need separate transitions for text as well or they all pile up. Also, I can't understand why they're positioned at their original partition spot instead of where the arc exists now.
My approach was add labels on mouseOver. I've uploaded that here: https://github.com/johnnymcnugget/d3-bilevelLabels
In this, I'm calling the two functions in both sets of "path" snippets, and the transitions are handled within the single variable of "legend"
Another D3 newbie, but I managed to resolve this. Beggining from the original Bilevel Partition:
Add the text for the first time the chart is drawn:
var path = svg.selectAll("path")
.data(partition.nodes(root).slice(1))
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return d.fill; })
.each(function(d) { this._current = updateArc(d); })
.on("click", zoomIn);
var text = svg.selectAll("text")
.data(partition.nodes(root).slice(1))
.enter().append("text")
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) {return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.html(function(d) { return d.name; });
when zooming in or out you have to redraw labels, add the following in function zoom(root, p)
text.enter().append("text")
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) {return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d) { return d.name; });
text.exit().transition()
.style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
.remove();
text.transition()
.style("fill-opacity", 1)
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) {return radius / 3 * d.depth; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
Finally modify the computeTextRotation function as:
function computeTextRotation(d) {
return (d.x + (d.dx)/2) * 180 / Math.PI - 90;
}
Hope I haven't missed anything.
Indeed one modified line is missing in "2.". In function zoom(root, p), you should also add a line after path = path.data(partition ... .key; });:
path = path.data(partition.nodes(root).slice(1), function (d) {
return d.key;
});
text = text.data(partition.nodes(root).slice(1), function (d) {
return d.key;
});
I'm trying to generate a modal with information pulled from my json file when the text of a node is clicked on. I'm having trouble, so I'm just trying to generate an alert box at the moment. I think that I need to declare a variable for the node text, but I'm having trouble. Here is what I have right now:
node.append("svg:text")
.attr("text-anchor", "middle")
.attr("dy", "3.5em")
.text(function(d) { return d.name; })
var textNodes = node.append("svg:text").text()
.on("click", function(d, i) { alert("Hello world"); });
Or this, I don't see why this wouldn't work either.
node.append("svg:text")
.attr("text-anchor", "middle")
.attr("dy", "3.5em")
.text(function(d) { return d.name; })
.on("click", function(d) { alert("Hello world"); });
You are explicitly setting pointer-events: none for the text nodes (maybe a copy and paste error). Removing this line in the styles allows the click event to fire.
I managed to do do recogize a click on the label using something like this:
const text = this.g.selectAll('text')
.data(nodes)
.enter().append('text')
.attr('class', 'label')
.style('fill-opacity', function(d) { return d.parent === root ? 1 : 0; })
.style('display', function(d) { return d.parent === root ? 'inline' : 'none'; })
.style('pointer-events', 'auto')
.on("click", function(d) {
d3.event.stopPropagation();
console.log(d.data.name);
})
.text(function(d) { return d.data.name});
to expand on the topic, the following function
d3.event.stopPropagation();
will make the node not expand or collapse if you clicked on the text but the node will continue to expand and collapse if you clicked on the node circle next to the name. Pretty neat.