Make multiple delays in chained transitions in D3.JS - javascript

I am moving a rectangle from point a to point i in a picture, i want to mark a stop delay of 5s for each point (there are 8 points). the transitions work fine in the code below (the delay works only for point b).The problem is that i can't add more delays for my other transitions.
Is there any way to do it ?
Thank you all in advance.
function TRANSITION(access,dur=10000,Delay=5000,b=390.5,c=523,d=632.5,e=810.8,f=942.5,g=1063,h=1196,i=1334.5)
{
access.transition().duration(dur).attr('x',b)
.transition().delay(Delay).duration(dur).attr('x',c)
.transition().duration(dur).attr('x',d)
.transition().duration(dur).attr('x',e)
.transition().duration(dur).attr('x',f)
.transition().duration(dur).attr('x',g)
.transition().duration(dur).attr('x',h)
.transition().duration(dur).attr('x',i)
}

You could add a transition that changes no attributes but still has a duration:
.transition()
.duration(dur)
.attr('x',d)
.transition() // don't transition anything
.duration(5000) // but take five seconds doing it
.transition()
.duration(dur)
.attr('x',e)
I've only tested this in version 4, so it is possible that this might not work in version 3. Alternatively, you could add the .attr line in the delaying transition if you were to leave some attribute the same.

Related

Removing elements by class on scroll

Note: I asked this question about interrupting transitions during a scroll, but am trying a different technique now that is resulting in a similar issue that doesn't get resolved with the accepted (and working) answer.
This time, rather than initializing all the graphs with 0 opacity and having a separate function to change the opacity that gets called on each step, I'd like to use selection.remove() in each drawing function. I want to do this so that out-of-view graphs don't get in the way of any mouseover interactions that I might want on the current graph.
For example, I have functions that clear the existing graphs and then draw the current one with some transition:
var makeCircle0 = function() {
d3.selectAll(".nancygraphs").interrupt().remove()
g.append("circle")
.attr("cx", 50)
.attr("cy", 100)
.attr("r", 20)
.attr("fill", "red")
.attr("id", "red")
.attr("opacity", 0)
.transition()
.duration(1000)
.attr("opacity", 1)
.attr("class", "nancygraphs")
}
These functions are put in a list
var activateFunctions = [];
activateFunctions[0] = makeCircle0;
activateFunctions[1] = makeCircle1;
activateFunctions[2] = makeCircle2;
activateFunctions[3] = makeCircle3;
And depending on the step, the function gets called to draw the correct graph
function handleStepEnter(response) {
console.log(response)
step.classed('is-active', function(d, i) {
return i === response.index;
})
figure.select('p').text(response.index);
figure.call(activateFunctions[response.index]) // HERE!
}
Here is a jsfiddle to illustrate. Basically, if you scroll back-and-forth quickly then old graphs don't get cleared and you'll notice several graphics in view simultaneously. Why isn't d3.selectAll(".nancygraphs").interrupt().remove() doing the job?
Three observations regarding your approach:
First, according to the d3 manual on
transitions:
remove: remove the selected elements when the transition ends.
The remove will not interrupt already running transitions - it only removes when all transitions have stopped. More specifically it seems to act when __transition__.count of an element reaches 0. You could consider using a non-d3 remove implementation here, e. g. jQuery.
Second, from the same manual:
Interrupting a transition on an element has no effect on any transitions on any descendant elements. (...) you must therefore interrupt the descendants: selection.selectAll("*")
You should call interrupt on both by doing d3.selectAll(".nancygraphs").interrupt().selectAll("*").interrupt().
Third, it is never a good idea to directly couple mouse or scroll input to your logic (when you directly couple input events to e. g. attaching a transition, you might be doing so many thousands of times): did you use a debounce function? The lodash implementation is highly recommended.
After trying these modifications I would assume your current problem is solved. If it is not, a further way of debugging would be to log / overwrite the __transition__.count attribute of your elements.

Fade in bars one by one with D3

I have a bar chart and want to add effect to fade bars one by one with some delay.
Here is what I have now but it fades in all bars that are path at once. How can I make them appear one after another with some delay?
.selectAll("path")
.attr "opacity", (d,i)->
0
.transition().delay(3000).duration(1000)
.attr "opacity", (d,i)->
1
Answer
Use the index value to stagger the delay
.delay(function(d,i){return i * 300;})
Because the index is zero based this means the first item has no delay. If this is not desired then you could do something like something like
.delay(function(d,i){return (1+i) * 300;})
Example
For those less familiar with D3 a quick example of this in action at this JSFiddle

How to cancel the mouseover transition in d3.js

Here is the structure of my HTML
svg
g id=invisibleG
g
circle
g
circle
g
circle
So I want something like this on hover of any particular circle
svg
g id=invisibleG
g
circle --> radius is increased on hover.....decreased on hoverout
text
g
circle
g
circle
here is the code
.on("mouseover",function(){
var r=d3.select(this).attr("r");
d3.select(this).style('fill','tan')
.style('fill-opacity', '1')
.transition()
.duration(1000)
.attr("r",50);
d3.select(this).attr("stroke","blue")
.attr("stroke-width",4);
})
.on("mouseout",function(){
var r=d3.select(this).attr("prevRadius");
d3.select(this).attr("r",r)
.attr("stroke-width",0)
.style('fill-opacity','0');
});
Now the problem is that when I hover over a circle and immediately hover out of it the transition which is started in mouseover doesn't stop immediately.It completes its transition and the size of radius is increased despite being the fact that mouseout event should be called.And whatever the transition was going should stop.
Please let me know the problem and its solution .
You just need to use transitions in both cases. From the documentation:
If a newer transition runs on a given element, it implicitly cancels any older transitions, including any that were scheduled but not yet run. This allows new transitions, such as those in response to a new user event, to supersede older transitions even if those older transitions are staged or have staggered delays.
So your code would need to be something like this.
.on("mouseover", function() {
this.prevRadius = d3.select(this).attr("r");
d3.select(this)
.style('fill','tan')
.style('fill-opacity', '1')
.transition()
.duration(1000)
.attr("r",50)
d3.select(this)
.attr("stroke","blue")
.attr("stroke-width",4);
}).on("mouseout", function() {
d3.select(this)
.transition()
.attr("r", this.prevRadius)
.attr("stroke-width",0)
.style('fill-opacity','0');
});
Demo here.
If your d3 version is mature enough (3.3+), they seemed to have added selection.interrupt
So you could perhaps try:
.on("mouseout",function(){
d3.select(this).interrupt();
// if interrupt isn't supported in your version use below
//d3.select(this).transition().duration(0);
})
Otherwise, newer transitions on the same selection will cancel the old active transitions. So you could run a new transition on mouseout where you transition to the reset values again. If you want to just freeze the transitions, just run a dummy transition to cancel the old one.
FURTHER INSIGHTS
If your goal is to stop the only transition of the r (radius) dead in its tracks see this fiddle which uses interrupt.
If your goal is to reset the r value or the non-transition changes you've made during the mouseover, see this fiddle

Too fast insertion of data into d3 diagram with animation

I am using d3js to visualize my data. Everything works fine, when I have my "normal" code running. But now when I add animations for the insertion and deletion of elements and I insert/delete data elements too fast, then the animations of the first inserted element is not completed before the next element being inserted triggers the animations once again. Is there a way to wait for the animations of d3 to be completed?
Example code für an animation:
layoutRoot.selectAll('g')
.data(nodes, function (d) { return d.path })
.exit()
.transition()
.duration(400)
.style('opacity', 0)
.remove()
This would be a comment but I don't have the necessary reputation.
See this d3 issue on github. Is this what you're looking for?
It's in the 3.3 milestone and the current version is 3.2.8. So, hopefully it won't be too much longer.

Transition flickering

I see a strange flickering effect after a transition. It is unusual mainly because I do not set the opacity in any way (I want the color to remain the same). Any ideas why this happens?
To have an idea about how the code looks like, here is an example.
var theBars = this.vis.selectAll(".bar" + source.id).data(this.columns);
theBars.enter().insert("svg:rect")
//some attributes
.style("fill", sourceColor)
//some other attributes
theBars.transition()
//.duration(.01)
.attr("y", function(d) {
return this.settings.base - this.getStackedBarHeight(d, source.id);
}.bind(this))
.attr("height", function(d) {
return this.getBarHeight(d.counters[source.id]);
}.bind(this));
As it can be seen only one line sets the color.
I initially tought I made some mistakes at binding, but after checking some posts here and on Google Groups, I discovered that this flickering usually appears when you have transitions that also change the opacity of the object. Unfortunately I don't change any opacity, I just make a transition. This effect appears in all major browsers when executing that transition (theBars.transition).
I try to select a bar from a stacked bar and modify its height.
Best regards!
To fix this I added 2 things:
in the init phase - I added all the bars but with all counters set
on 0;
in the draw phase - I added this code:
var theBars = this.vis.selectAll("#bar_"+index+"_"+currentIndex);
this.settings.sources.each(function(pair) {
theBars
.style("fill", source.color)
.attr("height", this.getBarHeight(source.id)
.attr("y", this.settings.size.baseLine - this.getStackedBarHeight(counters, source.id))
}, this);
The flickering caused by the transitions is gone since we have no transition here. There are still situations in which we need to do a transition, for example when we have several bars with the same word, but there I resolved the flickering by doing it really quick (a .duration(.1) or even less).

Categories

Resources