1

In the process of experimenting with scaling/panning an inline SVG image by applying a matrix transform I have discovered a rather peculiar thing. After loading the image I am attaching a touchstart event listener to some of the elements in the SVG image and the event fires right away when the object is touched. However, after applying a transform

document.getElementById('mysvg').setAttribute('transform''matrix(a b c d e)')

which has the effect of scaling and/or translating the entire SVG image touching the same object no longer triggered the expected touch event. After some experiment I found that the event could still be triggered by the touch location on screen had no bearing to the actual new placement of the object on the screen. I then proceeded to first removeEventListener followed by addEventListener for the object after issuing the matrix transform and lo & behold the touch event handling was back to normal.

Quite apart from the fact that I would like to avoid the rather expensive operations of removing & then reassigning the same event listener after each pan/zoom I would like to understand just why this is happening. It is like the browser is locating the pixel location of the object at the addEventListener stage and then holds on to that somewhere in its memory blissfully ignorant of any object displacements that might have occurred later.

Can anyone here tell me what is going on here and how I can go about retaining the utility of the touch event after pan & zoom in a more efficient manner?

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
DroidOS
  • 8,530
  • 16
  • 99
  • 171
  • 1
    There used to be a CSS bug like this where if the transform was done on the GPU, the hit-box of the object wasn't updated. It's not supposed to happen. The workaround for that bug was to tweak the style change so that it couldn't be done on the GPU (like adding a padding or margin change). I don't know if that's what's happening here but I'm guessing so. Which browsers are you seeing this problem in? I'd report a bug. – Michael Mullany May 18 '19 at 21:54
  • 1
    Yes. Sounds like a browser bug. Please report it. And please post the bug link here for the benefit of future readers. – Paul LeBeau May 19 '19 at 01:53

1 Answers1

0

I've set up a similar issue: There is a <circle> element, with a transform attribute inside an <svg>. The 'touchstart' event fires only at the first tap on the <circle>. After that it doesn't trigger the 'touchstart' event anymore.

I have found a strange workaround: Add a 'touchstart' eventListener to the <svg> element with a noop handler:

document.querySelector('svg').addEventListener('touchstart', () => {});

After this the <circle> triggers the 'touchstart' events perfectly.

You can test it with the folllowing snipet:

let debugLines = [];
let lines = 0;
function writeDebug(...t) {
  let d = document.getElementById('debug');
  debugLines.unshift(`${lines++}: ${t.join(' ')}`);
  debugLines.splice(5);
  d.innerHTML = debugLines.join('<br />');
}

document.querySelectorAll('circle')[0].addEventListener('touchstart', writeDebug);

/* remove comment from the line below to test workaround */
// document.querySelector('svg').addEventListener('touchstart', () => {});
<!doctype html>
<html>
<head>
    <style>
        svg { background: #f0f0f0; width: 200px; float: left; }
    </style>
</head>
<body>
    <div id="wrap">
        <svg viewBox="-50, -50, 100, 100" class="b-circular-slider-svg">
            <circle cx="0" cy="0" r="8" 
                    stroke="#ccc" fill="#fafafa" 
                    transform="translate(0, -10)"></circle>
        </svg>
    </div>
    <strong>debug:</strong>
    <div id="debug"></div>
</body>
</html>
Burnee
  • 2,453
  • 1
  • 24
  • 28
  • The bug disappeared a day or so after I reported it - I assume it got fixed. Interesting to know that it has cropped up again. – DroidOS Jan 19 '21 at 09:27
  • It seems like a general issue now. I've tested this behavior on chrome, chromium, brave and firefox. All works the same. – Burnee Jan 19 '21 at 13:45