【问题标题】:Why does rotating element make it bounce?为什么旋转元件会使其弹跳?
【发布时间】:2017-09-05 16:58:36
【问题描述】:

我有一个 svg 元素,我正在向它添加一个简单的旋转属性。 问题是,我希望元素相对于自身中心旋转,而不是整个 svg,所以我指定 x 和 y 进行旋转,但它有一个奇怪的弹性效果。

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>

作为替代方案,我尝试在 css 上添加 transform-origin,类似于 transform-origin: 800px 800px;(但当然具有有效的中心 px),虽然它在 Chrome 中有效,但在 IE 和 Safari 中无效。

为什么在旋转时提供 x 和 y 会使我的元素反弹?

【问题讨论】:

  • 这是一个不使用 d3 的示例,它可以工作 jsfiddle.net/LukaszWiktor/haye1xj2
  • 我最终使用gsap 来代替,因为它使用了似乎在 IE 8 中有效的矩阵转换。

标签: javascript d3.js


【解决方案1】:

围绕这个问题存在一些问题。这里有一个解释一下发生了什么:D3.js animate rotation

Mike Bostock 在此处的操作方式:https://bl.ocks.org/mbostock/3305854 是将对象放在 &lt;g&gt; 中,该对象被转换为您想要的位置,然后旋转。这可能是获得漂亮动画的最简单方法。例如:

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>

【讨论】:

  • 嗨,马克,谢谢。这个解释是有道理的(有点)所以也谢谢你。为了这个问题,我简化了我的场景,但是我已经在一个组中有一堆元素,我正在轮换整个组。 (我已经更新了我的代码 sn-p 以更好地反映我的情况) - 我认为我无法将您的代码翻译为适用于整个组。 &lt;g&gt; 似乎不想遵守上述规则?这是显示我的修改的代码,它添加了另一个新的&lt;g&gt;codepen.io/anon/pen/ayrdYg
【解决方案2】:

看看这个不同

如果你 select idclassrotate 慢慢移动,你会看到中间旋转的红点一点点移动,但 select id 我觉得它更稳定不像select by class 它弹跳得更厉害

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>

那么如果你用苛刻的值(大值)弹跳它,你肯定会看到红点弹跳,但id 再次select 做得更稳定

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>

解决方案

你必须让它慢慢旋转到终点,你可以做补间 使用d3.interpolate 和繁荣......它完美地旋转了idclass

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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多