Pergunta

I came across a bug a few weeks back in Android where by if you position a canvas element on the Native Android Browser (WebKit 534.4) using css positioning position:absolute; top:10px; left:100px; the duplicated Canvas (Apparently android uses one for GPU acceleration) is rendered to the browser ignoring the positioning.

So if I have a canvas at position top:100px; left:100px; I would have my canvas in position perfectly, but the GPU accleration canvas would be ignoring it and will sit in the top left corner (see images from my previous question

Android Native Browser duplicating HTML5 canvas (fine in chrome)

I found a solution, which was to use CSS translate instead, like this transform: translate(100px, 100px); this now fixes the issue as the GPU accleration canvas is rendered in the same place (so it doesnt appear duplicated)....

BUT as a knock on effect I now have a clicking bug.

As im centering the canvas, when the window width is smaller than the device width the X position will be a negative value, the only clickable area of the canvas when this has happened is what would be displayed without the positioning.

This is hard to explain but hopefully this image will make it clearer

Click Bug

I think it's an issue with the browser itself as even when I have this code the alert doesnt fire from half of the screen

canvas.addEventListener('click', function(e) { alert('click'; });


I'm guessing that CSS position top and left use the CPU to move the canvas so the GPU generated one is in the wrong place, but CSS translate uses the GPU to move the canvas so the GPU generated one is correctly positioned but the CPU is reading mouse events without this offset........AHHHHH!


EDIT: after testing on more devices I can confirm that this appears to be an issue with browsers using a version of webkit under 535 as this issue appears on most Android Native browsers and Safari on iOS5

Foi útil?

Solução

Ok, i've fixed this issue, but I think it's pretty case specific.

if(webKitVer < 535) {
     document.body.style.paddingTop = pos.top + "px";
    if(canSeeWholeOfCanvas) {
        canwrap.style.transform = 'translateX('+pos.left+'px)';
        canwrap.style.left = 'auto';
    } else {
        canwrap.style.left = pos.left + "px";
        canwrap.style.transform  = 'none';
    }
} 
else 
{
    //standard all browsers
    canwrap.style.transform = 'translate('+pos.left+'px, '+pos.top+'px)';
}

feels hacky, case specific and hard to explain. but it works


in old webkit browsers (generally Android native browsers and IOS5 safari there are two bugs

if the canvas is positioned with css top and left, then a duplicate GPU rendered canvas (generated for GPU hardware acceleration) will be rendered ignoring them properties so they're not aligned correctly.

if the canvas is positioned with css transform then the GPU duplicate canvas is correctly aligned, BUT when the canvas is positioned at minus X position then the only the part of the canvas that would be visible without the css is clickable

so changing between the two depending on visibility of the canvas is needed

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top