2014-01-16 39 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