2014-01-16 42 views
1

我已經建立了這個形狀(我稱之爲管道)從兩個圓圈建立和路徑:http://jsfiddle.net/gluz/4udR2/3/embedded/result/ 代碼:怎樣繪製管道,使之互動

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

var circle1 = svg.append("circle").attr("cx", 320).attr("cy", 171).attr("r", 37).style("fill", "#CDDE3A"); 

var shapeCoordinates = [{"x":254,"y":370},{"x":352,"y":189},{"x":284,"y":162},{"x":235,"y":363}]; 

var coordinatesFunction = d3.svg.line() 
          .x(function(d) { return d.x; }) 
          .y(function(d) { return d.y; }) 
         .interpolate("linear-closed"); 

var lineGraph = svg.append("path") 
.attr("d", coordinatesFunction(shapeCoordinates)) 
          .attr("stroke", "blue") 
          .attr("stroke-width", 0) 
          .attr("fill", "#CDDE3A") 
          .style("opacity","0.2"); 

var circle2 = svg.append("circle").attr("cx", 245).attr("cy", 365).attr("r", 10).style("fill", "#CDDE3A").style("opacity", 0.2); 

我想使它互動。 對於初學者,我想,當它看起來會像從下面的方式一小圈,但在第一個例子中的影子建:http://jsfiddle.net/gluz/jeRgz/embedded/result/ 代碼:

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

var circle1 = svg.append("circle").attr("cx", 245).attr("cy", 365).attr("r", 10).style("fill", "#CDDE3A"); 

var circle2 = svg.append("circle").attr("cx", 245).attr("cy", 365).attr("r", 10).style("fill", "#CDDE3A").style("opacity", 0.2); 

circle1.transition().duration(3000) 
    .attr("cx", 320) 
    .attr("cy", 171) 
    .attr("r", 37) 
    .style("opacity", 1.0); 

我的問題是:1。 如何我可以一起做路徑對象的圓的過渡嗎? 2.有沒有辦法將它建成一個形狀? 3.我如何讓小圓圈不顯示它下面的內容,所以它不會像第一個例子中那樣拼接成兩個?

謝謝!

+0

關於2.,是的,你可以使它成爲一個單一的對象,我使用'path'元素並給它一個適當的'd'屬性。這應該照顧3.並使1.更容易。 –

+0

關於使用單個「路徑」元素渲染形狀的附加提示:正交地繪製此形狀(例如,在Y軸上對稱,兩個圓的中心具有零座標)可能會相當簡單,然後應用在路徑上使用'transform'屬性進行旋轉。 – meetamit

+0

但是,如何在路徑元素中繪製一條直線跟隨弧? (據我所知,這是我應該這樣做,以創建一個形狀) – Gluz

回答

3

下面是使用單個path sting繪製形狀的功能。 Here's a fiddlehere a simpler版本。這裏有關於數學的some info,這可以使用一些精簡。 pt1pt2指定小圓圈和大圓圈的中心,預期爲2元素陣列,[x,y]r1r2控制每個圓的半徑。

您可以使用transition()爲路徑設置動畫,但並不完美,因爲弧參數是線性插值的。更準確的選擇是通過調用pipePath()來找出如何在每個動畫幀重建路徑。

function pipePath(pt1, r1, pt2, r2) { 
    angle = Math.atan2(
    pt2[0] - pt1[0], 
    pt2[1] - pt1[1] 
) 
    distance = Math.sqrt(
    Math.pow(pt2[0] - pt1[0], 2) + 
    Math.pow(pt2[1] - pt1[1], 2) 
) 
    rDiff = r1 - r2 

    if(distance+5 <= r2) { return "M0,0";} 

    theta = Math.asin(rDiff/distance) 

    l11 = [ 
    pt1[0] + r1 * Math.cos(theta-angle), 
    pt1[1] + r1 * Math.sin(theta-angle) 
    ] 
    l12 = [ 
    pt2[0] + r2 * Math.cos(theta-angle), 
    pt2[1] + r2 * Math.sin(theta-angle) 
    ] 
    l21 = [ 
    pt1[0] + r1 * Math.cos(-theta-angle+Math.PI), 
    pt1[1] + r1 * Math.sin(-theta-angle+Math.PI) 
    ] 
    l22 = [ 
    pt2[0] + r2 * Math.cos(-theta-angle+Math.PI), 
    pt2[1] + r2 * Math.sin(-theta-angle+Math.PI) 
    ] 
    return "M" + l12 + 
    "A" + [r2,r2] + " 0,0,0 " + l22 + // swap 0,0,0 with 0,1,1 for full shape 
    "L" + l21 + 
    "A" + [r1,r1] + " 0,0,1 " + l11 + "z" 
} 
+0

感謝您的偉大答案! – Gluz