d3 on brush triangle symbols disappears - d3.js

The grey strip in the lower area allows the user to spread the data across x axis .fiddle Everything is resizing apart from the triangle symbols which are generated initially but disappear as soon as I redraw using the brush (ps: this happen only when i run the code from the same code from the browser and not jsfiddle!)
My axis increases in length but 0min is repeated 3 to 4 times instead of showing 0.1 0.2 0.3 etc
milestone_marks.selectAll(".milestone_markers")
.data(milestones)
.enter().append("path")
.attr("d", d3.svg.symbol().type('triangle-down'))
.attr('class', 'milestone_markers')
.attr("transform", function (d) {
return "translate(" + x__axis(d.processing_time) + "," + -7 + ")";})
and in the brushed function I write the following:
d3.select('.milestone_marks').selectAll('path').data(milestones).attr("d", d3.svg.symbol().type('triangle-down')).attr("transform", function (d) {
return "translate(" + x__axis(d.processing_time) + "," + -7 + ")";})
Any inputs will be appreciated.

Related

Force layout node rotation

Ok, first - look at this fiddle.
You should see shapes rotating back and forth like crazy.
This is what is going on:
force.on("tick", function(e) {
vis.selectAll("path")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
// this is the thing
+"rotate(" + Math.random() * 50 + ")";
});
});
On every tick I'm changing the transform: rotate() to Math.random() * 50 in this case.
Now what I want is a smooth rotation. Not this jerky stuff.
See this to better understand what I mean. Imagine the height as the rotation. The gray box represents what I have now, the blue - what I want.
I tried applying 'transition: all 1s ease' CSS to that element, but it just ignores it, I'm obviously doing it wrong.
So how do I make this infinite back and forth rotation smooth as if I was using CSS3 transitions?
Every tick you are randomly setting the rotation to something between 0 and 50 degrees of rotation. You need to maintain the current rotation, calculate an offset, and then set the rotation to the current + offset.
Here's an updated tick function:
force.on("tick", function(e) {
vis.selectAll("path")
.attr("transform", function(d) {
if(!d.rotate) {
d.rotate = Math.random() * 50;
} else {
d.rotate = d.rotate + 1;
}
return "translate(" + d.x + "," + d.y + ")"
+"rotate(" + d.rotate + ")";
});
});
Here's the updated working example: https://jsfiddle.net/1aLc7x4j/

How to make d3 milestone Shape

I'm trying to align a down triangle with a rectangle to make a group that can be used to represent a milestone. Any ideas why this code only shows 2 triangles and how to move them to centre bottom of rectangle or any other methods to achieve the same goal?
http://jsfiddle.net/sjp700/Pej4M/
tri.enter().append("path")
.attr("d", d3.svg.symbol().type("triangle-down"))
.style("fill", "black")
.attr("transform", function (d) { return "translate(" + xRange(d.start) + "," + yRange(d.Duration) + ")"; });
As pointed out in the comments, the reason you're seeing only two rectangles is that some of the data is bound to existing paths. To fix, assign a special class to the symbols that you can select by:
var tri = vis.selectAll("path.tri").data(datar);
For the positioning of the symbols, you need to use the same values you use for the rectangles. The y position needs to be offset by a constant so that the symbols appear at the bottom and the x position by half the duration -- I'm guessing that this is what you really want to show as you're currrently hardcoding everything to length 50.
.attr("transform", function (d) { return "translate(" + (xRange(d.start) + 25) + "," + (yRange(d.start) + 15) + ")"; });
Complete demo here.

How to produce axes that do not intersect at (0, 0)?

I would like to generate axes that do not intersect at (0, 0) (and also do not necessarily coincide with the edges of a plot), as shown in the example below.
How can I do this with d3?
You will first need to figure out where you want to display the axis. If they are fixed to canvas, take ratios of width and height.
Here's an example that I made:
http://vida.io/documents/zB4P4fjHz79um3qzX
x-axis is at to 2/3 of height:
.attr("transform", "translate(0," + height * 2 / 3 + ")")
And y-axis is at 1/3 of width:
.attr("transform", "translate(" + width / 3 + ", 0)")
If you need the axis relative to range of values, calculate them based on range. For example:
var domain = d3.extent(data, function(d) { return d.y_axis; })
var y_axis_pos = width * (y_axis_value - domain[1]) / (domain[0] - domain[1]);
// svg code...
.attr("transform", "translate(" + y_axis_pos + ", 0)")
From the D3.js API documentation:
to change the position of the axis with respect to the plot, specify a transform attribute on the containing g element.

Using the zoom and pan functionality of d3

I'm trying to use the pan/zoom ability of d3 to draw boxes on the screen so that when you click on a box a new box appears and shifts the rest of the boxes to the right so that the new box is on the center of the canvas. The panning would allow me to scroll through all the boxes I've drawn.
Here is my jsfiddle: http://jsfiddle.net/uUTBE/1/
And here is my code for initializing the zoom/pan:
svg.call(d3.behavior.zoom().on("zoom", redraw));
function redraw() {
d3.select(".canvas").attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
And here is my code for drawing the boxes:
function drawBox(x, y) {
var boxGroup = canvas.append("g");
boxGroup.append("rect")
.attr("x", x)
.attr("y", y)
.attr("height", 100)
.attr("width", 100)
.attr("fill", function () {
var i = Math.floor(Math.random() * 4);
if (i === 1) return "red";
else if (i === 2) return "blue";
else if (i === 3) return "yellow";
else return "green";
})
.on("click", function () {
counter++;
d3.select(".canvas")
.transition()
.duration(1000)
.attr('transform', "translate(300,0)");
drawBox(x - counter * 120, y);
});
}
I have multiple problems with this fiddle, but two of my main concerns is:
1) How do I make it so that when I click on a new box a second time the boxes move accordingly (i.e. when I click on the box initially the old box shifts to the right and a new box appears, but when I click on the new box, the older boxes doesnn't shift to the right).
2)Why is it that when I click on the new box, the newer box has a big spacing between it? (only happens after trying to put 3 boxes on the screen).
Thanks any hints are appreciated!
I think there's some confusion here around transform. The transform attribute is static, not cumulative, for a single element - so setting .attr('transform', "translate(300,0)") more than once will have no effect after the first time. It also looks like your placement logic for the new boxes is off.
The positioning logic required here is pretty straightforward if you take a step back (assuming I understand what you're trying to do):
Every time a new box is added, the frame all boxes are in moves right 120px, so it needs a x-translation of 120 * counter.
New boxes need to be offset from the new frame position, so they need an x setting of -120 * counter.
Zoom needs to take the current canvas offset into account.
(1) above can be done in your click handler:
canvas
.transition()
.duration(1000)
.attr('transform', "translate(" + (offset * counter) + ",0)");
(2) is pretty easily applied to the g element you're wrapping boxes in:
var boxGroup = canvas.append("g")
.attr('transform', 'translate(' + (-offset * counter) + ',0)');
(3) can be added to your redraw handler:
function redraw() {
var translation = d3.event.translate,
newx = translation[0] + offset * counter,
newy = translation[1];
canvas.attr("transform",
"translate(" + newx + "," + newy + ")" + " scale(" + d3.event.scale + ")");
}
See the working fiddle here: http://jsfiddle.net/nrabinowitz/p3m8A/

What is the proper way to both rotate and translate text in d3?

I have an array with two strings and I want them to align with two circles (see example: http://bl.ocks.org/3028447)
I'm currently doing this:
.attr("transform", function(d, i) { return "translate(" + x(i)+",0) rotate(-45," + x(1)+"," + 0+") "; })
I was sure there was a simpler way to do it, something like this:
.attr("transform", function(d, i) { return "translate(" + x(i)+",0) rotate(-45) "; })
but when I use that I get this (http://bl.ocks.org/3028512), and I don't understand why.
You've combined your transform with x and y attributes:
.attr("y", 0)
.attr("x", 60)
These get applied before the transform (i.e., before the rotation), hence the text is not in the same position as the circles. Sometimes this technique is useful; the x moves the text parallel to the text’s baseline. So, if you wanted to position the text slightly outside the circle, you could change the x value to 6 rather than 60.

Resources