【问题标题】:d3.js User viewer chartd3.js 用户查看器图表
【发布时间】:2014-03-12 01:43:01
【问题描述】:

开发一个图表,为用户提供查看过它们的视觉效果。内圈显示匹配项(用户关注/被关注),下一个环 - 用户关注其他人,最后一个环 - 用户的关注者。

我已经模拟了 cy、cx 的位置,但是要像这样定位它们需要什么 - 将橙色圆圈绑定到各个圆形象限中?

http://jsfiddle.net/NYEaX/281/

sampleSVG.selectAll("circle")
    .data(dataset)
        .enter().append("circle")
        .style("stroke", "gray")
        .style("fill", "orange")
        .attr("r", 6)
        .attr("cx", function(d, i){return 2 + (i*80)})
        .attr("cy", function(d, i){return (i*80)});

【问题讨论】:

  • 我看过这个例子,但不确定它是否适用。 jsfiddle.net/nrabinowitz/5CfGG - 几乎就像我需要将小圆圈放在新月形内
  • 我已将这两个示例合并在一起。我如何能够控制这些点的象限区域。 jsfiddle.net/5CfGG/26 - 它是否可以跟随任何形状的区域 - 而不仅仅是一个圆圈?
  • 我已经让点变成螺旋状 - 但我不相信这是将点放入自定义形状路径的最佳方式。

标签: javascript d3.js charts


【解决方案1】:

“最新代码”-http://jsfiddle.net/NYEaX/336/(注意:仅是概念性的,高度优化!)

我不确定 d3 是否可以以某种方式自动执行此操作,但您总是可以找出 xy 自己用一些数学计算点的位置:

一种方法是随机放置每个点,直到它正确放置。这绝对不是最快的方法,但如果你没有太多的点要放置,它可能仍然足够好。

假设您的最小圆的半径为 rs 和中心点 (xs sub>, ys) 和你的中间圆圈 rm 和 (xm, ym) 和你最大的圆圈 rl 和 (xl, yl),然后你可以检查一个点是哪个圆圈或​​者通过比较它从圆的中心点到该圆的半径的距离,不会落入:

例如,如果您想在中间的圆圈中放置一个点:

  • 选择一个随机位置(xy),使其可以落在该圆圈中的任何位置:
    • xm - rmxxm + rm
    • ym - rmyym + rm
  • 确保它确实在圆圈内:
    • 检查 (x - xm)2 + (y - ym)2 ≤ rm2
    • 如果不是这种情况,请重新开始并选择不同的 (x, y)
  • 确保它不在小圆圈内:
    • 检查 (x - xs)2 + (y - ys)2 > rs2
    • 如果不是这种情况,请重新开始并选择不同的 (x, y)

现在您有一些随机点位于中间圆圈内,但不是小圆圈。将一个放入更大的圆圈中的工作方式相同(只需替换 xmym sub>rmxlylrl 以及 xs, ysrsxmymrm i>)。要将一个点放入最小的圆圈中,您只需要检查第一个条件(与 xm, y mrm 替换为 x sysrs)。

现在,您可以停在这里(但取决于您的点密度,这可能不是最漂亮的图片),或者您可以尝试将点之间的间距设置得更好一些。一种方法如下:

  • 循环遍历所有点(x1y1) ... (xn, yn)
  • 计算每个点到其他点的距离
  • 找到最接近的两个
  • 在这两个中,找出哪个更接近它的邻居
  • 去掉这个点,再用上面介绍的方法随机放置
  • 要么重复此操作数次,要么直到任意两个点之间的距离达到可接受的最小距离(我会尝试最有效的方法)

通过调整上面的两个检查方程,您还可以通过替换 rm 在圆的边界周围添加一些圆点将避免的间隙2 与 (rm - d)2rs2 与 ( rs + d)2

肯定有很多方法可以优化这个简单的方法:例如,您可以选择您的初始 (xy) 在极坐标中的位置,通过选择 rα 然后计算 xy 以确保您永远不会选择不在您想要的圆圈内的点。只需确保从正确加权的分布中选择 r,以便 xy 结果是均匀分布的。此外,您可以在放置点时立即检查从新放置的点到其所有邻居的距离,而不是在最后的第二步中。例如,为每个点找到 10 个地点,然后始终从与最近邻点距离最大的地点中选择一个。

更新

这就是不用担心点间距的样子:http://jsfiddle.net/NYEaX/328/

实现点放置的相关部分在这里(变量名称已更改为与上面匹配):

function getXCoordinateInCircleSection(i, xm, ym, rm, xs, ys, rs) {
    done = false;
    while (!done) {
        x = getRandomCoordinate(xm-rm, xm+rm);
        y = getRandomCoordinate(ym-rm, ym+rm);
        done = true;
        if ((x-xm)*(x-xm)+(y-ym)*(y-ym) >  (rm-10)*(rm-10)) done = false;
        if ((x-xs)*(x-xs)+(y-ys)*(y-ys) <= (rs+10)*(rs+10)) done = false;
    }
    window.ys[i] = y;
    return x;
}

function getYCoordinateInCircleSection(i) {
    return window.ys[i];
}

并改进点间距:http://jsfiddle.net/NYEaX/329/

(这两个都是基于@TheOldCounty创建的http://jsfiddle.net/NYEaX/326/

【讨论】:

  • 我明白了 - 所以我们首先将容器圆圈放在彼此的顶部。然后为每个容器圆圈分配较小的点 - 随机放置点 - 如果它检测到它被上面的容器圆圈遮挡,请再次移动 - 直到它找到一个未被遮挡的位置。这个数学有基本的演示吗?比如说 2 个正方形和 2 个点?
  • 这个问题听起来很熟悉 - 试图传播馅饼标签 - stackoverflow.com/questions/21939977/…
  • @TheOldCounty 听起来不错,是的。我不知道这方面的任何演示,但实施起来可能并不难。 ;) 顺便说一句:如果您在圆的边界周围添加间隙(正如我刚刚添加的那样),如果您想要更均匀地间隔它们,您只需要检查同一圆中点之间的距离。
  • @TheOldCounty 是的,圆内的点间距与图表上的标签间距几乎完全相同。您还只是添加了点需要保留在各自圆形部分中的约束。
  • 好的。所以第一步是在每个容器中随机绘制点。然后循环通过点。但是如何检测点是否被遮挡?
猜你喜欢
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
  • 2023-04-02
  • 2019-05-02
  • 2020-10-01
  • 1970-01-01
  • 2015-02-14
相关资源
最近更新 更多