gpt4 book ai didi

d3.js - D3js : Automatic labels placement to avoid overlaps?(力斥力)

转载 作者:行者123 更新时间:2023-12-03 06:34:36 25 4
gpt4 key购买 nike

如何在 map 标签上应用力排斥力,以便它们自动找到正确的位置?

<小时/>

博斯托克“让我们制作一张 map ”

迈克博斯托克的 Let's Make a Map (下面的屏幕截图)。默认情况下,标签放置在点的坐标和多边形/多边形的 path.centroid(d) + 简单的左对齐或右对齐处,因此它们经常发生冲突。

enter image description here

手工制作的标签位置

一项改进 I met需要添加人为的 IF 修复,并根据需要添加尽可能多的修复,例如:

.attr("dy", function(d){ if(d.properties.name==="Berlin") {return ".9em"} })

随着需要重新调整的标签数量的增加,整体变得越来越脏:​​

//places's labels: point objects
svg.selectAll(".place-label")
.data(topojson.object(de, de.objects.places).geometries)
.enter().append("text")
.attr("class", "place-label")
.attr("transform", function(d) { return "translate(" + projection(d.coordinates) + ")"; })
.attr("dy", ".35em")
.text(function(d) { if (d.properties.name!=="Berlin"&&d.properties.name!=="Bremen"){return d.properties.name;} })
.attr("x", function(d) { return d.coordinates[0] > -1 ? 6 : -6; })
.style("text-anchor", function(d) { return d.coordinates[0] > -1 ? "start" : "end"; });

//districts's labels: polygons objects.
svg.selectAll(".subunit-label")
.data(topojson.object(de, de.objects.subunits).geometries)
.enter().append("text")
.attr("class", function(d) { return "subunit-label " + d.properties.name; })
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
.attr("dy", function(d){
//handmade IF
if( d.properties.name==="Sachsen"||d.properties.name==="Thüringen"|| d.properties.name==="Sachsen-Anhalt"||d.properties.name==="Rheinland-Pfalz")
{return ".9em"}
else if(d.properties.name==="Brandenburg"||d.properties.name==="Hamburg")
{return "1.5em"}
else if(d.properties.name==="Berlin"||d.properties.name==="Bremen")
{return "-1em"}else{return ".35em"}}
)
.text(function(d) { return d.properties.name; });

需要更好的解决方案

这对于较大的 map 和标签集来说是无法管理的。 如何向这两个类添加力排斥:.place-label.subunit-label

这个问题是一场头脑 Storm ,因为我还没有截止日期,但我对此很好奇。我正在考虑这个问题作为 Migurski/Dymo.py 的基本 D3js 实现。 Dymo.py 的 README.md 文档设定了一大组目标,从中选择核心需求和功能(20% 的工作,80% 的结果)。

  1. 初始放置:Bostock 在相对于地理点的左/右定位方面取得了良好的开端。
  2. 标签间排斥:可以采用不同的方法,Lars 和 Navarrc 各提出了一种方法,
  3. 标签湮灭:标签湮灭函数,当一个标签由于被其他标签挤压而整体排斥力太强时,湮灭的优先级可以是随机的,也可以是基于群体 数据值,我们可以通过 NaturalEarth 的 .shp 文件获取。
  4. [豪华] 标签到点排斥:具有固定点和移动标签。但这是相当奢侈的。

我忽略标签排斥是否可以跨标签层和类别起作用。但让国家标签和城市标签不重叠也可能是一种奢侈。

最佳答案

在我看来,强制布局不适合在 map 上放置标签的目的。原因很简单——标签应该尽可能靠近它们标记的位置,但强制布局没有强制执行这一点。事实上,就模拟而言,混合标签并没有什么坏处,这对于 map 来说显然是不可取的。

可能会在力布局之上实现一些东西,将地点本身作为固定节点,并在地点与其标签之间产生吸引力,而标签之间的力将是排斥力。这可能需要修改强制布局实现(或同时多个强制布局),所以我不会走这条路。

我的解决方案仅依赖于碰撞检测:对于每对标签,检查它们是否重叠。如果是这种情况,请将它们移开,其中移动的方向和幅度来自重叠。这样,只有实际重叠的标签才会被移动,并且标签只会移动一点点。重复此过程,直到不再发生任何移动。

代码有些复杂,因为检查重叠非常困惑。我不会在这里发布完整的代码,它可以在 this demo 中找到。 (请注意,我已将标签做得更大以夸大效果)。关键部分如下所示:

function arrangeLabels() {
var move = 1;
while(move > 0) {
move = 0;
svg.selectAll(".place-label")
.each(function() {
var that = this,
a = this.getBoundingClientRect();
svg.selectAll(".place-label")
.each(function() {
if(this != that) {
var b = this.getBoundingClientRect();
if(overlap) {
// determine amount of movement, move labels
}
}
});
});
}
}

整个事情远非完美——请注意,有些标签距离它们标记的位置相当远,但该方法是通用的,至少应该避免标签重叠。

enter image description here

关于d3.js - D3js : Automatic labels placement to avoid overlaps?(力斥力),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17425268/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com