8

现场演示

所以我有这样的想法,应该允许所有单轴数据以所有基本方式显示;至少从馅饼到酒吧。理想情况下,这将是一个动画过渡,但这就是困难所在。

制作饼图很容易,制作条形图也是如此。这是我到目前为止所拥有的:

# fields
width   = 750
height  = width/2
margin  = 20
radius  = (height-(margin*2))/2

# helpers
pie     = d3.layout.pie().value (d) -> d 
arc     = d3.svg.arc()
    .outerRadius(radius)
    .innerRadius(radius/4)
x       = d3.scale.linear().domain([0, 100]).range [0, width]

$http.get('/Classification_Top_10_by_Count.json').success (data) ->

    percents = (parseFloat item.Percent for item in data).sort d3.ascending

    svg      = d3.select('#svgStage').append('svg')         
        .attr('width', width+(margin*2))
        .attr('height', height+(margin*2))

    svg.data([percents])

    g = svg.append('g')
        .attr('transform', "translate(#{radius},#{radius})")

    paths   = g.selectAll 'path'

    paths.data(pie).enter().append('path')
        .attr('d', arc)

    toBars = ->
        g.selectAll('path').transition().duration(2000) 
            .attr 'd', (d, index) ->
                # this is over complex because I was playing with it.
                cord = 
                    tl : [0,          index*20]
                    tr : [d.value*20, index*20]
                    br : [d.value*20, index*20-20]
                    bl : [0,          index*20-20]
                oCord = [
                    cord.tl
                    cord.tr 
                    cord.br 
                    cord.bl
                ]
                "M #{oCord[0][0]}, #{oCord[0][2]}
                A 0, 0 0 0, 0 #{oCord[1][0]}, #{oCord[1][3]}
                L #{oCord[2][0]}, #{oCord[2][4]}
                A 0, 0 0 0, 0 #{oCord[3][0]}, #{oCord[3][5]}
                Z"  

显然,要使它起作用,它必须是路径元素到路径元素,并且过渡现在正在起作用。问题是它看起来像垃圾。它开始的那一刻看起来是乱码,直到它结束并变成像样的条形图。

我一直在看这个:http ://d3-example.herokuapp.com/examples/showreel/showreel.html 它以我想要的方式演示了一个条转换为甜甜圈的方式。查看源代码,这是通过自定义补间完成的。(查看源代码第 518 行)

现在我在我的头上。这里发生了什么?我怎样才能让这种过渡发挥作用?有没有其他人处理过这个问题?


更新

为了清楚起见,下面的插图更清楚地说明了我过渡的意图。

在此处输入图像描述


赏金清晰。我为这个问题添加了赏金,因为我需要解释出了什么问题。Superboggly 做到了,所以他得到了赏金。但是 Amit Aviv 的方法更胜一筹,所以我接受他的回答是最正确的。我也都+1了。

4

2 回答 2

10

这是我的看法:http: //jsfiddle.net/amitaviv99/x6RWs/42/

我的方法是使用三次贝塞尔曲线来近似弧和条,控制点的数量完全相同。代码有些复杂,需要一些工作。但结果相当顺利。

这是摘录(所以需要..)

var bezierArc = function(radiusIn, radiusOut, startAngle, endAngle){
    var arcIn = makeCompArc(radiusIn, startAngle, endAngle);
    var arcIOut = makeCompArc(radiusOut, startAngle, endAngle);
    var lines = makeBezierDoubleLine(radiusIn, radiusOut, startAngle, endAngle);
    var path = [arcIn, lines[0], arcOut, lines[1]].join(' ');

    return path;
}
于 2013-05-11T20:18:44.643 回答
9

D3 在路径之间的插值方面做得很好,但是在路径之前和之后的原始路径有问题,所以我认为也许我们可以想出更好的路径来让 D3 的工作更轻松,而不是我自己接管整个补间过程. 我的结果

首先是看 svg arc path 元素。它基本上是这样的:

A rx,ry a f1,f2 x,y 

你可以在这里阅读详细信息。这将从您所在的任何位置(之前的最终坐标)到坐标 x,y 绘制一条弧线。但要关注的是,前两个数字是隐含的椭圆半径,而结束坐标之前的最后一部分,我标记为f1,f2,是标志,因此不能插值。

所以从你的代码转换的主要怪异是因为你试图在

一个 rx,ry, 0 0, 1

一个 0,0 0 0, 0

如果在一种情况下将结束路径设置为 A0,0 0 0,1,您将立即看到更平滑的过渡。

为了使这些部分更好地结合在一起,我对饼图的内半径进行了动画处理,使这些部分看起来更像条形但弯曲,然后我让 D3 计算出曲线到条形的过渡,但不切换弧形标志。然后,您希望钢筋具有平端。如果您增加隐含的椭圆半径,则路径将具有更平坦的弧线!所以我只用了100,100。我的酒吧的最终过渡路径如下所示:

"M " + oCord[0][0] + "," + oCord[0][1] + 
"A100,100 0 0,1 " + oCord[1][0] + "," + oCord[1][1] + 
"L " + oCord[2][0] + "," + oCord[2][1] + 
"A100,100 0 0,0 " + oCord[3][0] + "," + oCord[3][1] + 
"Z";

然后实际上,正确地展平端点,我有第二个过渡(它们连续运行)以将路径的弧段归零。我怀疑有一种更好的方法可以使用 D3 转换进行这种清理,但是持续时间为 0 的转换也可以。

为了让反向效果很好,我从上面设置了平坦弧形曲线的路径。具有较大的半径和正确的标志意味着 D3 计算的转换回圆环图的效果很好。然后我简单地将内半径动画化。

于 2013-05-10T18:32:23.393 回答