Fiddle
I am trying to insert basically a label to the center of a donut graph using D3. I was able to work with an existing code I found and manipulate it so all the slices of the graph mesh in the middle to appear like there is a label there, but I think it'd be a better idea just to figure out how to make it a more permanent home in the center. I am very new to JS and D3.
Any help is grealty appreciated.
Thank you
This is currently the code that is falsifying a label being in the center.
svg.selectAll("text").data(pie(data)).enter()
.append("text")
.attr("class","label1")
.attr("transform", function(d) {
var dist=radius-120;
var winkel=(d.startAngle+d.endAngle)/2;
var x=dist*Math.sin(winkel)-4;
var y=-dist*Math.cos(winkel)-4;
return "translate(" + x + "," + y + ")";
})
You can simplify your code quite a bit. Since you are already centering the pie chart:
var svg = d3.select("#svgContent").append("svg")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("transform","translate("+width/2+","+height/2+")");
You can just add the text as follows:
svg.append("text")
.attr("text-anchor", "middle")
.text("$" + totalValue);
Note that since you are only adding one <text>, you don't need to bind any data to it, and can pass .text(...) a value directly instead of a function.
Related
I am making a very basic force-directed graph with labels using the d3.js library. Here is part of my code:
var node = d3.select("#canvas").selectAll(".node")
.data(data_nodes)
.enter()
.append("g")
.attr("class","node");
var nodes = node.append("circle")
.style("fill","green")
.style("r",10);
var text = node.append("text")
.attr("dx", 20)
.attr("dy", ".35em")
.style("z-index",1)
.text(function(d){
return d.name;
});
This goes well at the beginning but due to the shifting location of nodes that occurs with the ticking, these text elements that are supposed to serve as labels get covered up by other nodes. I would like to know if there is a way to solve this problem.
I found this is a very helpful example to create tooltip on line charts. I am following this to work on a line chart now. The difference is the tooltip in my chart has a box/background to contain the value showing in the tooltip, so I add append('rect') with attr('fill', 'white').
mousePerLine.append('rect').
attr('width', '38px').
attr('height', '20px').
attr('class', 'tooltipRect').
style('fill', 'white').
attr('transform', 'translate(5,-13)');
To avoid overlapping of text as well as rect, I changed line 292 according to a post here How to select multiple selectors with selectAll?
.select("text")
.attr("transform", function(d,i) {
return "translate (10,"+(3+ypos[i].off)+")";
})
to
.selectAll(".tooltipRect, text")
.attr("transform", function(d,i) {
return "translate (10,"+(3+ypos[i].off)+")";
})
Here's a fiddle of the problem.
However, the tooltips are still overlapping. Can anyone help to figure out what is the cause of the problem? Thanks in advance!
The rects keep overlapping likely because the way you are selecting them.
Why not close the selectiona at the text (keep the text selection above as is) but a make a new selection for the rect:
d3.selectAll(".mouse-per-line")
.select("rect")
.attr("transform", function(d,i) {
return "translate (5,"+(ypos[i].off - 13)+")";
});
This works for me.
I did the translation based on your initial set up of the rect. I adjusted the offset on line 286 from 15 to 20 - it looks a bit better.
I am working on a D3 bar chart as per the mock-up below:
How do I make the bars to have random colors?
jsFiddle
Code:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
d3 has 4 built in color palettes.
Here's the link for the built in color palettes.
This tutorial is good on using specific colors for specific element.
Another tutorial by Jerome Cukier.
And the official site for d3 colors.
Fiddle - Note: In the fiddle I've passed the colors by adding colors in the data.
It can even be done by passing the colors from a different variables.
Hope this helps.
colors = d3.scale.category20()
rects = svg.selectAll('rect')
.data(data)
.enter()
.append("rect")
.attr("class","rect")
.....#other attributes
.attr("fill",function(d,i){return colors(i)})
this is old now, but this is a pretty good approach if you need N number of random colors
http://bl.ocks.org/jdarling/06019d16cb5fd6795edf
I can't seem to figure out how to update bar labels when I re-sort ranking data; essentially the label names will all remain the same, but their order will change.
Originally I have:
// University Names
labelsContainer = chart.append('g')
.attr('transform', 'translate(' + (uniLabel - barLabelPadding) + ',' + (gridLabelHeight + topMargin) + ')')
.selectAll('text')
.data(sortedData)
.enter()
.append('text')
.attr('x', xoffset)
.attr('y', yText)
.attr('stroke', 'none')
.attr('fill', 'black')
.attr("dy", ".35em") // vertical-align: middle
.attr('text-anchor', 'end')
.text(barLabel);
I sort the data differently, which I still call sortedData. The rectangles and rest of the graph updates successfully...save for the labels (which I have on only one rectangle bar column.)
In a new function I tried:
// update University Names (this overwrites, however... I want to select the existing label instead of appending text on top of the original text)
labelsContainer = chart.append('g')
.attr('transform', 'translate(' + (uniLabel - barLabelPadding) + ',' + (gridLabelHeight + topMargin) + ')')
.selectAll('text')
.data(sortedData)
.enter() // using transition ... or selecting the group ... does not allow the new text to appear!
.append('text')
.attr('x', xoffset)
.attr('y', yText)
.attr('stroke', 'none')
.attr('fill', 'black')
.attr("dy", ".35em") // vertical-align: middle
.attr('text-anchor', 'end')
.text(barLabel);
The issue here is that this just adds the new (correct) labels on top of the existing ones, instead of replacing them.
Using transition() I'm able to update the rest of the graph, but not the labels.
Any ideas of how to fix? Happy to provide more info/context if need be...
UPDATE 12/24: JSFiddle: http://jsfiddle.net/myhrvold/BVB2d/
JSFiddle showing transition, but with labels being overwritten: http://jsfiddle.net/myhrvold/BVB2d/embedded/result/
I know that by appending, I'm overwriting; but in attempting to replace, nothing happens and the original text remains, so the idea here is that I'm showing that I am at least generating the correct new labels and putting them in the right place...it's just that I'm not substituting them from my original labels...
You're completely repeating your code when you update your data -- including the chart.append('g') which creates a new group and then adds text labels to it. Because you've just created this as a new group, when you select inside it you can't select any of the labels you created the first time, so instead you end up creating all new labels.
To fix: first, as #musically_ut suggested, give each of your groups a unique class name. Then, in your update method select this group and the text elements it contains using chart.select(g.univerity-labels-container).selectAll("text"). However, you'll find you still have problems because you've got everything chained to an enter(); since you don't expect any new elements to be added when sorting, just take out that line. *
That should get it working, but the program is still painfully complex for what you're trying to do. For starters, all of this could work a lot better as an HTML table which would handle a lot of the layout for you. More importantly, you could save a lot of work if, instead of grouping elements by column you grouped them by row. That way, you would only have to join the data once, to the group, instead of doing separate data joins for each variable. If I have a chance in the next few days, I might try to write up a from-the-ground up explanations of how to approach this. In the meantime, google "d3 sortable table" for a couple examples, or look at the source code for this NYT graphic by Mike Bostock.
*For updating with an enter() step, I find most tutorials don't describe the update process very clearly, but I wrote up a step-by-step breakdown here yesterday.
After fiddling around for several hours now, I still cannot make labels work in my D3 Sunburst layout. Here's how it looks like:
http://codepen.io/anon/pen/BcqFu
I tried several approaches I could find online, here's a list of examples I tried with, unfortunately all failed for me:
[cannot post link list because of new users restriction]
and of course the coffee flavour wheel: http://www.jasondavies.com/coffee-wheel/
At the moment i fill the slices with a title tag, only to have it displayed when hovering over the element. For that I'm using this code:
vis.selectAll("path")
.append("title")
.text(function(d) { return d.Batch; });
Is there something similar I could use to show the Batch number in the slice?
--
More info: Jason Davies uses this code to select and add text nodes:
var text = vis.selectAll("text").data(nodes);
var textEnter = text.enter().append("text")
.style(...)
...
While the selection for his wheel gives back 97 results (equaling the amount of path tags) I only get one and therefore am only able to display one label (the one in the middle)
Needs some finessing but the essential piece to get you started is:
var labels = vis.selectAll("text.label")
.data(partition.nodes)
.enter().append("text")
.attr("class", "label")
.style("fill", "black")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.text(function(d, i) { return d.Batch;} );
You can see it here
The trick is that in addition to making sure you are attaching text nodes to the appropriate data you also have to tell them where to go (the transform attribute with the handy centroid function of the arc computer).
Note that I do not need vis.data([json]) because the svg element already has the data attached (when you append the paths), but I still have to associate the text selection with the nodes from each partition.
Also I class the text elements so that they will not get confused with any other text elements you may want to add in the future.