Transition between a circle and a line with svg an

2019-07-28 13:20发布

JS Fiddle

I am trying to figure out how to "unfurl"/"unravel" a circle by "snipping" it at the top, and then it would animate to a line.

I have made a circle by using 16 points (and a 17th to close it since if I used a closed interpolation, the transition would look weird)

How (would it be via an animation?, just adjusting the x and y points?, another interpolation?) can you transition between the circle and the line one point at a time?

Circle points:

//The data for our line
var circleData = [ { "x": 150 , "y": 20   },
                 { "x": 165.30, "y": 23.04},
                 { "x": 178.28, "y": 31.71},
                 { "x": 186.95, "y": 44.69},
                 { "x": 190   , "y": 60   },
                 { "x": 186.95, "y": 75.30},
                 { "x": 178.28, "y": 88.28},
                 { "x": 165.30, "y": 96.95},
                 { "x": 150   , "y": 100   },
                 { "x": 134.69, "y": 96.95},
                 { "x": 121.71, "y": 88.28},
                 { "x": 113.04, "y": 75.30},
                 { "x": 110   , "y": 60.00},
                 { "x": 113.04, "y": 44.69},
                 { "x": 121.71, "y": 31.71},
                 { "x": 134.69, "y": 23.04},
                 { "x": 150   , "y": 20   }   ];

Line Points:

var lineData = [ { "x": 10    , "y": 200   },
                 { "x": 20    , "y": 200   },
                 { "x": 30    , "y": 200   },
                 { "x": 40    , "y": 200   },
                 { "x": 50    , "y": 200   },
                 { "x": 60    , "y": 200   },
                 { "x": 70    , "y": 200   },
                 { "x": 80    , "y": 200   },
                 { "x": 90    , "y": 200   },
                 { "x": 100   , "y": 200   },
                 { "x": 110   , "y": 200   },
                 { "x": 120   , "y": 200   },
                 { "x": 130   , "y": 200   },
                 { "x": 140   , "y": 200   },
                 { "x": 150   , "y": 200   },
                 { "x": 160   , "y": 200   },
                 { "x": 170   , "y": 200   }   ];

标签: svg d3.js
1条回答
贪生不怕死
2楼-- · 2019-07-28 13:32

The first thing that I noticed when trying Duopixel's demo was that the circle seemed to shrink to fit on the line. Thus I decided to make the line the same length as the circle. Moreover to have a uniform distribution I wrote two functions to create the line and circle data arrays:

var numberOfPoints = 30;
var radius = 60
var margin = {top: 20,left: 20}
var lineLength = 2 * radius * Math.PI

var circleData = $.map(Array(numberOfPoints), function (d, i) {
    var imag = margin.left + lineLength / 2 + radius * Math.sin(2 * i * Math.PI / (numberOfPoints - 1))
    var real = margin.top + radius - radius * Math.cos(2 * i * Math.PI / (numberOfPoints - 1))
    return {x: imag, y: real}
})

var lineData = $.map(Array(numberOfPoints), function (d, i) {
    var y = margin.top + 2 * radius;
    var x = margin.left + i * lineLength / (numberOfPoints - 1)
    return { x: x, y: y}
}).reverse()

So, now, what effect can we apply? I will go with the easiest one: a transition mapping each point of the circle to its point on the line.

var circle = svgContainer.append("g")
    .append("path")
    .data([circleData])
    .attr("d", lineFunction)
    .attr("class", "circle")
    .on("click", transitionToLine)

function transitionToLine() {
    circle.data([lineData])
        .transition()
        .duration(1000)
        .ease("linear")
        .attr('d', lineFunction)
    circle.on("click", transitionToCircle)
}
function transitionToCircle() {
    circle.data([circleData])
        .transition()
        .duration(1000)
        .ease("linear")
        .attr('d', lineFunction)
    circle.on("click", transitionToLine)
}

Here is the jsFiddle, you just have to click on the node to see the animation.

One important thing to notice is that the transition takes the same time for each point whereas in reality you would like the points in the end to arrive after the points near the middle. The trick you can use is to make the duration of the animation be proportional to the distance from the source point to the destination one but I don't see how to use it with lines as you pass the whole array so you cannot change the duration for a specific point.

查看更多
登录 后发表回答