简体   繁体   中英

Why does rotating element make it bounce?

I've got an svg element and I'm adding a simple rotation attribute to it. Problem is, I want the element to rotate relative to center of itself, not the whole svg, so I specify x and y for rotate, but it has a weird bouncy effect.

 let currentAngle = 0; function rotate() { d3.select('.group1') .transition() .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; currentAngle += 90; return `rotate(${currentAngle}, ${rx}, ${ry})`; }); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <svg viewbox="0 0 1600 1600" width="500" height="500"> <g class="group1" onclick="rotate()"> <rect x="250" y="250" width="100" height="100" /> <circle cx="420" cy="300" r="50" /> </g> </svg> 

As an alternative, I tried adding transform-origin on css, something like transform-origin: 800px 800px; (but with valid center px of course) and while it works in Chrome, it doesn't work in IE and Safari.

Why is supplying x and y on rotate making my element bounce?

There are a few questions floating around that deal with this issue. Here's one that explains a bit what's going on: D3.js animate rotation

The way Mike Bostock does it here: https://bl.ocks.org/mbostock/3305854 is by placing the object in a <g> that is translated to the position you want and then rotating. This might be the easiest way to get a nice animation. For example:

 let currentAngle = 0; function rotate() { d3.select('rect') .transition() .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; currentAngle += 45; return `rotate(${currentAngle}, ${rx}, ${ry})`; }); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <svg viewbox="0 0 1600 1600" width="500" height="500"> <g transform="translate(250, 250)"> <rect x="-50", y="-50" width="100" height="100" onclick="rotate()" /> </g> </svg> 

if you select by id or by class and rotate it slowly, you will see the red dot in middle rotation move by little, but select by id i thing it more stable not like select by class it bouncing harder

 let currentAngle = 0; let currentAngle2 = 0; function rotate() { d3.select('#aa') .transition() .duration(300) .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') currentAngle += 10; return `rotate(${currentAngle}, ${rx}, ${ry})`; }); } function rotate2() { d3.selectAll('.aa') .transition() .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') currentAngle2 += 10; return `rotate(${currentAngle2}, ${rx}, ${ry})`; }); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <svg viewbox="0 0 1600 1600" width="500" height="500"> <g id ='aa' onclick="rotate()"> <rect x="100", y="100" width="100" height="100" /> <circle cx="250" cy="150" r="50"/> </g> <g class ='aa' onclick="rotate2()"> <rect x="600", y="100" width="100" height="100" /> <circle cx="750" cy="150" r="50" /> </g> </svg> 

then if you bouncing it with harsh value(big value) you will defintely see the red dot bouncing, but once again select by id doing more stable

 let currentAngle = 0; let currentAngle2 = 0; function rotate() { d3.select('#aa') .transition() .duration(300) .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') currentAngle += 90; return `rotate(${currentAngle}, ${rx}, ${ry})`; }); } function rotate2() { d3.selectAll('.aa') .transition() .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') currentAngle2 += 90; return `rotate(${currentAngle2}, ${rx}, ${ry})`; }); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <svg viewbox="0 0 1600 1600" width="500" height="500"> <g id ='aa' onclick="rotate()"> <rect x="100", y="100" width="100" height="100" /> <circle cx="250" cy="150" r="50"/> </g> <g class ='aa' onclick="rotate2()"> <rect x="600", y="100" width="100" height="100" /> <circle cx="750" cy="150" r="50" /> </g> </svg> 

you must make it slowly to rotated to end point, you can make tween using d3.interpolate , and boom... it rotated perfecly by id or by class

 let currentAngle = 0; let currentAngle2 = 0; function rotate() { d3.select('#aa') .transition() .duration(300) .attrTween("transform", tween); /* .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') currentAngle += 10; // console.log(rx,ry,currentAngle) return `rotate(${currentAngle}, ${rx}, ${ry})`; }); */ function tween(d, i, a) { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') var e = `rotate(${currentAngle}, ${rx}, ${ry})` currentAngle += 90; var o = `rotate(${currentAngle}, ${rx}, ${ry})` return d3.interpolateString(e,o); } } function rotate2() { d3.selectAll('.aa') .transition() .duration(300) .attrTween("transform", tween); /* .attr('transform', function() { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') currentAngle2 += 10; // console.log(rx,ry,currentAngle) return `rotate(${currentAngle2}, ${rx}, ${ry})`; }); */ function tween(d, i, a) { let bb = this.getBBox(); let rx = bb.x + bb.width / 2; let ry = bb.y + bb.height / 2; d3.select(this).append('circle') .attr('cx',rx) .attr('cy',ry) .attr('r',20) .attr('fill','red') var e = `rotate(${currentAngle2}, ${rx}, ${ry})` currentAngle2 += 90; var o = `rotate(${currentAngle2}, ${rx}, ${ry})` return d3.interpolateString(e,o); } } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <svg viewbox="0 0 1600 1600" width="500" height="500"> <g id ='aa' onclick="rotate()"> <rect x="100", y="100" width="100" height="100" /> <circle cx="250" cy="150" r="50"/> </g> <g class ='aa' onclick="rotate2()"> <rect x="600", y="100" width="100" height="100" /> <circle cx="750" cy="150" r="50" /> </g> </svg> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM