How to keep a crosshair out from the margins in d3.js? - javascript

I am trying to understand the logic behind this chart : http://bl.ocks.org/d3noob/6eb506b129f585ce5c8a made by D3noob.
I have tried to add a focus line from the focus circle to right before the margin.
I found a partial solution which is :
// append the x line_up
focus.append("line")
.attr("class", "x_track_line_up")
.style("stroke", "black")
.style("stroke", "3,3")
.style("opacity", 0.9)
.attr("y1", 0)
.attr("y2", height);
//call the x line
focus.select(".x_track_line_up")
.attr("transform",
"translate(" + x(d.date) + "," +
y(d.close) + ")")
.attr("y2", -height - y(d.close));
The only problem is that this added line is also drawn in the top margin.
I believe that the issue here is the last line of this portion of code but I am not sure how to fix it.

You don't need the translate. Just do:
focus.select(".x_track_line_up")
.attr("x1", x(d.date))
.attr("x2", x(d.date))
.attr("y2", y(d.close));
Here is the updated bl.ocks: http://bl.ocks.org/anonymous/dd1bb9adda42e4bc9768e9a35432197a

Related

D3 - Append SVG inside SVG

I have been trying to append a set of SVGs inside SVG. So, in inside SVG, I want to create a function to make plot. However, this doesn't work in the way I expected as the inside SVGs don't have the dimension according to my specification. So, I'd like to know what went wrong.
svg_g_g = svg_g.append("g")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + xScale(d.key) + "," + lift + ")"
})
.append("svg")
.attr("width", function(d) { return xScale(d.key) })
.attr("height", height)
.append("line")
.style("stroke", "black")
.attr("x1", function(d) { return xScale(d.key) })
.attr("y1", height-100)
.attr("x2", function(d) { return xScale(d.key) + 50 } )
.attr("y2", height-100);
This is the output.
While if I bind data to g (without appending svg), the result looks more promising.
svg_g_g = svg_g.append("g");
svg_g_g.selectAll("line")
.data(data)
.enter()
.append("line")
.style("stroke", "black")
.attr("x1", function(d) { return xScale(d.key) })
.attr("y1", height-100)
.attr("x2", function(d) { return xScale(d.key) + 50 } )
.attr("y2", height-100);
and this is the result. (notice: the lines were shown in this case)
Any help will be appreciated.
edit: what I intended to do was I wanted to create a box-plot, I used "iris" dataset here as I can compared it against other data visualisation libraries. The current state I tried to create a SVG with an equal size for each category which I would use to contain box-plot. In other words, after I can create internal SVGs successfully, I will call a function to make the plot from there. Kinda same idea Mike did here.

Add horizontal crosshair to d3.js chart

I am successful in getting crosshair in D3.js chart but issue is I am only getting vertical line, how do I add code for horizontal line as well?
Image of chart
JSFiddle code chart is not plotting in JSFiddle
Basically code to add vertical line crosshair is as below:-
var vertical = d3.select("body")
.append("div")
.attr("class", "remove")
.style("position", "absolute")
.style("z-index", "19")
.style("width", "1px")
.style("height", "450px")
.style("top", "47px")
.style("bottom", "1px")
.style("left", "8px")
.style("background", "#000");
Can I add horizontal crosshair as well same way?
P.S. also wanted a way to keep this vertical line only in chart area, but is coming in whole body, i.e. empty area next to chart in right and left.
Your approach is too complicated. This is simpler:
First, create a transparent rectangle to get the mouse movements:
var transpRect = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "white")
.attr("opacity", 0);
Then, create the lines:
var verticalLine = svg.append("line")
.attr("opacity", 0)
.attr("y1", 0)
.attr("y2", height)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("pointer-events", "none");
var horizontalLine = svg.append("line")
.attr("opacity", 0)
.attr("x1", 0)
.attr("x2", width)
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("pointer-events", "none");
Finally, position the lines on mousemove:
transpRect.on("mousemove", function(){
mouse = d3.mouse(this);
mousex = mouse[0];
mousey = mouse[1];
verticalLine.attr("x1", mousex).attr("x2", mousex).attr("opacity", 1);
horizontalLine.attr("y1", mousey).attr("y2", mousey).attr("opacity", 1)
}).on("mouseout", function(){
verticalLine.attr("opacity", 0);
horizontalLine.attr("opacity", 0);
});
Here is your fiddle: https://jsfiddle.net/xrf1ro1a/
PS: to avoid killing your tooltips, I put the mousemove both on the rectangle and on the svg as well, which has the undesirable effect of making the lines going outside the chart area. To avoid this, set pointer-events = none to the elements outside the chart area.

Major and minor ticks with different style, whole page covered D3?

I want to draw an axis with major and minor ticks that cover my whole page styled differently. I followed structure of this example, but I can't get it to work make different between major and minor ticks lines. Here is a picture represent what I'm looking for:
This is my code:
// Define identity (1:1) scales
var x = d3.scale.identity().domain([0, 400]);
var y = d3.scale.identity().domain([0, 300]);
// Define container
var chart = d3.select("body")
.append("svg")
.attr("class", "chart")
.attr("width", 500)
.attr("height", 400)
.append("g")
.attr("transform", "translate(40,20)");
// Draw X-axis grid lines
chart.selectAll("line.x")
.data(x.ticks(50))
.enter().append("line")
.attr("class", "minor")
.attr("x1", x)
.attr("x2", x)
.attr("y1", 0)
.attr("y2", 300)
.style("stroke", "#ccc");
// Draw Y-axis grid lines
chart.selectAll("line.y")
.data(y.ticks(50))
.enter().append("line")
.attr("class", "minor")
.attr("x1", 0)
.attr("x2", 400)
.attr("y1", y)
.attr("y2", y)
.style("stroke", "#ccc");
// Define stock x and y axis
var xAxis = d3.svg.axis().scale(x).orient('top');
var yAxis = d3.svg.axis().scale(y).orient('left');
chart.append('g')
.attr("class", "axis")
.call(xAxis);
chart.append('g')
.attr("class", "axis")
.call(yAxis);
In this case I don't know if I missed some thing?
Complete jsfiddle here.
I have made the change to your fiddle, please see here http://jsfiddle.net/17ubhxqw/1/
All you have to do is figure out at which interval you want the darker line and return a different color in your x and y grid declarations:
// Draw X-axis grid lines
chart.selectAll("line.x")
.data(x.ticks(50))
.enter().append("line")
.attr("class", "minor")
.attr("x1", x)
.attr("x2", x)
.attr("y1", 0)
.attr("y2", 300)
.style("stroke", function(d,i){
if (d%50 !== 0) {
return "#ccc";
}else {
return "#666";
}
});
// Draw Y-axis grid lines
chart.selectAll("line.y")
.data(y.ticks(50))
.enter().append("line")
.attr("class", "minor")
.attr("x1", 0)
.attr("x2", 400)
.attr("y1", y)
.attr("y2", y)
.style("stroke", function(d,i){
if (d%50 !== 0) {
return "#ccc";
}else {
return "#666";
}
});
Hope this helps.
The new way to do this is to have several axes, one for the major ticks and another one for the minor ones. You would select the ticks that also appear on the major axis for the minor one and remove them.
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis().scale(x).ticks(20).tickSize(-height))
.selectAll(".tick")
.data(x.ticks(10), function(d) { return d; })
.exit()
.classed("minor", true);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.svg.axis().scale(x).ticks(10));
More information here.

d3.js - transition starting only without svg title, not with it

I found no direct answer for this, please forgive me if this has been covered differently in another topic.
I draw a bar chart which appears with a transition. I also want to add a tooltip which displays the value of data on mousehover.
Using the code below I have managed to obtain either the tooltip or the transition, but never the 2 together, which is my objective.
chart.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", function(d) {return colorscale(colorize(d.age));})
.attr("x", function(d) {return xscale(d.name);})
.attr("y", height - 3)
.attr("height", 3)
.attr("width", xscale.rangeBand())
.append("title")
.text(function(d){return d.age;})
.transition()
.duration(1600)
.attr("y", function (d) {return yscale(d.age);})
.attr("height", function (d) {return height - yscale(d.age);}) ;
If I remove
.append("title")
.text(function(d){return d.age;})
Then my transition works fine. If I but those 2 lines back I can see my tooltip but I lose my transition.
Any suggestion would be appreciated!
You can see the result here
Thank you
You need to add the transition to the rect and not the title element:
var sel = chart.selectAll(".bar")
.data(data)
.enter()
.append("rect");
sel.append("title")
.text(function(d){return d.age;});
sel.transition()
.duration(1600)
.attr("y", function (d) {return yscale(d.age);})
.attr("height", function (d) {return height - yscale(d.age);}) ;

Floating line disturbs the mousemove function

My quest for d3.js wisdom continues!
This time, I have added a guide line which is hovering in a vertical direction as a tool close to the pointer. The problem is that the line disturbs the mousemove functions since it adds an extra layer on top of the rest of the graph, which makes the the code run the mouseout event on sudden pointer movements. Is there a solution for this?
I have implemented the function in the following manner:
svg.on("mousemove", function(d) {
svg.select(".guideline").remove();
//svg.select(".valuelabel").remove();
svg.append("line")
.attr("class", "guideline")
.attr("x1", d3.mouse(this)[0]-3)
.attr("x2", d3.mouse(this)[0]-3)
.attr("y1", margin[0])
.attr("y2", height+margin[0])
.attr("opacity", originOpacity)
.attr("stroke", "#333");
});
And as an example of an event it is disturbing:
//Highlight each stack when hovering, and calculate y value for legend
stacks.on("mousemove", function(d) {
svg.select(".label").remove();
//Calculate the closest index when hovering
var perValue = width / data[0].data.length;
var index = Math.ceil((d3.mouse(this)[0]-margin[3]) / perValue - 0.5);
chart.selectAll(".valuelabel").each(function(data) {
if (data.name == d.name) {
d3.select(this).text(Math.round(data.data[index].y) + "%");
}
});
d3.select(this).attr("opacity", "1");
svg.selectAll("." + d3.select(this).attr("class")).attr("opacity", "1");
svg.append("text")
.attr("class", "label")
.attr("width", "100px")
.attr("height", "20px")
.attr("x", d3.mouse(this)[0] + 40)
.attr("y", d3.mouse(this)[1] - 5)
.text(d.group + ": " + d.name);
});
stacks.on("mouseout", function(d) {
groups.selectAll("." + d.name).text(d.name);
svg.select(".label").remove();
svg.selectAll("." + d3.select(this).attr("class")).attr("opacity", originOpacity);
});
Looks like you want pointer-events none on the guide line.

Categories

Resources