Javascript d3命运之轮

Javascript d3命运之轮,javascript,d3.js,Javascript,D3.js,我正在尝试使用d3.js创建一个可以在移动设备上工作的交互式命运之轮。以下是我到目前为止所做的工作: 现在,我正试图使它,以便您可以点击拖动饼图切片和“旋转”它周围,只要鼠标是下来。在鼠标移动期间,我使用Math.atan2获取圆上两点之间的角度,并相应地更改饼图角度。看起来我已经差不多做到了,但是有一个延迟/抖动。我能做些什么来平滑它,使它看起来像这样吗 理想情况下,从长远来看,我希望mouseup事件为旋转创建某种速度,并且无论指向上方的切片是什么,都能够被查询 但现在,我只是尝试创建一个平

我正在尝试使用d3.js创建一个可以在移动设备上工作的交互式命运之轮。以下是我到目前为止所做的工作:

现在,我正试图使它,以便您可以点击拖动饼图切片和“旋转”它周围,只要鼠标是下来。在鼠标移动期间,我使用Math.atan2获取圆上两点之间的角度,并相应地更改饼图角度。看起来我已经差不多做到了,但是有一个延迟/抖动。我能做些什么来平滑它,使它看起来像这样吗

理想情况下,从长远来看,我希望mouseup事件为旋转创建某种速度,并且无论指向上方的切片是什么,都能够被查询


但现在,我只是尝试创建一个平滑的拖动过程。

您之所以会感到“不安”,是因为您使用了鼠标坐标。您要做的是使用一个固定点,即车轮的中心

 var thisX = d3.event.x - lastX,
       thisY = d3.event.y - lastY;
     angleDeg = Math.atan2(lastY - d3.event.y, lastX - d3.event.x) // * 180 / Math.PI) - curAngle
     if (angleDeg < 0) angleDeg += 2 * Math.PI;
     angleDeg = angleDeg * 180 / Math.PI;
     angleDeg = angleDeg - curAngle + finishAngle; //reset to 0 and add last rotation calculated
     if (angleDeg < 0) angleDeg += 360;
     d3.select('#degrees').text(Math.round(angleDeg))
     svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + angleDeg + "," + 0 + "," + 0 + ")");
因此,与其使用d.event.x/y更新lastX和lastY,不如将其保持为:

var lastX = width/2; //center points of circle
var lastY = height/2;
在您的算法中使用此选项,如下所示:

if (isDown) {
     var thisX = d3.event.x - lastX,
       thisY = d3.event.y - lastY;
     var angleDeg = Math.atan2(lastY - d3.event.y, lastX - d3.event.x) * 180 / Math.PI;
     svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + angleDeg + "," + 0 + "," + 0 + ")");
   }
我把这个放在JSFIDLE上,因为plnkr不能正常工作,有鼠标事件等等:

即使这样也不完美

基本上,这里发生的是,获取鼠标坐标并旋转到该坐标。但是你不希望这样,你只希望它在你移动鼠标时移动,即使这样,你也只希望它按你移动光标的量移动,而不是跳转到光标(如果这有意义的话:P)

所以你们要做的是从0开始,若你们在鼠标按下的时候移动光标,保存旋转的位置,这样当你们再次开始时,你们可以从你们离开的地方开始。这很难解释

无论如何,当鼠标按下时,保存鼠标坐标和圆心之间的角度:

var thisX = d3.event.x - lastX,
     thisY = d3.event.y - lastY;
   curAngle = Math.atan2(lastY - d3.event.y, lastX - d3.event.x)  
   if (curAngle < 0) curAngle += 2 * Math.PI; //make sure its positive
   curAngle = curAngle * 180 / Math.PI; //change to degrees

工作小提琴:

感谢您的详细回复!这很有道理,而且效果也很好。我还想问你是否知道有一种方法可以对触摸事件做同样的事情。touchstart/end事件有X,Y吗?@QuantumRich看看这个例子
 var thisX = d3.event.x - lastX,
       thisY = d3.event.y - lastY;
     angleDeg = Math.atan2(lastY - d3.event.y, lastX - d3.event.x) // * 180 / Math.PI) - curAngle
     if (angleDeg < 0) angleDeg += 2 * Math.PI;
     angleDeg = angleDeg * 180 / Math.PI;
     angleDeg = angleDeg - curAngle + finishAngle; //reset to 0 and add last rotation calculated
     if (angleDeg < 0) angleDeg += 360;
     d3.select('#degrees').text(Math.round(angleDeg))
     svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + angleDeg + "," + 0 + "," + 0 + ")");
 finishAngle = angleDeg;