问题
In my SVG based web application, a user can select a large number of shapes (even 800 or more) & move them about on the screen, which as one can imagine severely impacts the framerate. After reading the merits of requestAnimationFrame
, I have been working since yesterday trying to incorporate it into my mousemove
function, with the hope that by using a combination of throttling & requestAnimationFrame
, I can get to a smooth framerate.
Here is the jsFiddle in which I am moving 600 svg shapes on mousemove
. Ignoring throttling for now, how can I incorporate requestAnimationFrame
into the mousemove
function.
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:
Basically, you'd need to move the draggroup.setAttribute()
calls to another function. Since you only need to animate when the mouse is down, add another variable to indicate whether you're dragging or not, and only call requestAnimationFrame
when that's the case.
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...
}
You're already storing the updated location for the group (dx
, dy
) in a separate variable, so remove the draggroup.setAttribute()
call from mousemove()
and add the above modifications, and you should be good!
来源:https://stackoverflow.com/questions/21249493/how-to-use-requestanimationframe-in-mousemove-event