簡體   English   中英

鼠標移動時找到點的最有效方法

[英]Most efficient way of finding point upon mousemove

將鼠標懸停在SVG圖像路徑上時,我希望鼠標移動以標識光標下方的相關點。

邏輯:當前的邏輯是瀏覽器計算SVG圖像路徑坐標。 共原點存儲在2d數組中。 將這些坐標與mousemove坐標進行比較。 當兩者匹配時,在匹配的目標位置會出現一個預渲染的圓圈。

關心:我主要擔心的是這種動作對性能的影響,尤其是當我參加我目前正在從事的項目時。 如何在瀏覽器中簡化此過程。 我可以使用“限制”來減少瀏覽器必須執行的計算數量,但是我主要關心的是上面的邏輯。

Jsfiddle:

http://jsfiddle.net/a4tb8/

HTML:

<div id="svgContainer" style="float: left;">
    <svg viewBox="0 0 800 600" height="600" width="800">
    <path class="clipPath clipNeck" fill="none" stroke="#848484" stroke-width="1.0244" d="M329.66,99.99l22.1,4c0,0-6.9,45.5-2.1,51.6
          c0,0-11.75,72.7-10.05,83.7c0,0,18.8,81.1,17.3,85.4H238.43c-1.5-4.3,17.3-85.4,17.3-85.4c1.7-11-10.12-83.7-10.12-83.7
          c4.8-6.1-2.1-51.6-2.1-51.6l22.1-4"/>

    </svg>
</div>
<div id="stats" style="float: left;">
    <div id="total_nodes">                
    </div>
    <div id="mouse_cordinates">                
    </div>
    <div id="svg_cordinates">                
    </div>

    <div id="response_time">                
    </div>

    <div id="zoom" data-action="zoomin" style="width: 82px;height: 25px;background-color: red;border: 2px solid #000;cursor: pointer;display: none">
        Zoom In
    </div>
</div>

Js:

            var pointsArray = new Array();
            var nodes = new Array();
            var zoom = document.getElementById('zoom');

            function createNode(type, attributes) {
                var node = document.createElementNS('http://www.w3.org/2000/svg', type);
                if (type === 'image')
                    attributes.preserveAspectRatio = 'none';
                if (typeof attributes !== undefined)
                    setAttributes(node, attributes);
                return node;
            }

            function setAttributes(el, attributes) {
                for (var attribute in attributes) {
                    if (attributes[attribute] !== null && typeof (attributes[attribute]) !== "undefined") {
                        el.setAttribute(attribute, attributes[attribute]);

                    }
                }
            }

            function roundDecimalNumber(number, places) {
                var place;
                if (places === 0)
                    place = places;
                else if (!places)
                    place = 2;
                else
                    place = places;

                number = parseFloat(number);
                number = number.toFixed(place);
                number = parseFloat(number);
                return number;
            }

            function showStats(count) {
                var total_nodes = document.getElementById('total_nodes');
                total_nodes.innerHTML = 'Total Nodes = ' + count;
                zoom.style.display = 'block';
            }

            function fetchTemplatePath() {
                var path = document.getElementsByClassName('clipPath clipNeck')[0];
                if (path) {

                    var length = Math.ceil(path.getTotalLength());
                    var point, tx, ty;
//                                var tab = TabController.currentTab.id;
//                                var view = TabController.currentView;


                    var path2 = createNode('path', {
                        id: 'path_node_test',
                        d: '',
                        stroke: 'red',
                        'stroke-width': 1,
                        fill: 'none'
                    });
                    document.getElementsByTagName('svg')[0].appendChild(path2);

                    var i = 0;
                    var incrementor = 1;
                    var d = '';
                    var intervalVar = setInterval(function() {
                        point = path.getPointAtLength(i);
                        tx = roundDecimalNumber(point.x, 0);
                        ty = roundDecimalNumber(point.y, 0);




                        cordinatesXY = {
                            x: tx,
                            y: ty
                        };

                        if (!nodes[tx]) {
                            nodes[tx] = new Array();
                            nodes[tx][ty] = 1;
                        }
                        else {
                            if (!nodes[tx][ty]) {
                                nodes[tx][ty] = 1;
                            }

                        }

                        if (i === 0)
                            d = 'M ' + tx + ' ' + ty + ' L ';
                        else
                            d += tx + ' ' + ty + ' ';
                        path2.setAttribute('d', d);
                        pointsArray.push(cordinatesXY);
                        i += incrementor;

                        if (i > length) {
                            clearInterval(intervalVar);
                            showStats(i);

                        }
                    }, 1);

                }
            }

            function matchSurrondings(x, y) {
                var flag = false;
                var radius = 10;//boxes left, right, up & down;

                for (var i = x; i <= (x + radius); i++) {// right
                    if (nodes[i]) {
                        if (nodes[i][y]) {
                            return {x: i, y: y};
                        }
                    }
                }

                 for (var i = x; i >= (x - radius); i--) {// left
                    if (nodes[i]) {
                        if (nodes[i][y]) {
                            return {x: i, y: y};
                        }
                    }
                }

                for (var i = y; i >= (y - radius); i--) {// top
                    if (nodes[x]) {
                        if (nodes[x][i]) {
                            return {x: x, y: i};
                        }
                    }
                }

                for (var i = y; i <= (y + radius); i++) {// down
                    if (nodes[x]) {
                        if (nodes[x][i]) {
                            return {x: x, y: i};
                        }
                    }
                }


                return flag;
            }

            function matchMouseCordinatesWithNodes(x, y) {

                if (nodes[x]) {
                    if (nodes[x][y]) {
                        return {x: x, y: y};
                    }
                }

                var value=false;
                value = matchSurrondings(x, y);

                return value;
            }

            function getSvgCordinates(event) {
                if (!event) {
                    return  {
                        x: 0,
                        y: 0
                    };
                }
                var mainsvg = document.getElementsByTagName('svg')[0];
                var m = mainsvg.getScreenCTM();
                var p = mainsvg.createSVGPoint();

                var x, y;

                x = event.pageX;
                y = event.pageY;

                p.x = x;
                p.y = y;
                p = p.matrixTransform(m.inverse());

                x = p.x;
                y = p.y;

                x = roundDecimalNumber(x,0);
                y = roundDecimalNumber(y,0);

                return {x: x, y: y};
            }

            function createCircleNode(x, y) {
                var circle_node = document.getElementById('circle_node');
                if (!circle_node) {
                    circle_node = createNode('circle', {
                        id: 'circle_node',
                        cx: x,
                        cy: y,
                        r: 3,
                        fill: 'green',
                        stroke: 'none'
                    });
                    document.getElementsByTagName('svg')[0].appendChild(circle_node);
                }
                else {
                    circle_node.setAttribute('cx', x);
                    circle_node.setAttribute('cy', y);
                }
            }

            function defaultmousemove(event) {
                var starttime=Date.now();
                var mouse_cordinates = document.getElementById('mouse_cordinates');
                if (mouse_cordinates) {
                    mouse_cordinates.innerHTML = 'Mouse Co-ordinates = X:' + event.pageX + ' , Y:' + event.pageY;
                }
                var svgXY = getSvgCordinates(event);
                var svg_cordinates = document.getElementById('svg_cordinates');
                if (svg_cordinates) {
                    svg_cordinates.innerHTML = 'SVG Co-ordinates = X:' + svgXY.x + ' , Y:' + svgXY.y;
                }

                var nodes_matched = matchMouseCordinatesWithNodes(svgXY.x, svgXY.y);
                if (nodes_matched)
                    createCircleNode(nodes_matched.x, nodes_matched.y);

                var endTime=Date.now();
                var diff=endTime-starttime;
                diff=diff/1000;// in secs;
                var response_time=document.getElementById('response_time');
                response_time.innerHTML='Calculation completed in '+diff+' secs';
            }



            function zoomIn() {
                zoom.setAttribute('data-action', 'zoomout');
                zoom.innerHTML = 'Zoom Out';
                var mainsvg = document.getElementsByTagName('svg')[0];
                mainsvg.setAttribute('viewBox', '100 100 400 200');

            }

            function zoomOut() {
                zoom.setAttribute('data-action', 'zoomin');
                zoom.innerHTML = 'Zoom In';
                var mainsvg = document.getElementsByTagName('svg')[0];
                mainsvg.setAttribute('viewBox', '0 0 800 600');
            }

            function defaultmousedown(event) {
                event.cancelBubble = true;
                event.preventDefault();
                if (event.target.hasAttribute('data-action')) {
                    var action = event.target.getAttribute('data-action');
                    if (action === 'zoomin') {
                        zoomIn();
                    }
                    else if (action === 'zoomout') {
                        zoomOut();
                    }
                }
            }

            fetchTemplatePath();
            var mainsvg = document.getElementsByTagName('svg')[0];
            mainsvg.addEventListener('mousemove', defaultmousemove, false);
            document.addEventListener('mousedown', defaultmousedown, false);

如果路徑少於幾百個點,我看不出計算有問題。

但是,滾動所有瀏覽器的網頁時,鼠標和SVG坐標不會跟蹤。

請嘗試以下操作以獲取這些值:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>SCR X,Y using SVGPoint &amp; getScreenCTM</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
<h4>SCR X,Y using SVGPoint &amp; getScreenCTM</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
  Assume the SVG image is contained in a DIV inline within the HTML5 document. However neiher the SVG <b>viewBox</b> nor its <b>width/height</b> are the same as the DIV container.
Therfore you must use getScreenCTM to get the x,y values(scr).
</div>
<table>
<tr><td align=left>
A 400x400 DIV containing SVG.<br />
SVG has a viewBox=0 0 2000 2000
</td>
<td align=left>
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG" width="100%" height="100%" viewBox="0 0 2000 2000" onmousemove="getXY(evt)"  >
<circle r=20 fill=black cx=200 cy=200 />
</svg>
</div>
</td>
<td align=left>
<table style='font-family:lucida console'>

<tr><td colspan=4><b>SVG clientX/Y - DIV offset</b></td></tr>
<tr style='font-size:110%'>
<td align=right>svg X:</td>   <td><input style='border:2px solid black;font-size:120%'  type=text id=svgOffsetXValue size=1 /></td>
<td><input style='border:2px solid black;font-size:120%'  type=text id=svgOffsetYValue size=1 /></td><td align=left>:svg Y</td>
</tr>

<tr><td colspan=4><b>SVGPoint/getScreenCTM</b></td></tr>
<tr style='font-size:110%'>
<td align=right>scr X:</td> <td><input style='border:2px solid black;font-size:120%'  type=text id=scrXValue size=1 /></td>
<td><input style='border:2px solid black;font-size:120%'  type=text id=scrYValue size=1 /></td><td align=left>:scr Y</td>
</tr>
</table>
</td>
</tr>
</table>
<br />SVG Source:<br />
<textarea id=svgSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:200px'></textarea>
<br />Javascript:<br />
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<div id='browserDiv' style='padding:3px;position:absolute;top:5px;left:5px;background-color:gainsboro;'></div>
<script id=myScript>
//---mouse move---
function getXY(evt)
{
    var rect = svgDiv.getBoundingClientRect();
    svgOffsetXValue.value=evt.clientX-rect.left
    svgOffsetYValue.value=evt.clientY-rect.top

    var pnt = mySVG.createSVGPoint();
    pnt.x = evt.clientX;
    pnt.y = evt.clientY;

    var sCTM = mySVG.getScreenCTM();
    var PNT = pnt.matrixTransform(sCTM.inverse());
    scrXValue.value=PNT.x
    scrYValue.value=PNT.y
}

</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
    svgSourceValue.value=svgDiv.innerHTML
    jsValue.value=myScript.text
}
</script>

</body>

</html>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM