Can *you* get SVG on mobile browser accept mouse/touch events? I can't

后端 未结 2 697
走了就别回头了
走了就别回头了 2021-02-19 09:38

I display an HTML, with an embedded SVG. I want it to detect mouse events, but it isn\'t working on the mobile (Android Jellybean). It works fine for a desktop browser.

相关标签:
2条回答
  • 2021-02-19 10:05

    I had that problem and it turns out the iPad considers the opacity of an object for its hit-test function, so if you have something with fill:none it won't register an event.

    I successfully tested a path with this style:

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

    and two event handlers placed on the tag containing the path:

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

    the load(id) function is stored in an external JS file.

    Another catch is that the SVG has to be placed directly inside the HTML dom and not referenced as an <embed .../>, the latter causes security exceptions

    0 讨论(0)
  • 2021-02-19 10:09

    After a lot of research into plain SVG events and RaphaelJS events, I have a workable solution for each. Here is a RaphaelJS solution:

    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);
    };
    

    The code is not airtight, but illustrates the major points.

    First, the events must be registered through the addEventHandler() call. Using the RaphaelJS onmousemove(), etc., handlers doesn't work on the tablet.

    Second, for touch events you need to dig into the list of touches. My application only cares about a single finger, and so the [0] event of the list is enough. There are a number of lists -- touches, targetTouches, changedTouches -- so choose an appropriate one.

    Third, determine if the window needs to bubble the events. I get more sensitivity to touches if I call preventDefault().

    I tested this on a Google Nexus, iPad 3 and iPad Mini. Good results.

    I also have a solution for plain SVG. It is based on this site: http://my.opera.com/MacDev_ed/blog/2010/02/01/how-to-get-all-svg-elements-intersected-by-a-given-rectangle

    The differences for what I use and the Javascript he uses is that, again, for touches the touches list needs accessing. "root" is the svg element ID for this example. "logTrace" is a span that receives comments.

    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) + ")";
    

    I've tested this solution on a Nexus and an iPad successfully. However, it behaves badly on an iPad Mini -- why behave differently on two iPad devices?

    I also noticed that the "plain svg" solution doesn't seem to detect as accurately as the RaphaelJS version. Near the edges of my SVG elements the detection just isn't very good with the plain svg detection. I'm consistently getting good results for the RaphaelJS use.

    OTOH, the RaphaelJS use is sensitive to the SVG having (fill:none). The plain SVG doesn't care if (fill:none) is set in an element. Choose your poison.

    0 讨论(0)
提交回复
热议问题