转换后的 SVG 元素的触摸事件是错误的 [英] Touch events are wrong for transformed SVG elements

查看:32
本文介绍了转换后的 SVG 元素的触摸事件是错误的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在通过应用矩阵变换尝试缩放/平移内联 SVG 图像的过程中,我发现了一个相当奇特的事情.加载图像后,我将 touchstart 事件侦听器附加到 SVG 图像中的某些元素,并且在触摸对象时立即触发该事件.但是,在应用变换后

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

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

除了我想避免移除 & 的相当昂贵的操作这一事实之外.然后在每次平移/缩放后重新分配相同的事件侦听器,我想了解为什么会发生这种情况.这就像浏览器在 addEventListener 阶段定位对象的像素位置,然后将其保存在其内存中的某处,完全不知道以后可能发生的任何对象位移.

这里的任何人都可以告诉我这里发生了什么,以及我如何在 pan & 之后保留触摸事件的效用.以更有效的方式放大?

解决方案

我已经设置了一个类似的问题:有一个 元素,在 中有一个 transform 属性.'touchstart' 事件仅在第一次点击 时触发.之后它不再触发 'touchstart' 事件.

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

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

在此之后, 完美地触发了 'touchstart' 事件.

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

let debugLines = [];让行 = 0;函数 writeDebug(...t) {让 d = document.getElementById('debug');debugLines.unshift(`${lines++}: ${t.join(' ')}`);debugLines.splice(5);d.innerHTML = debugLines.join('<br/>');}document.querySelectorAll('circle')[0].addEventListener('touchstart', writeDebug);/* 从下面的行中删除注释以测试解决方法 *///document.querySelector('svg').addEventListener('touchstart', () => {});

<头><风格>svg { 背景:#f0f0f0;宽度:200px;向左飘浮;}</风格><身体><div id="包裹"><svg viewBox="-50, -50, 100, 100" class="b-circular-slider-svg"><circle cx="0" cy="0" r="8"中风="#ccc" 填充="#fafafa"transform="translate(0, -10)"></circle></svg>

<strong>调试:</strong><div id="调试"></div></html>

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?

解决方案

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>

这篇关于转换后的 SVG 元素的触摸事件是错误的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆