首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >元素的svg.js动画旋转会产生意想不到的结果(可见的“抖动”)

元素的svg.js动画旋转会产生意想不到的结果(可见的“抖动”)
EN

Stack Overflow用户
提问于 2018-02-25 19:27:36
回答 1查看 231关注 0票数 1

我正在使用svg.js创建一个自行车骑手的动画。半完整版本在这里:https://pedalfuriously.neocities.org/。在使用requestAnimationFrame (而不是动画中内置的svg.js )创建动画的过程中,我遇到了一些移动和旋转svg元素的问题。

如果你看一下链接,并使用节奏滑块使骑手的踏板非常快,然后快速翻转滑块一直到零,你可以看到他的小腿以一种断开连接的方式“抖动”。真正让我头疼的是,腿在每一帧中的位置都是基于与曲柄旋转的绝对关系来确定的(而不是用一些增量时间值来确定在该帧上的运动)。

我想我已经能够确认是我的代码的哪个方面导致了这个问题。这是一个最小的例子,它没有展示确切的行为,但我认为说明了我认为是负责的那类事情:

代码语言:javascript
复制
var draw = SVG("drawing").viewbox(0, 0, 400, 400)
var origin = {
  x: 70,
  y: 70
}
var length = 60

var blueLine = draw.group()
blueLine.line(0, 0, 0 + length, 0).move(origin.x, origin.y)
  .stroke({
    color: "#00f",
    width: 4
  })
blueLine.angle = 0

var greenLine = draw.group()
greenLine.line(0, 0, 0 + length, 0).move(origin.x, origin.y)
  .stroke({
    color: "#0f0",
    width: 4
  })
greenLine.angle = 0

var previous = 0
var dt = 0
var step = function(timestamp) {
  dt = timestamp - previous
  previous = timestamp
  blueLine.angle += 0.18 * dt
  blueLine.rotate(blueLine.angle, origin.x, origin.y)
  var endX = Math.cos(toRad(blueLine.angle)) * length
  var endY = Math.sin(toRad(blueLine.angle)) * length

  // Comment out this line, and rotation works fine
  greenLine.move(endX, endY)

  greenLine.angle = blueLine.angle - 10

  // Comment out this line, and movement works fine
  greenLine.rotate(greenLine.angle, origin.x, origin.y)

  // But they don't work together. If I both move and rotate 
  // the green line, it goes in this crazy huge arc, rather 
  // than rotating neatly around the end of the blue line 
  // as expected.
  window.requestAnimationFrame(step)
}
window.requestAnimationFrame(step)

function toRad(deg) {
  return deg * (Math.PI / 180)
}
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.4/svg.js"></script>
<div id="drawing"></div>

我在实际代码中注意到的另一件事是,如果我移动腿的位置,它会改变问题的严重程度,甚至完全停止它。如果臀部一直靠近自行车的前面,问题就不会那么严重了。另外,如果我禁用小腿上的旋转,就不会有抖动。在某些位置,小腿在加载时会立即旋转出屏幕,甚至在开始任何运动之前也是如此。

我希望得到一些关于我是否误解了操纵元素的工作方式的一些指导,无论是在svg.js中,还是在一般的SVG中。

感谢矢量图形专家的好意!

这是腿的实际代码。step()函数可能是最相关的。不确定它是否会有帮助:

代码语言:javascript
复制
Rider.Leg = function(foot, front, xOffset, yOffset) {
    var upper = front ? SVGE.upperLeg : SVGE.upperLegBack
    var lower = front ? SVGE.lowerLeg : SVGE.lowerLegBack
    this.foot = foot
    this.draw = foot.draw
    this.geo = {
        upper: {
            x: this.foot.pedal.gear.x + 150,
            y: this.foot.pedal.gear.y - 750,
            length: 396
        },
        lower: {
            length: 390
        }
    }
    this.upper = this.draw.group().svg(upper).move(this.geo.upper.x, this.geo.upper.y)
        .transform({ scale: 0.95, cx: 0, cy: 0 })
    this.lower = this.draw.group().svg(lower).move(this.geo.upper.x, this.geo.upper.y)
}

// Step function does not take in a time argument. Positioning of legs is based only on
// the absolute position of other elements, none of which jiggle.
Rider.Leg.prototype.step = function () {
    var angle = this.pedalAngle() - Math.PI
    var ha = this.scaleneAngle(this.geo.lower.length, this.geo.upper.length, this.pedalDistance())
    var ka = this.scaleneAngle(this.pedalDistance(), this.geo.lower.length, this.geo.upper.length)
    var x = this.geo.upper.length * Math.cos(ha + angle)
    var y = this.geo.upper.length * Math.sin(ha + angle)
    this.upper.rotate(Drive.toDeg(angle + ha), 0, 0)
    this.lower.move(this.geo.upper.x + x, + this.geo.upper.y + y)
    this.lower.rotate(Drive.toDeg(angle + ha + ka - Math.PI), 0, 0)

}

// Gets the distance between the hip joint and the pedal
Rider.Leg.prototype.pedalDistance = function () {
    var pos = this.foot.getPos()
    var xDist = this.geo.upper.x - pos.x
    var yDist = this.geo.upper.y - pos.y
    return Math.hypot(xDist, yDist)
}

// Gets the angle between the hip joint and the pedal 
Rider.Leg.prototype.pedalAngle = function () {
    var pos = this.foot.getPos()
    var xDist = this.geo.upper.x - pos.x
    var yDist = this.geo.upper.y - pos.y
    return Math.atan2(yDist, xDist)
}

Rider.Leg.prototype.scaleneAngle = function (a, b, c) {
    return Math.acos(((b * b) + (c * c) - (a * a)) / (2 * b * c))
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-28 17:34:05

当您在组上调用move()时,它在内部表示为翻译。svg.js想出了一种疯狂的方法,可以将对象转换到新的位置,而不需要更改任何其他转换。这通常不会奏效。尤其是当你旋转的时候。

这就是为什么你应该避免这些绝对转换,而使用相对转换。只需在每次移动前调用untransform并从零开始。然后您可以执行以下操作:

代码语言:javascript
复制
greenLine.transform({x:endX, y:endY, relative: true})

将线移动一定的量。这应该会工作得更好。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48972883

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档