14

我显示一个带有嵌入式 SVG 的 HTML。我希望它检测鼠标事件,但它不适用于移动设备(Android Jellybean)。它适用于桌面浏览器。

这是一个演示页面: http ://artsyenta.org/misc/ss/j.touchtry1.html 。

如果您将鼠标拖到圆圈上,您会看到鼠标条目记录到名为“j_xxx”的元素中。这适用于 Firefox 和 Chrome。

打开您的 Android 平板电脑(我也在某人的 iPhone 上尝试过,结果相同)。在圆圈上拖动手指,您只会时不时地收到一个 touchenter 事件。没有其他显示。

您可以通过查看页面源代码来查看整个页面和代码。它不长,最长的部分是 SVG 定义。重要的部分是:

$(document).ready(function() {
  makeSomethingHappen("hello");
});
function makeSomethingHappen(svg) {
  placeATop(true);
  $('[class^=j_]')
    .on("mouseover", function(event) { logAction(event, this); })
    .on("mouseout", function(event) { logAction(event, this); })
    .on("touchstart", function(event) { logAction(event, this); })
    .on("touchend", function(event) { logAction(event, this); })
    .on("touchenter", function(event) { logAction(event, this); })
    .on("touchleave", function(event) { logAction(event, this); })
    .on("touchEnter", function(event) { logAction(event, this); })
    .on("touchLeave", function(event) { logAction(event, this); });
}

var cntAct = 0;
function logAction(ev, ele) {
  cntAct++;
  var logSpan = $('#logTrace');
  logSpan.html("" + cntAct + ": " + ev.type + " '" + $(ele).attr("class") + "'<br/>" + logSpan.html());
}

这是 SVG 的一部分:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     id="jsvg" x="0px" y="0px" width="376.247px" height="364.318px" viewBox="140 110 130 120"
     enable-background="new 0 0 376.247 364.318" xml:space="preserve">
  <g id="Layer_1">
    <path class="j_aa_" opacity="0.75" fill="#FFFFFF" stroke="#0071BC" stroke-width="0.9925" enable-background="new    " d="M224.739,6.55l-6.414,23.957c-10.377-2.785-21.304-2.785-31.671,0L180.232,6.55C194.813,2.63,210.155,2.63,224.739,6.55z"/> 
    [snip]
  </g>
</svg>

同样,我在桌面浏览器上检测到鼠标事件,但在移动浏览器上没有检测到触摸或鼠标事件。是否缺少技术,或者手机缺少某些东西?它在 iPhone 浏览器、Jellybean 上的 Google Chrome 和 Firefox 移动设备上失败。

在此先感谢,杰罗姆。

4

2 回答 2

11

在对普通 SVG 事件和 RaphaelJS 事件进行了大量研究之后,我为每个事件提供了一个可行的解决方案。这是一个 RaphaelJS 解决方案:

window.onload = function(e) {
    document.getElementById("rsr").addEventListener("mousemove",
        function(event) { 
            logAction(event, this, "m");
        }, false);

    document.getElementById("rsr").addEventListener("touchmove",
        function(event) {
            if(event.preventDefault) event.preventDefault();
            // perhaps event.targetTouches[0]?
            logAction(event.changedTouches[0], this, "t");
        }, false);
};

代码不是无懈可击的,但说明了要点。

首先,必须通过 addEventHandler() 调用注册事件。使用 RaphaelJS onmousemove() 等,处理程序在平板电脑上不起作用。

其次,对于触摸事件,您需要深入了解触摸列表。我的应用程序只关心一个手指,因此列表的 [0] 事件就足够了。有许多列表——touches、targetTouches、changedTouches——所以选择一个合适的列表。

第三,确定窗口是否需要冒泡事件。如果我调用 preventDefault(),我对触摸更加敏感。

我在 Google Nexus、iPad 3 和 iPad Mini 上对此进行了测试。好结果。

我也有一个纯 SVG 的解决方案。它基于此站点: http: //my.opera.com/MacDev_ed/blog/2010/02/01/how-to-get-all-svg-elements-intersected-by-a-given-rectangle

我使用的和他使用的 Javascript 的区别在于,对于触摸列表需要访问的触摸。“root”是此示例的 svg 元素 ID。“logTrace”是一个接收评论的跨度。

var root = document.getElementById("root");
var evtt = evt.touches[0];

var rpos = root.createSVGRect();
rpos.x = evtt.clientX;
rpos.y = evtt.clientY;
rpos.width = rpos.height = 1;
var list = root.getIntersectionList(rpos, null);
var maxItemId = list.length <= 0 ? "(no match)" : list[list.length - 1].id;

document.getElementById("logTrace").innerHTML = "screen: (" + evtt.clientX + ", " + evtt.clientY + ") ? uu(" + maxItemId + "): (" + uupos.x.toFixed(0) + "," + uupos.y.toFixed(0) + ")";

我已经在 Nexus 和 iPad 上成功测试了这个解决方案。但是,它在 iPad Mini 上表现不佳——为什么在两台 iPad 设备上表现不同?

我还注意到“plain svg”解决方案的检测似乎不如 RaphaelJS 版本准确。在我的 SVG 元素的边缘附近,普通 svg 检测的检测效果不是很好。我一直在使用 RaphaelJS 获得良好的结果。

OTOH,RaphaelJS 的使用对具有 (fill:none) 的 SVG 很敏感。普通的 SVG 不关心 (fill:none) 是否在元素中设置。选择你的毒药。

于 2013-05-04T01:25:21.027 回答
2

我遇到了这个问题,事实证明 iPad 会考虑对象的不透明度来实现其命中测试功能,所以如果你有一些带有 fill:none 的东西,它就不会注册一个事件。

我成功地测试了这种风格的路径:

.st5 {fill:none;fill-opacity:0.01;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72}

以及放置在包含路径的标签上的两个事件处理程序:

  <g ...  onclick="top.load(3201);" ontouchend="top.load(3201);" > ...path here with style .st5 </g>

load(id)函数存储在外部 JS 文件中。

另一个问题是 SVG 必须直接放在 HTML dom 中,而不是引用为<embed .../>,后者会导致安全异常

于 2013-10-28T15:38:52.267 回答