Javascript 画布上的Atan2旋转口吃+;SVG路径

Javascript 画布上的Atan2旋转口吃+;SVG路径,javascript,math,canvas,svg,Javascript,Math,Canvas,Svg,之前,我用svg构建了一个运动路径,但注意到在移动设备上的渲染性能不是很好。我决定将运动路径转换为canvas,这将提供更好的性能 我选择使用svg创建我的canvas路径的克隆,这样我就可以使用getPointAtLength()和getTotalLength()方法来获得采样点的相应x,y值和canvas路径的长度 问题在于,使用getPointAtLength采样后返回的值似乎会导致不规则旋转 我有一种预感,这与我使用getPointAtLength()方法沿路径采样的位置不同有关 如何修

之前,我用svg构建了一个运动路径,但注意到在移动设备上的渲染性能不是很好。我决定将运动路径转换为
canvas
,这将提供更好的性能

我选择使用
svg
创建我的
canvas
路径的克隆,这样我就可以使用
getPointAtLength()
getTotalLength()
方法来获得采样点的相应x,y值和
canvas
路径的长度

问题在于,使用
getPointAtLength
采样后返回的值似乎会导致不规则旋转

我有一种预感,这与我使用
getPointAtLength()
方法沿路径采样的位置不同有关

如何修复从
atan2
返回的值,使其沿路径平滑线性旋转

var canvas=document.body.querySelector('.loader\uu canvas');
var source=document.body.querySelector('.loader\uu source');
var ctx=canvas.getContext(“2d”);
var角;
无功转速=0.5;
增值税;
var deltaY;
var-nextCoords;
var prevCoords;
var偏移=0;
var distance=source.getTotalLength();
render();
函数render(){
//一旦偏移量超过路径距离,则重置回路
如果(偏移量>=距离){
偏移量=1*速度;
}否则{
偏移量+=1*速度;
}
//从所有以前的操作中清除画布
clearRect(0,0,canvas.width,canvas.height);
//绘制对象附着到的环
ctx.beginPath();
ctx.线宽=10;
ctx.moveTo(250250);
ctx.lineTo(250300);
ctx.arc(30030050,Math.PI,-Math.PI/2,真);
ctx.lineTo(200250);
ctx.arc(20020050,Math.PI/2,0);
ctx.lineTo(250250);
ctx.strokeStyle='#ddd';
ctx.stroke();
ctx.closePath();
//保存当前转换矩阵以备将来重置
ctx.save();
//计算对象的坐标和角度,
//如果prevCoords未定义:指定初始值
prevCoords=nextCoords | | source.getPointAtLength(偏移量);
nextCoords=source.getPointAtLength(偏移量);
角度=Math.atan2(
(nextCoords.y-prevCoords.y),(nextCoords.x-prevCoords.x)
)+(Math.PI/2);
//应用变换
翻译(nextCoords.x,nextCoords.y);
ctx.旋转(角度);
//绘制路径对象
ctx.beginPath();
弧(0,0,20,0,数学π);
ctx.fillStyle='#f63';
ctx.fill();
ctx.closePath();
//还原转换
ctx.restore();
//环路
请求动画帧(渲染);
}
html,
身体{
保证金:0;
填充:0;
宽度:100%;
身高:100%;
}
.loader\uuu画布{
显示:块;
宽度:100%;
最大宽度:500px;
最大高度:500px;
保证金:自动;
边框:1px实心#ccc;
}
.loader\uuu源{
填充:透明;
行程:#ddd;
笔画宽度:10;
}

像素位置

我不确定为什么会发生这种情况,尽管我使用了一些有缺陷的逻辑并意外地找到了解决方案。要解决这个问题,请找到距离偏移稍远的点。我添加了4个像素,得到了上一个位置
prevCoords=source.getPointAtLength((偏移+4)%distance)我向前看,以确保负偏移不会打乱开始

即使移动偏移量,方向仍然有点粗糙。所以我给角度添加了一个简单的平滑算法。保留一个单独的值
angleReal
以显示平滑的角度,保留一个
angleDelta
以平滑运动。有一个
拖动
加速
组件决定了行为。不同的值将影响平滑效果。如果
drag
的值超过0.5,平滑将开始振荡(有时效果不错,但在这种情况下不需要)

还有一个问题是
atan2
将角度
-Math.PI
返回到
Math.PI
平滑将
-Math.PI
Math.PI
视为两个不同的角度,但是它们是相同的,所以我添加了一个测试,以确保从
-Math.PI
Math.PI
的转换不会使平滑旋转对象

下面是你的代码,我修改了一些位来平滑对象的方向。这不是唯一的解决方案,但它是一个我将用于动画

更新

经过进一步调查,我发现函数
getPointAtLength
存在故障

使用以下代码(在代码上下文中),我将
getTotalLength
给出的距离与使用
getPointAtLength
对路径进行采样所覆盖的距离进行比较

  var distance = source.getTotalLength(); // get the distance along the path;
  var next;         // next point 
  var dist = 0;     // the measured distance
  var step = 1;     // path sample rate
  var last = source.getPointAtLength(0);      // get the first point

  for(var i = step; i < distance; i+= step){  // sample points 
      next = source.getPointAtLength(i);      // get a point at offset i

      // get and sum the distance between the two samples 
      dist += Math.sqrt(Math.pow(next.x-last.x,2)+Math.pow(next.y-last.y,2));
      last = next;   // move the current sample to the last
  }
  // sample the last remaining bit 
  next = source.getPointAtLength(distance);
  // add that distance.
  dist += Math.sqrt(Math.pow(next.x-last.x,2)+Math.pow(next.y-last.y,2));
  // show result
  console.log("Measured:"+dist.toFixed(2)+" Given:"+distance.toFixed(2))
html,
身体{
保证金:0;
填充:0;
宽度:100%;
身高:100%;
}
.loader\uuu画布{
显示:块;
宽度:100%;
最大宽度:500px;
最大高度:500px;
保证金:自动;
边框:1px实心#ccc;
}
.loader\uuu源{
填充:透明;
行程:#ddd;
笔画宽度:10;
}


谢谢!我修改了您提供的一些代码,但您为我指明了正确的方向。记录
getPointAtLength()
似乎确实会为我提供浮动距离中的坐标,如上所述,使用
%
操作符获取路径距离以外的坐标是一个好主意。现在一切似乎都很好,振荡运动消失了,不幸的是我不完全理解为什么。增加
速度
变量也以某种方式消除了路径上某些点的振荡运动。我最好修正我的答案,因为我只是猜测坐标是整数。。如果MDN和你的日志显示不是这样,那么就是这样。非常感谢迄今为止所有的帮助!我用另一个现在可用的例子更新了我的帖子。剩下的唯一问题是为什么
Math.atan2(y,x)
给了我这样的振荡旋转