气泡图标签放置算法? (最好是在JavaScript中)

时间:2011-04-29 14:56:24

标签: javascript algorithm visualization labels placement

我想自动放置100-200个气泡标签,以满足以下要求:

  • 标签不应重叠
  • 标签最好不要重叠气泡
  • 标签应该接近泡沫
  • 在某种程度上应尊重首选标签位置(左上,上,下,右等)
  • 字体大小可能会有所不同

这有什么有用的库/算法吗? (最好是JavaScript或PHP)

(图片中的标签位置不符合这些要求)

enter image description here

9 个答案:

答案 0 :(得分:9)

答案 1 :(得分:5)

我想你正在使用javascript,html和css?无论如何,我想到了两种方法。

首先是将其表述为优化问题。您需要为每个标签计算理想位置。这将基于气泡的大小,所需的位置(即顶部,底部,左侧,右侧)和标签的大小(字体和长度)。然后,您需要参数化您的坐标,例如2N元素的列表,其中N是标签的数量。然后,您需要在某个位置(或使用遗传算法的群体)初始化标签,并应用需要成本函数的优化算法。这将基于一组标签位置与理想位置的距离,以及违反规则的任何内容,例如重叠。

或者,使它成为一个物理问题。使用一些刚性链接将每个标签“附加”到其气泡上。为每个标签和每个气泡赋予一个排斥力,并增加一个全局和更强的重力(在首选的上/左/右/下方向)。进行短暂的物理模拟直到达到平衡。数学不应该太难。

答案 2 :(得分:5)

我认为如果您在工具中使用D3,则可以使用“基于强制”的标签放置算法。该解决方案最初属于Max Planck Research Networks,但已经有一个现成的Javascript示例,例如:Force-based label placement in D3

答案 3 :(得分:4)

这可以表示为线性规划问题。您希望最大化或最小化函数(表示解决方案的“权重”或“优点”)受某些约束(您的要求)。您需要将您的需求正式化为值。像这样:

Variables:
x1 = 1 if Labels overlap, 0 otherwise
x2 = some measure of "how much" a label overlaps a bubble
x3 = distance from label to bubble //Label should be close to bubble
x4 = distance between ideal and actual label position
x5 = difference between actual and ideal font size


minimize x1 + 10*x2 + x3 + 20*x4 + 5*x5

subject to constraints:
    x1   = 0  // labels can never overlap
    x2   < /* maximum amount a label is allowed to overlap a bubble */
    ...
    x5   < 6 // font size does not vary by more than +/- 6 pts.

我编制了系数和约束,您可以使用它们根据哪些特征对您最重要来调整结果。系数会增加需求的值(在这种情况下,f4的权重最大,因此它“最重要”。约束是不能违反的硬限制。

由于这是一个众所周知的问题,您现在可以使用多种方法解决它。 Simplex算法很受欢迎。 Cormen et. al中有一整章关于这些问题。

答案 4 :(得分:3)

也许可以使用以下一些帮助工具包:

答案 5 :(得分:1)

不幸的是,我认为在Javascript或PHP中很难找到这个解决方案。但是,我认为您的问题可以分解为小的子问题(基于您的规则),以帮助您设计解决方案。

我会确定哪些规则最重要。从您提供的图表的外观来看,我会说规则#1和#2将提供可读性方面的最大改进。

要根据这些规则确定位置,我会计算文本和气泡的边界容器并测试交集。交叉时,移动到没有交叉点的位置。如果找不到,请使用最小重叠的空间。

这样您还可以为左上角,右下角等创建加权放置启发式,以帮助将标签放置在“首选”位置。

我尝试使用两个带有两个标签的气泡写出一小块放置算法,这两个标签通常很接近并且可能会重叠。如果您可以推广您的放置算法以适用于这个小子集,那么您应该更好地向前推进更多气泡。

此外,也许您可​​以使用kd-tree或其他空间分区数据结构的顺序来定位要避免的最近邻居。

答案 6 :(得分:1)

我在Java中找到了一种实际上可以解决这个问题的方法,它被称为强制定向地图标记,是一种开源的学术体验。

以下是文档+项目源代码:Force Directed Map Labeling

答案 7 :(得分:0)

怎么样

label.substring(0,Math.sqrt(bubbleValueOrRadius))

我在protovis.js的一个例子中找到了这个。

答案 8 :(得分:0)

This thread非常善于介绍一些方法。我正在使用具有多个焦点的力布局,因为它似乎是最好的整体方法。