Adding text to a rectangle - javascript

Is it possible to add a piece of text in the centre of multiple rectangles in a D3 treemap chart? So what i'm after is something like this:
As you can see by the picture, I want to have text appear once in the middle of each “section” (different colours) on the chart. Is it possible to do this with D3? If so how would I achieve it.
Currently I've managed to have it appear on each individual rectangle, like so:
cell.append("svg:text")
.attr("x", function(d) { return d.dx / 2; })
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.text("test")
.style("opacity", function(d) { console.log(this.getComputedTextLength());d.w = this.getComputedTextLength(); return d.dx > d.w ? 1 : 0; });
Full code is here: http://jsfiddle.net/noobiecode/9ev9qjt3/74/
Any help will be appreciated.

For appending these texts, we first need to find the corresponding data. Right now, nodes have data regarding all the different depths (parents and children), but for these texts we only need the data for the second depth (depth == 2).
So, we first get the data:
var parents = treemap.nodes(root)
.filter(function(d) { return d.depth == 2 });
It gives us an array with three objects, so we are in the right way. This array (parents) have all we need to position the texts (x, y, dx, dy, name).
Then, we bind this data to the texts:
var parentsText = svg.selectAll(".parentsText")
.data(parents)
.enter()
.append("text");
After that, we append the texts:
parentsText.attr("text-anchor", "middle")
.attr("dominant-baseline", "central")
.attr("x", function(d){ return d.x + d.dx/2})
.attr("y", function(d){ return d.y + d.dy/2})
.text(function(d){ return d.name})
.attr("class", "parentText");
And this is the resulting fiddle: http://jsfiddle.net/gerardofurtado/9ev9qjt3/94/
You can also have the texts for each individual rectangle and for the group (but, in that case, you may want to move away some overlapping texts): http://jsfiddle.net/gerardofurtado/9ev9qjt3/95/

Related

Moving and Changing Text Labels while Sorting Bar Chart

I'm trying to have my text labels move and change while sorting. I have a multidimensional array including bar height, width, and opacity. A kind contributor helped me out yesterday with getting the bars sorted correctly, but I'd also like to get the text labels to move and change at the top of each bar as the bar sorts and moves.
var s = -1;
svg.on("click", function() {
s = (s + 1) % 3;
var xPosition = parseFloat(d3.select(this).attr("x")) xScale.bandwidth() / 2;
var yPosition = parseFloat(d3.select(this).attr("y")) + 14;
svg.selectAll("rect")
.sort(function(a, b) {
return d3.ascending(a[s], b[s]);
})
.transition()
.delay(function(d, i) {
return i * 65;
})
.duration(250)
.attr("x", function(d, i) {
return xScale(i);
});
svg.selectAll("text")
.append("text")
.text(function(d) {
return d[s];
})
.attr("text-anchor", "left")
.attr("x", xPosition)
.attr("y", yPosition)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "red");
});
As you can see, I'm quite lost as to where to go moving forward. I took the xPosition and yPosition variable idea from a textbook but it doesn't seem to change anything. Also, the text labels never change while I sort through height, width, and opacity. Thanks for the help.
When you do this...
svg.selectAll("text")
.append("text")
//etc...
... you are appending <text> elements inside <text> elements, which makes no sense.
Instead of that, assuming that your texts were previously created, just select them and sort them accordingly:
svg.selectAll("text")
.text(function(d) {
return d[s];
})
.attr("x", xPosition)
.attr("y", yPosition);

D3 bar chart bar text labels not visible properly

I have a stacked bar chart in d3.js
For every stacked bar i have corresponding text value showing near stack itself.
problem is, some text values displaying are hidden behind bars, where as some are visible over bars. I want all text to visible over my bars. my code looks like,
bar.append("text")
.attr("x", function (d) { return x(d.x); })
.attr("y", function (d) { return y(d.y0 + d.y); })
.attr("dy", ".35em")
.attr('style', 'font-size:13px')
.text(function (d) { if (d.y != 0) { return "$" + d.y; } })
.style('fill', 'black');
Basically the issue related to z-index. But there is no z-index for SVG, so it can be fixed by reordering elements. Details here With JavaScript, can I change the Z index/layer of an SVG <g> element?
The simplest and fastest way:
To add .reverse() to the dataset.
// Create groups for each series, rects for each segment
var groups = svg.selectAll("g.cost")
.data(dataset.reverse())
.enter().append("g")
.attr("class", "cost")
.style("fill", function(d, i) { return colors[i]; });
The better way
To add different containers for bars and labels and put them in the right order in the DOM.
Try it http://jsfiddle.net/kashesandr/z90aywdj/

Adding 'measures' label to D3 bullet chart

I'm working with D3's bullet chart and am trying to figure out how to display the actual measures number just to the right of the measures rectangle. Since I want to do this for every bullet chart, I figure it'd be best to do it right in the bullet.js code. I'm rather new to D3 so any help would be much appreciated! Here is the link to Mike Bostock's bullet chart example with the bullet.js included at the bottom.
It looks like the measures code is handled in this snippet:
// Update the measure rects.
var measure = g.selectAll("rect.measure")
.data(measurez);
measure.enter().append("rect")
.attr("class", function (d, i) { return "measure s" + i; })
.attr("width", w0)
.attr("height", height / 3)
.attr("x", reverse ? x0 : 0)
.attr("y", height / 3)
.transition()
.duration(duration)
.attr("width", w1)
.attr("x", reverse ? x1 : 0);
measure.transition()
.duration(duration)
.attr("width", w1)
.attr("height", height / 3)
.attr("x", reverse ? x1 : 0)
.attr("y", height / 3);
I thought I could just add something like this after the rect is appended but I've had no such luck.
measure.enter().append("text")
.attr("dy", "1em")
.text(function (d) { return d.measurez; })
.attr("x", reverse ? x0 : 0)
.attr("y", height / 3)
.transition()
.duration(duration)
.attr("width", w1)
.attr("x", reverse ? x1 : 0);
Thank you in advance for your consideration!
You almost got it -- there're just two small things to consider. First, you can't call .enter() twice. Once the enter selection has been operated on, it's merged into the update selection and your second selection will be empty. This is fixed easily by saving the selection in a variable, but in this case I would recommend making a separate selection for the text labels.
var measureLabel = g.selectAll("text.measure")
.data(measurez);
measureLabel.enter()....;
Second, to position the text to the right of the rect, you need to take not only the position, but also the width into account when computing the position of the text element. Also, you can omit a few elements that are not relevant to text elements.
measureLabel.enter()
.append("text")
.attr("class", function(d, i) { return "measure s" + i; })
.attr("dy", "1em")
.attr("dx", "1em")
.text(String)
.attr("x", reverse ? function(d) { return w0(d) + x0(d); } : w0)
.attr("y", height / 3);
measureLabel.transition()
.duration(duration)
.attr("x", reverse ? function(d) { return w1(d) + x1(d); } : w1);
Complete example here.

Looking for a way to display labels on sunburst chart (could not find a working example)

Thanks to someone's help (Brandon), I've been able to add tooltips to the sunburst charts.
I am still looking for a way to display the label of a path on the sunburst chart (and then have the dual mode tooltip + text).
The example that I'd like to improve is provided on jsfiddle.net/trakkasure/UPqX5/
I am looking for the code to add to the following code section:
path = svg.data([getData()]).selectAll("path")
.data(partition.nodes)
.enter().append("svg:path")
.attr("d", arc)
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", magnify)
.on("mouseover", function(d) {
tooltip.show([d3.event.clientX,d3.event.clientY],'<div>'+d.name+'</div> <div>'+d.value+'</div>')
})
.on('mouseout',function(){
tooltip.cleanup()
})
.each(stash);
And I'd like to see the labels as shown on the example is provided on http://bl.ocks.org/910126. I can not get that example to work for me (I'm still new to D3)
I do recognize that there might be too much text on that chart, but in my scenario it is not a problem.
Can someone help me understand how to display all these labels on the chart?
Simply append svg:text elements to the canvas:
path.append("svg:text")
.attr("transform", function(d) { return "rotate(" + (d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180 + ")"; })
.attr("x", function(d) { return d.y; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d) { return d.name; });
However, in my edit, this will break your magnify function, so i create an svg group to hold together each pair of path and text. In my opinion, elements are better organized this way, easier to query in the future.
Note that you need to modify your magnify function to also animate the text, as for now it only animate the path and leave the text at their original position.
group = svg.data([getData()]).selectAll("path")
.data(partition.nodes)
.enter().append('svg:g');
//path variable is required by magnify function
path = group.append("svg:path")
.attr("d", arc)
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", magnify)
.on("mouseover", function(d) {
tooltip.show([d3.event.clientX,d3.event.clientY],'<div>'+d.name+'</div><div>'+d.value+'</div>')
})
.on('mouseout',function(){
tooltip.cleanup()
})
.each(stash);
// you may need to assign the result to a variable,
// for example to animate the text in your magnify function,
// as shown in the path variable above
group.append("svg:text")
.attr("transform", function(d) { return "rotate(" + (d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180 + ")"; })
.attr("x", function(d) { return d.y; })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d) { return d.name; });
Code was taken from your given example, however
I edited the x attribute into .attr("x", function(d) { return d.y; }) to properly position the text based on your data structure (the example uses Math.sqrt(d.y)). I also modify the text function to return d.name
here is the jsFiddle

How to set the label for each vertical axis in a parallel coordinates visualization?

I'm new to d3.js (and stackoverflow) and I'm currently working through the parallel coordinates example. I'm currently using a 2d array named 'row' for the data. Above each vertical axis is the label '0' or '1' or '2', etc. However, I'd like each vertical axis to be labeled with the text in row[0][i]. I believe the numbers 0,1,2 are coming from the datum. Any suggestions on how I may use the labels in row[0][i] instead? I suspect I'm doing something wrong that's pretty basic. Here's the relevant code. Thanks !
// Extract the list of expressions and create a scale for each.
x.domain(dimensions = d3.keys(row[0]).filter(function (d, i) {
return row[0][i] != "name" &&
(y[d] = d3.scale.linear()
.domain(d3.extent(row, function (p) { return +p[d]; }))
.range([height, 0]));
}));
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function (d) { return "translate(" + x(d) + ")"; });
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function (d) { d3.select(this).call(axis.scale(y[d])); })
.append("text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String);//.text(String)
If you only have a controlled set of Axis (like three axis), you may just want to set them up, individually, as follows...
svg.append("text").attr("class","First_Axis")
.text("0")
.attr("x", first_x_coordinate)
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
svg.append("text").attr("class","Second_Axis")
.text("1")
.attr("x", first_x_coordinate + controlled_offset)
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
svg.append("text").attr("class","Third_Axis")
.text("2")
.attr("x", first_x_coordinate + controlled_offset*2)
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
However, if you have dynamically placed axis that rely on the data, you may want to place the axis info using a function that holds the y coordinate constant while determining the x coordinate based on a fixed "offset" (i.e. data driven axis placement). For example...
svg.append("text")
.attr("class",function(d, i) {return "Axis_" + i; })
.text(function(d,i) {return i; })
.attr("x", function(d, i) { return (x_root_coordinate + x_offset_value*i); })
.attr("y", constant_y_coordinate)
.attr("text-anchor","middle");
I hope this helps.
Frank

Categories