Mikhus / canvas-gauges

HTML5 Canvas Gauge. Tiny implementation of highly configurable gauge using pure JavaScript and HTML5 canvas. No dependencies. Suitable for IoT devices because of minimum code base.
http://canvas-gauges.com/
MIT License
1.57k stars 395 forks source link

Gauge breaking in safari after certain amount of time #155

Open ruudboon opened 6 years ago

ruudboon commented 6 years ago

I'm working on a weather dashboard Here using MQTT I'm updating the gauge realtime. After a certain amount of time I get the following error:

CanvasRenderingContext2D.save() had been called without a matching restore() too many time. Ignoring save().

Causing the gauge to break and go crazy spinnin.

screen shot 2018-01-13 at 08 00 41 screen shot 2018-01-13 at 07 55 04
avijeetnpi commented 6 years ago

Did you find any solution to this problem. In my case it is running out of memory. Safari is storing all the old instances of gauge when I am updating the value and hence after certain amount of time it reaches the RAM threshold and crashes. Any help will be appreciated. I am usingthe update method of gauge to update it every second.

ruudboon commented 6 years ago

@avijeetnpi Nope. Still the issue for me.

javeshmonga commented 6 years ago

Having a similar issue, tried on chrome as well, application starts slowing down over a span of few minutes and then eventually freezes, on hitting refresh takes a few minutes to load again, again works fine for a few minutes then again the same thing happens. changing the value on the gauge through gauge.set() method as part of a loop.

avijeetnpi commented 6 years ago

@javeshmonga , @ruudboon I have figured out one thing. The issue disappears when I am not debugging. I am using it in mobile app. It works fine on my mobile device but debugging breaks it.

midu-liuzhaoping commented 5 years ago

@avijeetnpi Nope. Still the issue for me.

Hello, what's the best way? I also met

midu-liuzhaoping commented 5 years ago

Hello, what's the best way? I also met

videobuff commented 4 years ago

Same story here. It for about an hour and then goes crazy spinning

X25guru commented 4 years ago

I just upgraded from an old version that has worked for many many years and see this issue. Is this a dead project? How could this not be addressed in 2 years?

Mikhus commented 4 years ago

I just upgraded from an old version that has worked for many many years and see this issue. Is this a dead project? How could this not be addressed in 2 years?

No, it's not dead. You can suggest a PR and I will merge.

X25guru commented 4 years ago

Unfortunately the new version is unusable so I had to revert to v1

Lecter2508 commented 4 years ago

Same thing for me. I'm using a radial gauge as well that I'm updating with the Geolocation API to get speed readings. After a while it will start spinning like crazy. Any ideas on how to fix it ?

I believe this is webkit related : https://bugs.webkit.org/show_bug.cgi?id=159586

context.restore() would fix the issue I think, but I didn't try it yet!

Edit : fixed the issue for me. No more crazy spinning !

andrewdjackson commented 4 years ago

Same thing for me. I'm using a radial gauge as well that I'm updating with the Geolocation API to get speed readings. After a while it will start spinning like crazy. Any ideas on how to fix it ?

I believe this is webkit related : https://bugs.webkit.org/show_bug.cgi?id=159586

context.restore() would fix the issue I think, but I didn't try it yet!

Edit : fixed the issue for me. No more crazy spinning !

How did you fix this?

slokhorst commented 4 years ago

The issue is that context.save() is called much more often than context.restore() in RadialGauge.js. This causes the stack to grow with approximately 33 states on each update, until it's too large (> 1024 * 16 states according to the previously mentioned WebKit bug) and Safari refuses to increase it even more. So this would happen after approximately 1024*16/33 = 496 updates of the gauge.

The fix is pretty simple: remove all the context.save() calls that don't have a corresponding context.restore().

Edit: I've removed the most obvious superfluous context.save() in #220, and it seems to reduce the rate of the stack increase to (near) zero. Testing welcome!

Strandinator commented 3 years ago

Test browser: Safari 14.7.1 on iPadOS

In our case we have animated value changes in 1 second intervals with the default animation duration of 500.

The fix proposed by @slokhorst in #220 is unfortunately not enough. Although in our case the duration increased from ~4:15 to ~8:20 minutes until the gauge breaks and starts spinning. So I would guess they are right with their explanation.

I tried finding all context.save calls that have no corresponding context.restore but wasn't successful in limited time. Since there was also a related issue with firefox on windows I use a workaround instead.

let renderCount = 0;

radialGauge.on("render", () => {
  renderCount += 1;
})

function updateGauge(params) {
  if (renderTicks >= 450) {
    renderCount = 0;

    radialGauge.canvas.redraw(); // <- the important part

    // loads a new CanvasRenderingContext2D
    // the old instance with the overflowing context-state stack should be GC-able
  }

  // update gauge / set value etc...
});

In our specific case (apart from the safari issue) there was a rendering error after ~500 render ticks in firefox on gecko engine. If this doesn't apply to your gauge config you might want to increase that limit to somewhere around 8000 (?) not sure haven't tested

X25guru commented 3 years ago

I'm running v1 from 2012. Works great.