如何在mousemove事件中使用requestAnimationFrame?

时间:2014-01-21 04:57:12

标签: javascript svg mouseevent frame-rate requestanimationframe

在我的基于SVG的Web应用程序中,用户可以选择大量的形状(甚至800或更多)和在屏幕上移动它们,人们可以想象会严重影响帧速率。在阅读了requestAnimationFrame的优点之后,我从昨天起就开始尝试将其合并到我的mousemove函数中,希望通过使用节流和放大器的组合。 requestAnimationFrame,我可以达到平滑的帧速率。

Here是我在mousemove移动600 svg形状的jsFiddle。暂时忽略限制,如何将requestAnimationFrame合并到mousemove函数中。

http://jsfiddle.net/rehankhalid/5t5pX/

HTML CODE

<svg width="1200" height="800">
<symbol>
    <g id="symbol1">
    <path fill="#3ab6d1" d="M27.7,1.1C16-2,3.9,5.1,0.8,16.9s4,23.8,15.7,26.9c11.7,3.1,23.8-4,26.9-15.7C46.6,16.3,39.6,4.2,27.7,1.1z   M38.3,26.9C36,35.7,26.9,41,18,38.7C9.1,36.4,3.8,27.3,6.1,18.5C8.4,9.6,17.5,4.3,26.4,6.6C35.3,9,40.6,18,38.3,26.9z"/>
    <g fill="#d5e1db">
    <path d="m25.8,.8c2.5,.4 4.8,1.2 7,2.5l-2.9,4.6c-1.5-.8-3.1-1.4-4.8-1.7l.7-5.4z"/>
    <path d="m13.9,2.2l1.7,5.1c-1.5,.7-3,1.5-4.3,2.7l-3.8-3.9c.9-.8 1.9-1.5 2.9-2.2 1.2-.7 2.3-1.3 3.5-1.7z"/>
    </g>
    <path fill="#196275" d="m26.4,38.5l1.8,5.2c-2.5,.7-4.9,.9-7.4,.8l.6-5.4c1.6,0 3.3-.2 5-.6z"/>
    <path fill="#42aec2" d="M6.1,18.4C8.4,9.5,17.5,4.2,26.4,6.5S40.7,18,38.4,26.8C36,35.7,26.9,41,18,38.7C9.1,36.3,3.7,27.2,6.1,18.4  z"/>
    <path fill="#d2dfdd" d="m28.7,25.9l.5-4.9 9.5-1.3c0,.3 .1,.6 .2,.8 .4,2.9 0,5.8-1,8.3l-9.2-2.9z"/>
    <path fill="#1b6273" d="m19.7,29.3h4.9l2.1,9.4c-.3,.1-.6,.2-.8,.2-2.9,.6-5.7,.5-8.4-.3l2.2-9.3z"/>
    <path fill="#368098" d="m15.9,25.8l3.6,3.4-4.8,8.3c-.3-.1-.5-.3-.8-.4-2.6-1.5-4.6-3.5-6-5.9l8-5.4z"/>
    <path fill="#d2dfdd" d="m18.6,16.5l-3,3.9-8.7-4c.1-.3 .2-.5 .3-.8 1.2-2.7 3.1-4.9 5.3-6.5l6.1,7.4z"/>
    <path fill="#bde2e9" d="m26.4,32.1l-8.4-.5-4.9-6.8 2.3-8 7.7-3.2 7.3,4 1.5,8.2-5.5,6.3z"/>
    </g>
</symbol>
<g id="default">
<g id="my-element">

</g>
</g>


<g id="draggroup">

</g>

</svg>

的Javascript

document.addEventListener('mousedown', mousedown, false);


        var element = document.getElementById('my-element');
        var defaultg = document.getElementById('default');
        var mainsvg = document.getElementsByTagName('svg')[0];
        var draggroup = document.getElementById('draggroup');
        var svgns = "http://www.w3.org/2000/svg";



        var x = 0, y = 0;
        var scale = '0.25';
        for (var i = 0; i < 600; i++) {
            var useelement = document.createElementNS(svgns, "use");
            useelement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#symbol1');
            useelement.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(' + scale + ')');

            x += 12;
            if (x === 240) {
                x = 0;
                y += 12;
            }

            element.appendChild(useelement);

        }


        var bbox = element.getBBox();
        var selectionRect = document.createElementNS(svgns, "rect");
        selectionRect.setAttribute('id', 'selectionrect');
        selectionRect.setAttribute('x', bbox.x);
        selectionRect.setAttribute('y', bbox.y);
        selectionRect.setAttribute('width', bbox.width);
        selectionRect.setAttribute('height', bbox.height);
        selectionRect.setAttribute('fill', 'grey');
        selectionRect.setAttribute('opacity', '0.2');

        draggroup.appendChild(selectionRect);


        var dx = 0, dy = 0, mx = 0, my = 0;
        var rectdx = 0, rectdy = 0;
        var elementdx = 0, elementdy = 0;

        function getSvgCordinates(event) {
            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 = parseFloat(x.toFixed(3));
            y = parseFloat(y.toFixed(3));

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

        function mousedown(event) {

            if (event.target.id === 'selectionrect') {
                var svgXY = getSvgCordinates(event);
                mx = svgXY.x; // mouse down x
                my = svgXY.y;// mouse down y


                draggroup.appendChild(element);

                document.addEventListener('mousemove', mousemove, false);
                document.addEventListener('mouseup', mouseup, false);
            }
        }

        function mouseup() {
            document.removeEventListener('mousemove', mousemove, false);
            document.removeEventListener('mouseup', mouseup, false);

            draggroup.setAttribute('transform', 'translate(0,0)');

            rectdx += dx;
            rectdy += dy;
            elementdx += dx;
            elementdy += dy;

            selectionRect.setAttribute('transform', 'translate(' + rectdx + ',' + rectdy + ')');
            element.setAttribute('transform', 'translate(' + elementdx + ',' + elementdy + ')');

            defaultg.appendChild(element);

            dx = 0;
            dy = 0;
        }

        function mousemove(event) {
            var svgXY = getSvgCordinates(event);
            dx = svgXY.x - mx;
            dy = svgXY.y - my;

            draggroup.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');

        }

1 个答案:

答案 0 :(得分:1)

基本上,您需要将draggroup.setAttribute()次呼叫转移到另一个功能。由于您只需要在鼠标停止时进行动画处理,因此请添加另一个变量来指示您是否要拖动,并且只有在这种情况下才会调用requestAnimationFrame

var isDragging = false;
function update() { // New function
  if (isDragging) {
    requestAnimationFrame(update); // Call self again, if still dragging
  }
  draggroup.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
}
function mousedown(event) {
  if (event.target.id === 'selectionrect') {
    isDragging = true;
    requestAnimationFrame(update); // Start animation loop
    // existing logic here...
  }
}
function mouseup() {
  isDragging = false;
  // existing logic here...
}

您已将该群组的更新位置(dxdy)存储在单独的变量中,因此请从draggroup.setAttribute()移除mousemove()来电,添加上述修改,你应该是好的!