I would like to make the labelling of the x axis clickable so that the text includes links.
Here is a fiddle of my code so far: http://jsfiddle.net/3gLfb401/
The x axis labelling consists of the date and a build number. The build number should be a link.
In this example it should be enough if it links to google.com or something.
I already searched in the internet and found some things, that might do it but I don't know how to place it.
I thought something like this could work:
x.html(d3.time.format("%Y-%m-%d")(d.date) + '' + "#" + d.buildNb + "")
This is the method which forms at the moment the text of the labelling:
function formatDataToTick(d) {
return d3.time.format("%Y-%m-%d")(d.date) + " #" + d.buildNb;
}
Try this.
var xLabels = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-65)"
});
var insertTspans = function(a) {
var b = a.split(" ");
var textNode = d3.select(this);
textNode.text("");
textNode.append("tspan").text(b[0]);
var link = textNode.append("tspan").text(b[1]);
link.style("cursor", "pointer")
.style("fill","blue")
.style("text-decoration","underline")
.on("click", function(a) {
document.location.href = "http://www.example.com/" + a;
});
};
xLabels.each(insertTspans);
Related
I'm using d3 v4. I want to display some text corresponding to where folks are mousing-over my line chart and I would like to have a background box on this text. So I'm trying this
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
var rect = focus.append("rect")
.attr("x", 9)
.attr("dy", ".35em")
.attr("width", 50)
.attr("height", 50)
.attr("fill", "yellow");
...
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.index_date) + "," + y(d.value) + ")");
rect.select("text").text(formatCurrency(d.value));
}
but what is happening instead is there is just a rectangle without any text floating over my mouseover point as you can see here -- https://jsfiddle.net/xx77tzn3/9/. How do I adjust what I have to include the text and a background box?
<svg>'s (rather unintuitively) don't allow you to append text elements to rect elements. Uncomment
//var text = focus.append("text")
and comment out:
var text = rect.append("text")
Then it the mouse function, change line 113 to this:
focus.select("text").text(formatCurrency(d.value));
Then it's just a matter of formatting the text on that <g>.
EDIT: in order to format the text to be on the rect, you need to make the coordinates of the text relative to the <g>, not the rect. I.e.:
var text = focus.append("text")
//var text = rect.append("text")
.attr("x", 10)
.attr("y", 10);
Now the text is there, and on top of the rectangle.
Updated js.fiddle
I took this redraw function from http://bl.ocks.org/stepheneb/1182434 and I would like to adapt it.
How to remove the comma separator for the groups of thousands? in the code console.log(self.x.ticks(10).map(self.x.tickFormat(2, ".1"))) works and yields numbers in this format: [ "0", "1000", "2000",.. ], which is what I want. When I put it in .data() as in the code I get [ "0", "1,000", "2,000",.. ].
I am using a zoom so i cannot hardcode the labels.
The main part of the code should be:
fx = self.x.tickFormat(10),
//fx = self.x.tickFormat(d3.format("f2")), //does not work
fy = self.y.tickFormat(10);
// Regenerate x-ticks…
var gx = self.vis.selectAll("g.x")
.data(self.x.ticks(10).map(self.x.tickFormat(2, ".1")), String)
.attr("transform", tx);
console.log(self.x.ticks(10).map(self.x.tickFormat(2, ".1")))
gx.select("text")
.text(fx);
The whole redraw function:
SimpSimpleGraph.prototype.redraw = function() {
var self = this;
return function() {
var tx = function(d) {
return "translate(" + self.x(d) + ",0)";
},
ty = function(d) {
return "translate(0," + self.y(d) + ")";
},
stroke = function(d) {
return d ? "#ccc" : "#666";
},
fx = self.x.tickFormat(10),
//fx = self.x.tickFormat(d3.format("f2")), //does not work
fy = self.y.tickFormat(10);
// Regenerate x-ticks…
var gx = self.vis.selectAll("g.x")
.data(self.x.ticks(10).map(self.x.tickFormat(2, ".1")), String)
.attr("transform", tx);
console.log(self.x.ticks(10).map(self.x.tickFormat(2, ".1")))
gx.select("text")
.text(fx);
var gxe = gx.enter().insert("g", "a")
.attr("class", "x")
.attr("transform", tx);
gxe.append("line")
.attr("stroke", stroke)
.attr("y1", 0)
.attr("y2", self.height);
gxe.append("text")
.attr("class", "axis label")
.attr("y", self.height)
.attr("dy", "1em")
.attr("text-anchor", "middle")
.text(fx)
.style("cursor", "ew-resize")
.on("mouseover", function(d) { d3.select(this).style("font-weight", "bold");})
.on("mouseout", function(d) { d3.select(this).style("font-weight", "normal");})
.on("mousedown.drag", self.xaxis_drag())
.on("touchstart.drag", self.xaxis_drag());
gx.exit().remove();
// Regenerate y-ticks…
var gy = self.vis.selectAll("g.y")
.data(self.y.ticks(10), String)
.attr("transform", ty);
gy.select("text")
.text(fy);
var gye = gy.enter().insert("g", "a")
.attr("class", "y")
.attr("transform", ty)
.attr("background-fill", "#FFEEB6");
gye.append("line")
.attr("stroke", stroke)
.attr("x1", 0)
.attr("x2", self.width);
gye.append("text")
.attr("class", "axis label")
.attr("x", -3)
.attr("dy", ".35em")
.attr("text-anchor", "end")
.text(fy)
.style("cursor", "ns-resize")
.on("mouseover", function(d) { d3.select(this).style("font-weight", "bold");})
.on("mouseout", function(d) { d3.select(this).style("font-weight", "normal");})
.on("mousedown.drag", self.yaxis_drag())
.on("touchstart.drag", self.yaxis_drag());
gy.exit().remove();
//This zoom is call after the plot has loaded
self.plot.call(d3.behavior.zoom().x(self.x).y(self.y).on("zoom", self.redraw()));
self.update();
}
}
As far as changing the way d3 outputs numbers, I haven't the foggiest clue. But you can alter these values afterwards using string prototype .replace.
Example
var someString = 'The catcher in the rye';
someString.replace('catcher','captcha'); //"The captcha in the rye"
And here is how you apply this to an array.
http://jsfiddle.net/sq2johrv/1/
Use .ticks(myTicksCount, '.f') instead of .ticks(myTicksCount) to remove the comma to separate groups of thousands.
For details, see the docs on
https://github.com/d3/d3-axis/blob/master/README.md#axis_ticks
https://github.com/d3/d3-axis/blob/master/README.md#axis_tickFormat
https://github.com/d3/d3-format
You can test the format specifiers (including your own) on http://bl.ocks.org/zanarmstrong/05c1e95bf7aa16c4768e
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click)
.on("mouseover",function (d){
if(d.name=="Purchased"){
jQuery.getJSON("RequestHandler?usercommand=jsoncompany&subcommand=propCount&useraction=d3Tree_frm&mgmtId="+d.id+"&type="+d.name, function(json){
var count=JSON.stringify(json.prop_purchased_count);
result="Purchased Property :"+count;
});
}
var g = d3.select(this);
var info = g.append("text")
.classed('info', true)
.attr('x', 30)
.attr('y', 30)
.text(result); //result="Amount":200\n"Amount":300\n"Amount":400
})
.on("mouseout", function() {
d3.select(this).select('text.info').remove();
});
//result="Amount":200\n"Amount":300\n"Amount":400
i want to display tooltip such that after \n it appears in a new line within that tooltip.
How to achieve it ?
Thanks in advance
I can see result being set in the code you posted, however what we cannot see is where result is being set to get the content you are 'saying' it contains. That way we could help you interpret the application of these proven recommendations a lot better. But in anycase, have a look at these resources to help you in your quest.
http://bl.ocks.org/mbostock/7555321
How to dynamically display a multiline text in D3.js?
In the else part add "Amount:"+ count + "\n" while you are concatenating the newline
I have a D3 bar chart with the associated data points displayed as text on top of each bar. I want to display the text only on mouseover and also make the bar have a different fill color. So, essentially, on mouseover, the bar has to be styled to have a different fill color and the text opacity should go to 1 (from '0').
I am having trouble effecting two separate events on mouseover. I have given an index_value attribute to both elements in order to use d3.select(this).attr(index_value). But my mouseover function does not work. I have no idea why. Here's my relevant code section.
The bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr('data-value', function(d){return d[region]})
.attr("x", function(d) { return x(d.year); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d[region]); })
.attr("height", function(d) { return height - y(d[region]); })
.attr("fill", color)
.attr("index_year", function(d, i) { return "index-" + d.year; })
.attr("class", function(d){return "bar " + "bar-index-" + d.year;})
.attr("color_value", color)
.on('mouseover', synchronizedMouseOver)
.on("mouseout", synchronizedMouseOut);
The text overlay
svg.selectAll(".bartext")
.data(data)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d,i) {
return x(d.year)+x.rangeBand()/2;
})
.attr("y", function(d,i) {
return height - (height - y(d[region])) - yTextPadding;
})
.text(function(d){
return d3.format(prefix)(d3.round(d[region]));
})
.attr("index_year", function(d, i) { return "index-" + d.year; })
.attr("class", function(d){return "bartext " + "label-index-" + d.year;})
.on("mouseover", synchronizedMouseOver)
.on("mouseout", synchronizedMouseOut);
And the mouseover function
var synchronizedMouseOver = function() {
var bar = d3.select(this);
console.log(bar);
var indexValue = bar.attr("index_year");
var barSelector = "." + "bar " + "bar-" + indexValue;
var selectedBar = d3.selectAll(barSelector);
selectedBar.style("fill", "#f7fcb9");
var labelSelector = "." + "bartext " + "label-" + indexValue;
var selectedLabel = d3.selectAll(labelSelector);
selectedLabel.style("opacity", "1");
};
This can be achieved by simplifying your listeners. You don't need to add listeners to both rects and text. Just add them to the rects. Here are the simplified listeners:
function synchronizedMouseOver(d) {
var bar = d3.select(this)
.style("fill","red");
var text = d3.select(".label-index-" + d.year)
.style("opacity","1");
};
function synchronizedMouseOut(d) {
var bar = d3.select(this)
.style("fill",color);
var text = d3.select(".label-index-" + d.year)
.style("opacity","0");
};
Your two friends here are this and d, the DOM element for the rect and its data node, respectively.
Here is a FIDDLE with the behavior that you desire.
See: http://jsfiddle.net/bQHjj/
Following the green line, the circles should be vertically aligned with my x axis, but all of them are moved a few pixels to the right.
The X axis isn't showing it's first tick, which should be 01.05.2013.
My x axis settings:
var xAxis = d3.svg.axis().scale(x).ticks(d3.time.days, 1).tickFormat(d3.time.format("%d.%m.%Y"));
graph.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function (d) {
return "rotate(-65)"
});
Can anybody tell me what's wrong?
Your date parsing function is not correct, it seems to mess up time zones, since new Date(string) apparently assumes UTC.
This will work:
var format = d3.time.format("%Y-%m-%d");
function getDate(d) {
return format.parse(d.date);
}
cf the updated fiddle.