svg - 通过使用 SVG 和 d3 展开它来将圆转换为直线

标签 svg d3.js

对于一个项目,我们试图在圆沿直线路径旋转时将圆变成线(然后再返回),就像轮胎在路上滚动时旋转和平移,或者伸出弯曲的食指一样又回到了掌心。

在此Fiddle ,我有一个静态 SVG(顶部圆圈)沿着 HTML 中定义的线性黑色路径(在圆圈上方,以模仿手指拉伸(stretch))旋转。

我还使用 d3 生成一个由连接点组成的“圆圈”(感谢@ChrisJamesC here,如果你点击/在圆圈中可以展开),并且被平移和旋转 当您单击紫色线时,在 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) 无法识别并抛出一个 Uncaught TypeError: Object [object Array] has no method 'duration' console,所以在SVG中静态定义dur和在JS/D3中动态设置是有区别的,但这是次要的。

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

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

这些看起来更好:

  • 我应该尝试让展开动画在旋转的同时发生吗?这似乎需要逐步/顺序为基础......
  • 或者考虑一个八边形(定义为一条路径),如果要旋转其中的 7 个边,然后旋转 6 个,然后旋转 5 个......对多面体上相当多的点执行此操作? (圆只需要大约 50 个像素,所以 100 个点就足够了)这是 fiddle 中的中间示例。也许以编程方式执行此操作?
  • 或者这让我想到了一种不同的方式:(在八角形的情况下),我可以有 8 条直线路径(没有 Z,只有一个额外的闭合点),以及它们之间的过渡?像这样fiddle
  • 或者与关键帧有关的任何事情?我已经在 Synfig 中制作了一个动画,但不确定如何将它转换为 SVG。 synfig 文件位于 http://specialorange.org/filedrop/unroll.sifz如果可以转换为 SVG,但 xsl 文件 here使用 xsltproc 无法为我正确转换它。

这看起来真的很复杂但很有潜力:

  • 定义点遵循的路径(可能是具有相同引用点数量的贝塞尔曲线),并让引用点动态转换......参见this一个概念示例

这看起来很复杂和笨拙:

  • 做一个真正的圆圈,在它前面有一个不断增长的面具,同时一条线的长度也在增长

一些注意事项:

  • d3 圆中的点数可以在 JS 中调整,目前设置较低,以便您可以在渲染中看到一点点以验证是否发生了旋转(很像渐变在顶圈)。
  • 这是为了帮助学生了解数轴和圆之间守恒的内容,特别是帮助学生学习分数。对于概念应用,请查看 compthink.cs.vt.edu:3000查看我们的原型(prototype),这将有助于切换表示,帮助您获得更好的想法...

最佳答案

我最终使用了与问题中生成圆圈相同的函数,并做了一些思考,似乎我想要一个看起来像手指展开的动画 fiddle .这让我想到了在这个 fiddle 中实现它所需的数学和想法。 .

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

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);
}

和动画

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)            
     }
}

关于svg - 通过使用 SVG 和 d3 展开它来将圆转换为直线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16173731/

相关文章:

svg - 使用 Google 图表工具的范围标记

javascript - Internet Explorer 缩放无法正常工作

d3.js - d3选择器,用于直系子女

javascript - 没有数据时 SVG 路径中有间隙

javascript - 内容安全策略 (CSP) : how to allow svg image in object

html - Safari 图标错误地呈现为白色背景

javascript - 如何设置 d3 符号的大小?

javascript - 带 Meteor 的动态 SVG

javascript - 如何获取 tspan 元素的位置和宽度

javascript - 在 Vue 中使用 D3/没有选择器?