3

I cannot reproduce problem itself even on our MacBook's but we have some logs by users. The problem is when I try to use some of rendering methods on CanvasRenderingContext2D it crashes because it's null.

So I have the canvas element, is has getContext method but it return null. Short list of checked potentials:

  1. The canvas element is created, existing, has positive size and has getContext method
  2. getContext call executed after page loading (onload listener)
  3. there is NO other calls of getContext with other parameters ('webGl' for example)
  4. in getContext('2d') '2d' string is always in lower case
  5. this problem is reproducing only on Safari 10
  6. in some cases this error occurs not after page load but after some user actions. This mean canvas was destroyed and re-created some times, and it worked.
Michael Stets
  • 98
  • 1
  • 8
  • They probably have some plugin [(example for FF, dunno about any for safari)](https://addons.mozilla.org/nn-NO/firefox/addon/canvasblocker/) disabling the canvas because of its ability of fingerprinting. Can you talk to one of your customer able to reproduce it ? – Kaiido Nov 08 '16 at 09:06
  • Found one that does this : http://jsblocker.toggleable.com/ – Kaiido Nov 08 '16 at 09:51
  • yep, it's look like something blocks canvas, but as i know these extensions doesn't block canvas entirely – Michael Stets Nov 08 '16 at 10:16
  • I only know a bit the first one I linked to, and yes, it only overwrites export methods, but you know, bad code happens, in extensions too. – Kaiido Nov 08 '16 at 10:36

2 Answers2

5

I'm not sure if this is relevant to the situation described here, but I had a similar situation which I was able to solve. Perhaps this helps somebody down the line. The gist of the problem was that browsers deal with HTML5 canvases quite differently. In particular, the amount of memory they are willing to allocate to canvases en total and to individual canvases (constraints on height, width, and area) seem to differ. I never bothered to grok the details, but here's a stack question addressing some of the constraints

For me, I was generating many independent canvases and managing their 2d context separately. The problem is that I wasn't being careful with garbage collection, and it took me a long time to notice it because I was testing for the most part in Chrome, in which everything worked fine.
Meanwhile the behavior in firefox was that my project became totally unresponsive without throwing meaningingful errors, and in Safari i could get my contexts fine until i ran out of total memory to allocate to canvases, and then getContext('2d') would return null.

My first solution was to reduce the resolution of my canvases, but the better solution was to dispose of the ones I wasn't currently using and generate them on the fly.

Community
  • 1
  • 1
Badam Baplan
  • 270
  • 2
  • 12
  • Yes... Exactly this is it. I made a simple example with 300 canvases 1000*1000 with rect drawn on it created in a cycle. All browsers work well but Safari... After 4-5 refreshes of page it fell with same error on ~160 iteration... So I think it's a bug of Safari itself. – Michael Stets Apr 20 '17 at 07:27
  • Here it is - https://jsfiddle.net/zLtoqxuy/ You can just press run button or refresh page - it doesn't matter. – Michael Stets Apr 20 '17 at 07:43
  • Thanks for the fiddle! I played with it a little in firefox too, and it definitely seems like safari has the least tolerance for canvases. But if you increase the height and width of the canvas you'll find that firefox starts to have trouble too. Just doubling the height and width to 2000 will cause the script to become unresponsive. – Badam Baplan Apr 20 '17 at 18:55
  • The problem is total canvas memory limit in safari. This question give some useful detail about it https://stackoverflow.com/questions/52532614/total-canvas-memory-use-exceeds-the-maximum-limit-safari-12 – Duannx Aug 02 '20 at 13:18
0

I had the same problem. I don't know why it happens even though I searched it a lot but I tried 2 things and they solved my problem :

You can either :

  1. Get the type of context of your canvas in html using tags after your element. Even if you will not use it, just for initialization. I know it is really ugly and bad, unstructured code but it is just a workaround :(

    var canvas = document.getElementById('canvas');

    canvas.getContext('2d');

  2. Create dynamically your canvas with js and get the context :

    var newCanvas = document.createElement('canvas');

    newCanvas.id = 'canv';

    canvasContainer.appendChild(newCanvas);
    
    var c = newCanvas.getContext('2d'); // whatever type of context
    
ThanosSar
  • 532
  • 6
  • 20