【问题标题】:Piechart on a Hexagon六边形饼图
【发布时间】:2015-02-05 04:25:37
【问题描述】:

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

  1. 我的六边形(6 个顶点,4 个面)
  2. 最后应该是怎样的(没有灰线)

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

  4. 剪辑:在球体上绘制饼图很容易,也许我可以剪辑三个对象(没有 SVG.js!)所以我只看到带有剪辑图的六边形?

【问题讨论】:

  • 你有什么问题 - 如何绘制正六边形,如何绘制扇形或其他?
  • 我说的是three.js(标签&我说的是三个对象)。我已经用 6 个顶点和 4 个面构建了六边形,我想用这个 3D 对象构建一个饼图。但是怎么做呢?

标签: math three.js pie-chart clip


【解决方案1】:

嗯,three.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,这大大简化了问题:我们只需要找到它的y值。

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

这很容易解决,因为 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;
}

【讨论】:

  • 太棒了,剪裁的东西将来可能对我有很大帮助,但你的计算。在尝试了一些之后我停止了,因为我的数学在这一点上很糟糕。谢谢你的帮助!但我不知道如何将你的数学东西转换为 3d 几何,你能删除所有颜色等代码,只让用于创建六边形的代码在其中吗?这在带有顶点的 3D 中是否可行?
  • 我不知道你的 3D 顶点是什么样子,但这个答案中的代码只是获取六边形区域的代码。所以你可以直接调用regions([data array]),它返回一组2D多边形,(0,0)是六边形的中心。然后,您可以按照您想要的方式将其映射到 3D 点。
  • 这是一个非常好的答案,并解释了数学。继续努力!
  • @Cimbali 那是我当前的代码:jsfiddle.net/akn1gvgw 我不明白如何在我的 3D 代码中使用您的代码..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-17
  • 2015-09-23
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
相关资源
最近更新 更多