六角形的饼图

时间:2014-12-07 11:53:07

标签: math three.js pie-chart clip

我想在Hexagon上制作饼图。可能有几种解决方案。在图片中是我的Hexagon和两个想法:

  1. 我的六角形(6个顶点,4个面)
  2. 它应该如何看待结尾(没有灰线)

  3. 数学:我可以从对象中获取一些信息来动态计算新顶点(从中心到每个点)以添加彩色面吗?

  4. 剪切:在一个球体上,一个饼图很简单,也许我可以剪辑三个对象(没有SVG.js!)所以我只看到带有剪切图表的Hexagon?

  5. photo

1 个答案:

答案 0 :(得分:2)

三个.js中的整个剪辑事情已经在这里解决了:Object Overflow Clipping Three JS,有一个小提琴,表明它有效。所有。

所以我会选择"顶点"选项,或者更确切地说,一个函数,给定一个值列表返回一个多边形列表,每个值一个,这是六边形的一部分,这样

  • 它们都有中心点作为顶点
  • 它们在该点处的角度与值
  • 成比例
  • 他们形成六边形的分区

让我们假设六边形刻在半径为R的圆上,并由顶点定义:

  

{(R sqrt(3)/ 2,R / 2),(0,R),( - R sqrt(3)/ 2,R / 2),( - R sqrt(3)/ 2, - R / 2),(0,-R),(R sqrt(3)/ 2,-R / 2)}

这很容易从cos(Pi / 6),sin(Pi / 6)和各种对称的值中得出。

在每个多边形的中心获取角度非常简单,因为它与圆形相同。现在我们需要知道六边形上的点的位置。

请注意,如果使用坐标轴的对称性,则只有两种情况:[0,Pi / 6]和[Pi / 6,Pi / 2],然后通过镜像获得结果。如果你使用Pi / 3的旋转对称,你只有一个案例:[ - Pi / 6,Pi / 6],你可以通过旋转得到结果。

使用旋转对称

因此,对于每个点,您可以认为它的角度在[-Pi / 6,Pi / 6]之间。该部分六边形上的任何一点都有x=R sqrt(3)/2,这大大简化了问题:我们只需要找到它的值。

现在我们假设我们知道点的极坐标角,因为它与圆相同。我们将其称为beta,并将其值设为[-Pi / 6,Pi / 6](模Pi / 3)。我们不知道距中心的距离是多少,因此我们有以下系统:

system with alpha

由于cos在[-Pi / 6,Pi / 6]范围内从不为0,因此可以轻松解决。

因此d=R sqrt(3)/( 2 cos(alpha) )y=d sin(alpha)

现在我们知道了

  • 距中心beta
  • 的角度
  • 距离中心距离d,这要归功于旋转对称性

所以我们的观点是(d cos(beta), d sin(beta))

代码

是的,我很好奇,所以我最终编码了。对不起,如果你想自己玩它。它起作用了,最后很丑陋(至少有这个数据集),请参阅jsfiddle:http://jsfiddle.net/vb7on8vo/5/

var R = 100;
var hexagon = [{x:R*Math.sqrt(3)/2, y:R/2}, {x:0, y:R}, {x:-R*Math.sqrt(3)/2, y:R/2}, {x:-R*Math.sqrt(3)/2, y:-R/2}, {x:0, y:-R}, {x:R*Math.sqrt(3)/2, y:-R/2}];
var hex_angles = [Math.PI / 6, Math.PI / 2, 5*Math.PI / 6, 7*Math.PI / 6, 3*Math.PI / 2, 11*Math.PI / 6];

function regions(values)
{
    var i, total = 0, regions = [];

    for(i=0; i<values.length; i++)
        total += values[i];

    // first (0 rad) and last (2Pi rad) points are always at x=R Math.sqrt(3)/2, y=0
    var prev_point = {x:hexagon[0].x, y:0}, last_angle = 0;

    for(i=0; i<values.length; i++)
    {
        var j, theta, p = [{x:0,y:0}, prev_point], beta = last_angle + values[i] * 2 * Math.PI / total;

        for( j=0; j<hexagon.length; j++)
        {
            theta = hex_angles[j];
            if( theta <= last_angle )
                continue;
            else if( theta >= beta )
                break;
            else
                p.push( hexagon[j] );
        }

        var alpha = beta - (Math.PI * (j % 6) / 3); // segment 6 is segment 0
        var d = hexagon[0].x / Math.cos(alpha);
        var point = {x:d*Math.cos(beta), y:d*Math.sin(beta)};

        p.push( point );
        regions.push(p.slice(0));

        last_angle = beta;
        prev_point = {x:point.x, y:point.y};
    }

    return regions;
}