转换后的SVG元素的触摸事件不正确

时间:2019-05-18 10:00:54

标签: svg touch zoom addeventlistener

在尝试通过应用矩阵变换来缩放/平移内嵌SVG图像的过程中,我发现了一件非常奇怪的事情。加载图像后,我将向touchstart事件监听器附加到SVG图像中的某些元素,并且在触摸对象时立即触发该事件。但是,在应用转换后

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

具有缩放和/或平移触摸同一对象的整个SVG图像的效果,不再触发预期的触摸事件。经过一些实验,我发现事件仍然可以由屏幕上的触摸位置触发,与对象在屏幕上的实际新放置无关。然后,在发出矩阵变换后,我首先对对象进行removeEventListener,然后对addEventListener进行操作,然后发现触摸事件处理恢复正常。

除了我想避免每次平移/缩放之后删除然后重新分配同一事件侦听器的相当昂贵的操作这一事实外,我想了解为什么会这样。就像浏览器在addEventListener阶段定位对象的像素位置,然后在其内存中的某个位置过分地幸福地忽略了以后可能发生的任何对象位移。

这里有人可以告诉我这里发生了什么以及如何以更有效的方式平移和缩放后保留触摸事件的效用吗?

1 个答案:

答案 0 :(得分:0)

我设置了一个类似的问题: 有一个 <circle> 元素,在 <svg> 中有一个转换属性。 'touchstart' 事件仅在第一次点击 <circle> 时触发。之后它不再触发 'touchstart' 事件。

我发现了一个奇怪的解决方法:使用 'touchstart' 处理程序将 <svg> eventListener 添加到 noop 元素:

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

此后,<circle> 完美地触发了 'touchstart' 事件。

您可以使用以下代码进行测试:

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>