Recursive/recurring animation events in D3 - animation

I'm trying to make recurring transitions in D3 that will keep repeating indefinitely. Specifically, I'm working with a map and I want the background stars to occasionally flicker. The problem with transitions is that it appears they're all run ahead of time, so it will try to do the infinite recursion ahead of time and the page will never load. I found a related example (recursive d3 animation issue) that isn't infinite. My only other idea is to somehow use the d3 timer, but I'm not entirely sure how to go about that either. Any tips are appreciated.

Right, you can’t schedule an infinite number of transitions ahead of time. :) However, you can repeatedly schedule a new transition when the old transition ends (or starts), using transition.each to listen for end (or start) events.
Take a look at the chained transitions example for an infinitely-repeating animation. Whenever a circle transition starts, it also schedules an identical following transition, allowing the transition to repeat indefinitely.
Alternatively, you could use setInterval or setTimeout to create transitions repeatedly, as in the concurrent transitions example. Unlike the chained transitions example I linked, this approach won’t guarantee exact synchronization of chained transitions, but if all you want is an occasional background flicker, it might be a slightly simpler approach.

Related

How to debug HTML5 canvas pixi.js performance?

I've made a game on pixi.js where it is very simple and should run smoothly but doesn't. Since the game is big and has lots of elements I don't know where the bottleneck is. I believe some part/s of the is buggy resulting in lots of resource usage.
I want to learn the method on how to identify the functions I wrote that use up a lot of resources.
When I use default chrome tools they never show the part of the code that I wrote but always the library ticker: https://prnt.sc/qiplql.
This doesn't help me, I want to know which functions I wrote that is being called many times and uses up a lot of resources.
What is a way I can do this?
Here is our debugging server where the code isn't minimized.
Zoom in
To get the most out of the performance monitor you must zoom into the timeline and investigate small sections of code.
The image below shows the section of the timeline, and the Call tree's representation of that small section of time
Find a single frame
However this still is too much information. Zoom right in to find a single frame that is running long (over 16ms)
Use the graphical call tree (open fold main)
The next image shows a long frame (25ms) Opening the fold main (on left) will show a graphical representation of the call tree.
The frame is started with a long task triggered by a mouse up event. At the bottom of that stack the reason the event takes so long is the DOM recalculating the style.
The recalculation of the style meant that the next requestAnimationFrame callback had some extra baggage before (reflow) and after the script (DOM rendering and compositing) meaning the frame was late to present.
Zooming in on the requestAnimationFrame there are no problems. Just as an example I zoomed so you can see how the graphical representation relates to the Call tree. I have drawn some lines connecting graphical function calls with the same call in the call tree.
Many reasons
To find your bottle necks you will have to zoom right in on the slow frames. There may be many different reasons that frames are slow.

How can I make transitions between dc.js charts smooth when I have a map with more than 20k points?

I've recently built a smaller version of a prototype data explorer incorporating crossfilter, dc.js, and leaflet.markerCluster. The small version, (prototype dashboard), works properly. The problem I am having is when I try to scale it up to 20k points or more.
The charts still render correctly, and the map works to update the charts smoothly when zooming or panning, but when I interact with one of the charts, the transitions between the other charts are no longer smooth. They jump to their next position rather than smoothly transitioning.
I tried removing the map and this restored the transitions between the other charts to a nice smooth transition again.
I'm wondering if the re-rendering process is getting caught up with the 20k points each time an interaction occurs.
If anyone has any suggestions about where I might look for a solution I'd be grateful.
Thanks for posting a block, that makes things easier to test.
I simulated a lot more points by generating 200 rows for each of yours ~ 46k rows. I saw only a little stuttering at 100x ~ 23k rows (2017 iMac with plenty of RAM).
Leaflet.markercluster is known to be slow with more than 10K points. With 46k rows it took about 475ms for Leaflet.markercluster to clear and add the Leaflet layers:
Since there is only one thread in JavaScript (unless you use workers), D3 needs to get timeouts (actually requestAnimationFrame) every 16ms or so in order to produce fluid animation.
One workaround is to delay the map redrawing 500ms until the others have done:
dc.override(mapChart, 'redraw', function() {
window.setTimeout(() => mapChart._redraw(), 500);
});
Fork of your block with workaround.
Of course, this also makes the map take 500ms longer to redraw. And if you click around fast enough, the last map redraw will still be running when it's trying to draw the charts.
You could also try the chunked addLayers options but I think you would have to set the chunkedInterval so low that it would also slow down the markerclusters.
Processing this much data efficiently is possible in JavaScript - obviously crossfilter has no problem here. I don’t know if the cloistering algorithm is inherently too expensive. Someone on the issue suggested pre-aggregating the points, but I think this would mean you wouldn't be able to see individual points.

is it prohibited to use transition interval same as redraw interval?

I've been trying D3 for a day or two now. So I'm a D3 newbie but have lots of C/C++, Java, PHP, Javascript, etc background.
I started from the tutorials page github.com/mbostock/d3/wiki/Tutorials, and went fairly meticulously through
- Introduction
- Three Little Circles
- Thinking with Joins
- How Selections Work
first trying examples verbatim, sometimes trying different changes to see if I understand the results.
I then jumped to A Bar Chart, Part 1, and Part 2.
I ended up with results pretty much exactly as expected by the end of Part 2. The tutorial only has code fragments and I don't see a spot in the tutorial where it says "here is the full finished result you should end up with", nonetheless I end up with this http://jsbin.com/oqetuw/2/edit and it looks to be working identically to the tutorial.
Note for those who haven't tried this tutorial, the key points I'm asking about are the redraw interval, 1500 ms, the transition duration, 1000 ms, and the transition ease function, which the tutorial doesn't use or specify, but I've googled to find that it defaults to cubic-in-out.
As my goal is for a continuous smooth scrolling across the screen, I changed the redraw interval to 1000, and the transition ease function to "linear", and the result is here http://jsbin.com/ijumuv/1/edit
And these are the only changes as shown here:
$ diff tut2.09.html tut2.10.html
33c33
< }, 1500);
---
> }, 1000);
78a79
> .ease("linear")
82a84
> .ease("linear")
86a89
> .ease("linear")
The strange behaviour, and thus the question is, why do occasionally the bars that reach the left edge seem to bounce back and accumulate from left to right, behind the main bars? (and also occasionally get cleared)
Undoing only the 1500 -> 1000 change, the problem seems never to happen (so it is scrolling every 1.5 s, with each scroll duration being 1 s). So it would seem maybe if D3 is busy still doing the transition, it fails to remove them? or some other explanation I can't figure yet.
Thanks in advance for any tips.
Yeah, there are issues with d3 transitions. When the interval and duration are both 1000, there is high chance for the redraw operations to occur before the prior transition() on that selection is finished. And that messes with the data binding, or something along those lines.
I modified your code such that it continuously checks whether the previous redraw transition has finished before calling the next one. This is by no means "good javascript", but it does illustrate the issue, and some way around it. To understand what I added, just look for all occurrences of __readyForNext in the code. It should make sense.

What is the best way of making concurrent animations?

this is an algorithm/data structure question about making different animations at the same time. For example, a ball is falling down one pixel in a millisecond, a bullet is moving 5 pixels in a ms, and a man is moving 1 pixel in 20 milliseconds. And think that there are hundreds of them together. What is the best way of putting all animations together, moving what we need to move in one function call, and removing the ones whose animation is completed? I don't want to create a thread for each one. What I want to do is to create one thread moving all items and sleeping until an object needs to be moved.
Note: I'm using Java/Swing, printing objects and images in JPanel.
I recently did something similar in Python. I don't know if this is the best method, but here's what I did.
Create an abstract Event class with the following public interface:
tick - calculates how much time has passed since the last tick. Perform work proportional to that time span. This should be called frequently to create the illusion of smooth movement; maybe sixteen times a second or so.
isDone - returns true when the Event has finished occuring.
Make a subclass of Event for anything that takes more than one frame to finish. Rotating, scaling, color changing, etc. You might create a TweenEvent subclass of Event if you want to move an image from one part of the screen to another. During each tick, redraw the image in a position farther away from the original position, and farther towards the destination position.
You can run many Events concurrently, like so:
Array<Event> events = new Array<Event>();
//add a bunch of TweenEvents here - one for a bullet, one for a ball, etc.
while(True){
Sleep(1/16);
for(Event e in events){
e.tick();
if (e.isDone()){events.remove(e);}
}
}

Is it better to count n ticks or run two seperate timers

I'm making a snake game and on every tick the snake moves. because the snake is moving a whole unit on each tick the animation is jumpy. The game is on an invisable grid so the snake can only change directions at specific points.
Would it be considered better practice to have a timer that will move the snake a pixels at a time counting it with a variable, and on every n tick run the code to change direction. Or is it better to have two separate timers; one for move the snake a pixel at a time and another for changing the snakes direction?
Essentially, you're creating a "game-loop" to update the displayList (in Actionscript) and re-draw your view. When the game gets complex, Timers and listening for ENTER_FRAME events will be constrained to the flashplayer settings for screen refresh (i.e. it's FPS) and the CPU's rendering based on what it is tasked to process.
For frame-rate independent animation, you should probably use a combination of ENTER_FRAME to track milliseconds and GetTimer() calls to more accurately (to the millisecond) call animations and normalize the experience across a variety of platforms.
Basically, listen for the ENTER_FRAME event, check the current milliseconds since the last update and if it exceeds your refresh-rate (in terms of milli's), fire off the animation/state update: check for snake collision detection with a "direction-block" - handle if true, then update the snake's movement / position / state.
Flash updates the Display List at whatever it's settings, and CPU / machine-dependent issues are. The key, I've found, is to make sure you're normalizing the speed of updates to make the experience consistent. Timer's have their usage, but can cause memory performance issues. ENTER_FRAME is synced to the main timeline / frame-rate settings.
For a dated, but interesting discussion 3 years ago, check out this post from actionscript.org.

Resources