Можете * вы * получить SVG в мобильном браузере принять события мыши/касания? Я не могу

Я показываю HTML со встроенным SVG. Я хочу, чтобы он обнаруживал события мыши, но он не работает на мобильном устройстве (Android Jellybean). Он отлично работает для настольного браузера.

Вот демонстрационная страница: http://artsyenta.org/misc/ss/j.touchtry1.html.

Если вы нажмете мышь над кругами, вы увидите журнал записей мыши в элементы с именем "j_xxx". Это работает в Firefox и Chrome.

Откройте Android-планшет (я тоже пробовал это на iPhone, с теми же результатами). Перетащите палец по кругам, и вы получаете событие touchhenter только время от времени. Больше ничего не отображается.

Вы можете просмотреть всю страницу и код, просмотрев источник страницы. Это не долго, самая длинная часть - определение 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, Google Chrome на мобильных устройствах Jellybean и Firefox.

Спасибо заранее, Джером.

Ответ 1

После много исследований простых событий 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] списка достаточно. Существует несколько списков - touchs, 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 для этого примера. "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 чувствительно к SVG, имеющему (fill: none). Простой SVG не волнует, если (элемент: none) установлен в элементе. Выберите яд.

Ответ 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 .../>, последний вызывает исключения безопасности