使用SVG和d3展开圆,将其转换为直线

使用SVG和d3展开圆,将其转换为直线,svg,d3.js,Svg,D3.js,在一个项目中,我们试图使一个圆在沿线性路径旋转时变成一条线(然后再转回来),就像轮胎在道路上滚动时旋转和平移一样,或者弯曲的前指伸展并重新旋转到手掌中 在这里,我有一个静态SVG(顶部圆圈),它沿着HTML中定义的线性黑色路径(位于圆圈上方,以模拟手指延伸)旋转 我还使用d3生成一个由连接点组成的“圆”(通过@ChrisJamesC,如果你点击圆,它可以展开),并进行平移和旋转 在函数moveAlongLine中,单击紫色线时: function moveAlongLine() { circ

在一个项目中,我们试图使一个圆在沿线性路径旋转时变成一条线(然后再转回来),就像轮胎在道路上滚动时旋转和平移一样,或者弯曲的前指伸展并重新旋转到手掌中

在这里,我有一个静态SVG(顶部圆圈),它沿着HTML中定义的线性黑色路径(位于圆圈上方,以模拟手指延伸)旋转

我还使用d3生成一个由连接点组成的“圆”(通过@ChrisJamesC,如果你点击圆,它可以展开),并进行平移和旋转 在函数moveAlongLine中,单击紫色线时:

function moveAlongLine() {
  circle.data([lineData])
  .attr("transform", "translate(78.5,0) rotate(-90, 257.08 70) ")
  .duration(1000)
  circle.on("click", transitionToCircle)
}
第一个问题是,
.duration(1000)
无法识别,并抛出一个
未捕获类型错误:对象[Object Array]在控制台中没有方法“duration”
,因此SVG中的
dur
静态定义与JS/D3中的动态设置之间存在差异,但这是次要的

另一个问题是,转换属性是否应该像静态循环中那样相互抽象?在静态圆中,平移是一个动画,旋转是另一个动画,它们只是具有相同的星形和持续时间,所以它们一起设置动画。你将如何在d3中应用这两种方法

我无法接受的挑战是,如何让它向上展开(并重新回滚),静态点是圆的上圆心,也是直线上最左边的点

这些似乎更好:

  • 我应该尝试让展开动画在旋转的同时发生?这似乎需要以逐步/顺序为基础
  • 或考虑一个八角形(定义为一个路径),如果它旋转7个边,则6个,然后5个…对多面体上相当多的点执行此操作?(圆圈只需要大约50个像素,所以100个点就足够了)这是小提琴中的中间示例。也许是通过编程实现的
  • 或者这让我想到了另一种方式:(在八角形的情况下),我可以有8条线路径(没有Z,只是一个额外的闭合点),并且在它们之间过渡?像这样
  • 或者有什么关键帧要做?我已经用Synfig制作了一个动画,但是我不确定如何将它放到SVG中。如果您可以将synfig文件转换为SVG,那么synfig文件就可以了,但是使用
    xsltproc
    时,xsl文件不能正确地将其转换为SVG
这看起来很复杂,但很有潜力:

  • 定义点所遵循的路径(可能是具有相同数量参考点的贝塞尔曲线),并使参考点动态平移。。。有关概念示例,请参见
这似乎复杂而笨拙:

  • 让一个真实的圆圈滚动而过,前面有一个不断增长的面具,同时一条线也在不断增长
几点注意:

  • d3圆中的点数可以在JS中调整,当前设置为较低,以便您可以在渲染中看到一点,以验证是否发生了旋转(很像顶部圆中的渐变)
  • 这是为了帮助学生学习数字线和圆之间的守恒关系,特别是帮助学习分数。对于概念应用程序,请查看我们的原型,这将有助于切换表示,帮助您更好地了解
(注意:这应该在注释中,但间距不够)
  • 圆圈动画
    试着从SO开始。需要调整它,使角度从180开始,在相同的位置(线4-6,19)结束,并在每个交互上沿X轴(线11)移动。更改
    我最终使用了与问题中相同的生成圆圈的函数,并做了一些思考,似乎我想要一个像手指这样展开的动画。这让我想到了在这个世界上实现它所需要的数学和思想

    答案是数组数组,每个嵌套数组都是处于不同状态的一条线,然后通过在点之间插值来设置动画

    var circleStates = [];
    for (i=0; i<totalPoints; i++){
        //circle portion
        var circleState = $.map(Array(numberOfPoints), function (d, j) {
          var x = marginleft + radius + lineDivision*i + radius * Math.sin(2 * j * Math.PI / (numberOfPoints - 1));
          var y =  margintop + radius - radius * Math.cos(2 * j * Math.PI / (numberOfPoints - 1));
          return { x: x, y: y};
        })
        circleState.splice(numberOfPoints-i);
        //line portion
        var lineState = $.map(Array(numberOfPoints), function (d, j) {
          var x = marginleft + radius + lineDivision*j;
          var y =  margintop;
          return { x: x, y: y};
        })
        lineState.splice(i);
        //together
        var individualState = lineState.concat(circleState);
        circleStates.push(individualState);
    }
    
    var circleStates=[];
    
    对于(i=0;i更新:对于1,您可以使用
    来包装路径。因此,您所需要的只是将偏移量添加到与2中的x值相匹配的线11中的x轴。因此您是说有一个随圆旋转的遮罩?我们的好处是只需为chrome开发,因为它是唯一支持web音频套件的浏览器。这很好k您也可以将相同的数组与一些push-pop-map函数一起使用,但这可能会使事情变得更难理解,并且比您实际执行的操作更慢
    function all() {
        for(i=0; i<numberOfPoints; i++){
          circle.data([circleStates[i]])
            .transition()
            .delay(dur*i)
            .duration(dur)
            .ease("linear")
            .attr('d', pathFunction)            
        }
    }
    function reverse() {
        for(i=0; i<numberOfPoints; i++){
          circle.data([circleStates[numberOfPoints-1-i]])
            .transition()
            .delay(dur*i)
            .duration(dur)
            .ease("linear")
            .attr('d', pathFunction)            
         }
    }