I looked at your online code and found that you are using setInterval for the animation loop.
Most likely, the reason is that the code cannot complete the calc call, etc., you risk the call stack - for context, this means that you can have a path that reset each other.
Try replacing setInterval with setTimeout . Of course, you need to restart it again from within the code - even better, put everything in a function using setTimeout at the end of this function, i.e.:
function animate() {
I use 0 for a timeout here for this test. setTimeout/setInterval will not sync with the refresh rate of the screen anyway.
If this works, then you know the reason. The next step would be to replace it with requestAnimationFrame , but let me know how this happens.
In an attempt to illustrate the problem, we can look at this illustration:

Each block is a function within a cycle, and one cycle is one. Remember that setInterval calls at fixed intervals, while setTimeout calls a relative call when it calls. In this example, the functions are performed within the time budget, so that everything is going well.
In the following illustration:

costs are out of budget, so setInterval is called again and the next call queues in the second loop until the first is completed. When a queue is processed between calls, you end up risking having two functions working in the context at the same time (or coming in a different order than you might expect).
Javascript, of course, is single-threaded, so they are not executed at the same time, but one of them is held on hold - if the first block for the next queue is called before the last block has time to call, then the first block will change the context and, possibly, even change the path to the last call of the previous call. Over time, the lag will increase and potentially (if only some additional available processing resources do not decide the queue in the queue, then in a more busy system this will be less likely) worsen and worsen as more stacking occurs.
Those. in this case, you could add lines to the context with beginPath() before the arc is full.
(hope this made some sense ...)
Using setTimeout prevent this, since it will not be executed before all calls in the animation loop return. The best option is to use requestAnimationFrame , as this will cause synchronization with the refresh rate of the screen, as well as whenever possible. It is lower level and therefore also more efficient.
Another way (no pun intended) is to use Web workers to do the calculations. This will be multi-threaded and can increase overall performance since the web worker does not affect the user interface flow.