最有效的方法是在鼠标移动时找到点

时间:2014-05-12 05:46:24

标签: javascript arrays performance svg mouseevent

将鼠标悬停在SVG图像路径上时,我希望鼠标移动来识别光标下方的相关点。

LOGIC: 当前的逻辑是浏览器计算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);

1 个答案:

答案 0 :(得分:0)

如果路径小于几百点,我就不会发现计算有问题。

但是,鼠标和svg坐标不会跟踪所有broswers的网页滚动时间。

尝试以下方法获取这些值:

<!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>