2011-09-13 40 views
12

我已經使用了這個簡單的虛擬文件來做一些測試。預期的結果是沿路徑拖動紅色圓圈。問題是,我無法弄清楚如何關聯這兩種形狀。如何沿給定路徑拖動形狀

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8" />  
    <script src="raphael-min.js"></script>  
</head> 
<body>  
<script type="text/javascript">  
// Creates canvas 320 × 200 at 10, 50 
var r = Raphael(10, 50, 320, 200); 

var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}), 
    e = r.ellipse(104, 100, 4, 4).attr({stroke: "none", fill: "#f00"}), 


/*var c = r.circle(100, 100, 50).attr({ 
    fill: "hsb(.8, 1, 1)", 
    stroke: "none", 
    opacity: .5 
});*/ 


var start = function() { 
    // storing original coordinates 
    this.ox = this.attr("cx"); 
    this.oy = this.attr("cy"); 
    this.attr({opacity: 1}); 
}, 
move = function (dx, dy) { 
    // move will be called with dx and dy 
    this.attr({cx: this.ox + dx, cy: this.oy + dy}); 
}, 
up = function() { 
    // restoring state 
    this.attr({opacity: 1}); 
}; 
e.drag(move, start, up);  
</script> 
</body> 
</html> 
+0

的主要想法是讓類似animateAlong但拖,而不是動畫的東西。 – Guillermo

+2

這是一個jsFiddle供人們使用:http://jsfiddle.net/8T9NQ/ – Joe

+0

一般來說,您需要將光標位置投影到路徑上,找到路徑上最近的點。很有可能在最靠近光標的路徑上可能有兩個(或更多或無限)點,因此您需要消除歧義以選擇最佳點。 – Phrogz

回答

1

圓形物體的中心有一個x,y座標和一個半徑。爲了確保圓圈保持在線上,只需找到圓心和線本身的交點即可。

爲此,您需要存儲線條的起始和終止座標。然後使用線的方程:y = mx + b,可以找到斜率和y截距。一旦你有一個線的函數,你可以通過插入不同的x值來爲該圓生成新的座標。

此外,通過將圓的x,y座標插入函數中,您可以檢查圓是否在線上。

27

你沒有詳細說明你想如何交互工作,所以我用我覺得最自然的東西。

我們可以假設,點必須保持在路徑上,從而它的位置必須由

p.getPointAtLength(l); 

一些l給出。要找到l我們可以搜索當地曲線和光標位置之間的距離的最小值。我們用l0初始化搜索,其中l0l的當前值的值,用於定義點的位置。

見的jsfiddle這裏工作的例子:

http://jsfiddle.net/fuzic/kKLtH/

下面是代碼:

var searchDl = 1; 
var l = 0; 

// Creates canvas 320 × 200 at 10, 50 
var r = Raphael(10, 50, 320, 200); 

var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}), 
    pt = p.getPointAtLength(l); 
    e = r.ellipse(pt.x, pt.y, 4, 4).attr({stroke: "none", fill: "#f00"}), 
    totLen = p.getTotalLength(), 


start = function() { 
    // storing original coordinates 
    this.ox = this.attr("cx"); 
    this.oy = this.attr("cy"); 
    this.attr({opacity: 1}); 
}, 
move = function (dx, dy) { 
    var tmpPt = { 
     x : this.ox + dx, 
     y : this.oy + dy 
    }; 
    l = gradSearch(l, tmpPt); 
    pt = p.getPointAtLength(l); 
    this.attr({cx: pt.x, cy: pt.y}); 
}, 
up = function() { 
    this.attr({opacity: 1}); 
}, 
gradSearch = function (l0, pt) { 
    l0 = l0 + totLen; 
    var l1 = l0, 
     dist0 = dist(p.getPointAtLength(l0 % totLen), pt), 
     dist1, 
     searchDir; 

    if (dist(p.getPointAtLength((l0 - searchDl) % totLen), pt) > 
     dist(p.getPointAtLength((l0 + searchDl) % totLen), pt)) { 
     searchDir = searchDl; 
    } else { 
     searchDir = -searchDl; 
    } 

    l1 += searchDir; 
    dist1 = dist(p.getPointAtLength(l1 % totLen), pt); 
    while (dist1 < dist0) { 
     dist0 = dist1; 
     l1 += searchDir; 
     dist1 = dist(p.getPointAtLength(l1 % totLen), pt); 
    } 
    l1 -= searchDir; 

    return (l1 % totLen); 
}, 
dist = function (pt1, pt2) { 
    var dx = pt1.x - pt2.x; 
    var dy = pt1.y - pt2.y; 
    return Math.sqrt(dx * dx + dy * dy); 
}; 
e.drag(move, start, up);​ 
+0

做得非常好。這應該被接受爲正確的答案! –

+0

Fuzic如果我想創建一個餅圖類似[鏈接] http://www.shodor.org/interactivate/activities/PieChart/ [link]可以使用raphael js庫嗎? –

+0

@fuzic - 你能解釋一下gradSearch的工作原理嗎?請參閱:http://stackoverflow.com/questions/23812322/snap-svg-determine-drag-distance-along-a-path – Inator