2016-04-26 9 views
0

私はこの例ではMike Bostockのようにパスに沿って円を補間する最良の方法を見つけようとしています:http://bl.ocks.org/mbostock/1705868。しかし、1つのトランジション値を設定するのではなく、各ポイントツーポイント補間に固有の持続時間を設定できるようにしたいと思います。例えば、ノード[0]からノード[1]への円をxミリ秒に渡って遷移させ、ノード[1]からノード[2]にyミリ秒に渡って遷移させる等である。より小さい別々の経路の束とそれらに沿って連続的に移行するか?制限要因は、path.getTotalLength()のようです - パスのサブセットの長さだけを取得する方法はありますか?パスに沿ってある時点で補間する特定の継続時間を設定するにはどうすればよいですか?

transition(); 

function transition() { 
    circle.transition() 
    .duration(10000) 
    .attrTween("transform", translateAlong(path.node())) 
    .each("end", transition); 
} 

// Returns an attrTween for translating along the specified path element. 
function translateAlong(path) { 
    var l = path.getTotalLength(); 
    return function(d, i, a) { 
     return function(t) { 
     var p = path.getPointAtLength(t * l); 
     return "translate(" + p.x + "," + p.y + ")"; 
    }; 
}; 
} 

答えて

2

そこの方法は、実際にはだが(それは最初の強引な計算を必要とするため)、それはあまりにも醜いですが、解決策は以下が含まれます。あなたは、遷移時間を持つ配列を必要とするすべての

ファーストノード間、私の例では、例えば、第1の要素3000をDに必要な(遷移時間の和を計算[580,400]

  • [480,200]から取得するために、MSの時間に相当する、timesあります
  • このパスを作成した各ポイントに到達するまでの直線時間をmsで計算します。これは、2つのポイント間のパスがラインでない場合には実際にはトリッキーです。私の例では、私の例では、それらの時間をブルートフォースで計算して醜いものにしていますが、パス自体にあるポイントに到達するために必要なパス長を計算するメソッドがあれば素晴らしいでしょう。私が知る限りでは存在しません
  • 最後に、線形時間を知った後は、times配列の数値のリストに従ったかのように正しい時刻を計算する必要があります。

のは、最初のポイントを取得するための線形時間が50ミリ秒であり、我々は時間t < 50msに現在している、我々は[範囲内のどこかに[は0ms、50msの]の間で、この値をマッピングする必要があるとしましょう式3000 * (t ms - 0ms)/(50ms - 0ms)

var points = [ 
 
    [480, 200], 
 
    [580, 400], 
 
    [680, 100], 
 
    [780, 300], 
 
    [180, 300], 
 
    [280, 100], 
 
    [380, 400] 
 
]; 
 

 
var times = [3000, 100, 5000, 100, 3000, 100, 1000] 
 
var totalTime = times.reduce(function (a, b) {return a + b}, 0) 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", 960) 
 
    .attr("height", 500); 
 

 
var path = svg.append("path") 
 
    .data([points]) 
 
    .attr("d", d3.svg.line() 
 
    .tension(0) // Catmull–Rom 
 
    .interpolate("cardinal-closed")); 
 

 
svg.selectAll(".point") 
 
    .data(points) 
 
    .enter().append("circle") 
 
    .attr("r", 4) 
 
    .attr("transform", function(d) { return "translate(" + d + ")"; }); 
 

 
var circle = svg.append("circle") 
 
    .attr("r", 13) 
 
    .attr("transform", "translate(" + points[0] + ")"); 
 

 
function transition() { 
 
    circle.transition() 
 
     .duration(totalTime) 
 
     .ease('linear') 
 
     .attrTween("transform", translateAlong(path.node())) 
 
     .each("end", transition); 
 
} 
 

 
// initial computation, linear time needed to reach a point 
 
var timeToReachPoint = [] 
 
var pathLength = path.node().getTotalLength(); 
 
var pointIndex = 0 
 
for (var t = 0; pointIndex < points.length && t <= 1; t += 0.0001) { 
 
    var data = points[pointIndex] 
 
    var point = path.node().getPointAtLength(t * pathLength) 
 
    // if the distance to the point[i] is approximately less than 1 unit 
 
    // make `t` the linear time needed to get to that point 
 
    if (Math.sqrt(Math.pow(data[0] - point.x, 2) + Math.pow(data[1] - point.y, 2)) < 1) { 
 
    timeToReachPoint.push(t); 
 
    pointIndex += 1 
 
    } 
 
} 
 
timeToReachPoint.push(1) 
 

 
function translateAlong(path) { 
 
    return function(d, i, a) { 
 
    return function(t) { 
 
     // TODO: optimize 
 
     var timeElapsed = t * totalTime  
 
     var acc = 0 
 
     for (var it = 0; acc + times[it] < timeElapsed; it += 1) { 
 
     acc += times[it] 
 
     } 
 
     var previousTime = timeToReachPoint[it] 
 
     var diffWithNext = timeToReachPoint[it + 1] - timeToReachPoint[it] 
 
     // range mapping 
 
     var placeInDiff = diffWithNext * ((timeElapsed - acc)/times[it])  
 
     var p = path.getPointAtLength((previousTime + placeInDiff) * pathLength) 
 
     return "translate(" + p.x + "," + p.y + ")" 
 
    } 
 
    } 
 
} 
 

 
transition();
path { 
 
    fill: none; 
 
    stroke: #000; 
 
    stroke-width: 3px; 
 
} 
 

 
circle { 
 
    fill: steelblue; 
 
    stroke: #fff; 
 
    stroke-width: 3px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

によって与えられる0msと、3000ms]
関連する問題