- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 mapbox map ,其中添加了一些特征点,并带有显示位置名称的文本标签。
我正在尝试为此添加碰撞检测/避免,以免标签发生碰撞。我实际上有这个工作(见下图),但我不想进一步改进它。
目前我正在使用 D3 四叉树进行碰撞检测,如果两个边界框重叠(我们称它们为 A
和 B
),我首先检查是否它们在 X 或 Y 方向上有最大的重叠,然后在重叠最短的方向上将它们彼此分开。
如果你看一下 map ,你会发现一些标签被移到了离相应图标很远的地方(绿点,固定在原来的位置)。例如突出显示的标签“都柏林”。 我如何改进算法,以便它也考虑到图标位置的距离?“都柏林”可以更靠近左侧的图标。
我不一定需要解决方案的完整代码,只需要一些提示。我花了太多时间思考这个问题,所以我需要一些新的输入。
D3.js模拟就是这样定义的:
getSimulation() {
return (
d3
/** Setup a physics based simulation */
.forceSimulation<Node>()
.force('collision', this.forceCollide())
.stop()
)
}
碰撞检测定义如下:
/** Collision detection with quadtree.
*
* Will compare node to other nodes, using a quadtree,
* and move them apart of the overlap. If biggest overlap
* is in x direction, move apart in y direction, or visa versa.
*/
forceCollide() {
let nodes: Array<Node>
function force(alpha: number) {
// for (var i = 0; i < 10; i++) {
const quadtree = d3
.quadtree<Node>()
.x(d => d.x)
.y(d => d.y)
.addAll(nodes)
for (const node of nodes) {
const l1 = node.x
const r1 = node.x + node.size[0]
const t1 = node.y
const b1 = node.y + node.size[1]
/**
* visit each squares in the quadtree x1 y1 x2 y2
* constitutes the coordinates of the square want
* to check if each square is a leaf node (has data prop)
*/
quadtree.visit((visited, x1, y1, x2, y2) => {
/** Is a leaf node, and is not checking against itself */
if (isLeafNode(visited) && visited.data.id !== node.id) {
const l2 = visited.data.x
const r2 = visited.data.x + visited.data.size[0]
const t2 = visited.data.y
const b2 = visited.data.y + node.size[1]
/** We have a collision */
if (l2 < r1 && l1 < r2 && t1 < b2 && t2 < b1) {
/** Calculate intersecting rectangle */
const xLeft = Math.max(l1, l2)
const yTop = Math.max(t1, t2)
const xRight = Math.min(r1, r2)
const yBottom = Math.min(b1, b2)
/** Move the rectangles apart, so that they don't overlap anymore. 🙅🏼 */
/* Find which direction has biggest overlap */
if (xRight - xLeft > yBottom - yTop) {
/** Biggest in x direction (move y) */
const dy = (yBottom - yTop) / 2
node.y -= dy
visited.data.y += dy
} else {
/** Biggest in y direction (move x) */
const dx = (xRight - xLeft) / 2
node.x -= dx
visited.data.x += dx
}
}
}
return x1 > r1 || x2 < l1 || y1 > b1 || y2 < t1
})
}
}
force.initialize = (_: any) => (nodes = _)
return force
}
最佳答案
我最终对您的代码做了几处更改,我认为这应该会改善这种行为。
Node.size
属性从数组更改为对象:export interface NodeSize {
width: number;
height: number;
}
interface Node {
...
size: NodeSize;
}
/**
* Measure the width of a text were it to be rendered using a given font.
*
* @param {string} text the text to be measured
* @param {string} font a valid css font value
*
* @returns {number} the width of the rendered text in pixels.
*/
function getTextSize(text: string, font = "14px \"Open Sans Semibold\""): NodeSize {
const element = document.createElement("canvas");
const context = element.getContext("2d") as CanvasRenderingContext2D;
context.font = font;
const textSize = context.measureText(text);
return {
width: textSize.width,
height: textSize.actualBoundingBoxAscent + textSize.actualBoundingBoxDescent,
};
}
forceX
和 forceY
:d3.forceSimulation
.force("collision", rectCollide())
.force("x", d3.forceX<Node>().x(d => d.lng))
.force("y", d3.forceY<Node>().y(d => d.lat))
width/2
和 height/2
这样只有他们的 Angular 落应该接触。这将为 x
和 y
力提供更多自由,然后将节点拉回它们的 anchor :type TNodeBounds = {
t: number,
r: number,
b: number,
l: number
}
function getOffsets(node1: TNodeBounds, node2: TNodeBounds): { dx: number, dy: number } {
/** Calculate intersecting rectangle */
const xLeft = Math.max(node1.l, node2.l);
const yTop = Math.max(node1.t, node2.t);
const xRight = Math.min(node1.r, node2.r);
const yBottom = Math.min(node1.b, node2.b);
const xCenter = (xLeft + xRight) / 2;
const yCenter = (yTop + yBottom) / 2;
let dx = 0, dy = 0;
if((node1.l <= node2.l && node1.r >= node2.r)
|| (node2.l <= node1.l && node2.r >= node1.r)) {
// The larger node completely spans the smaller node, don't move sideways, since it won't matter
} else if(node1.l <= node2.l) {
// Node 1 is left of node 2
dx = xCenter - xLeft;
} else {
// Node 1 is right of node 2
dx = -(xCenter - xLeft);
}
if((node1.t <= node2.t && node1.b >= node2.b)
|| (node2.t <= node1.t && node2.b >= node1.b)) {
// The taller node completely spans the smaller node, don't move up/down, since it won't matter
} else if(node1.t <= node2.t) {
// Node 1 is above node 2
dy = yCenter - yTop;
} else {
// Node 1 is below node 2
dy = -(yCenter - yTop);
}
return { dx, dy };
}
/** Move the rectangles apart, so that they don't overlap anymore. 🙅🏼 */
const { dx, dy } = getOffsets(
{ l: l1, t: t1, r: r1, b: b1 },
{ l: l2, t: t2, r: r2, b: b2 }
);
node.x -= dx;
visited.x += dx;
node.y -= dy;
visited.y += dy;
关于javascript - 使用 D3.js(和 Mapbox)避免标签冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64470716/
刚刚通过 cocoapods 安装了 MapboxGL。我在我的 ViewController 中初始化它,就像给出的示例一样: @IBOutlet weak var mapViewWrapper:
有没有办法更改mapbox-gl-js图标图像的颜色? 取自https://www.mapbox.com/mapbox-gl-js/example/geojson-markers/的代码不会将标记颜色
我正在重写来自 Mapbox.js 的路线规划 Web 应用程序至 Mapbox GL JS图书馆。 几乎所有功能都已实现,但由于 的滞后、不流畅的动画和普遍的缓慢,它几乎无法使用。 map 层 .
我的问题是,如何从 MapBox 服务获取指定路线的海拔剖面图。 在输入中,我们将路径/路线作为坐标数组(纬度、经度)。作为结果,我们想要获得坐标对的数组 - 高程。 如果高程数据的分辨率高于提供的路
如何检查 map 上是否显示了 Mapbox 栅格图层? 我的目标是停止加载动画。我知道我可以检查 map 本身是否准备就绪。 map.on('ready', someFunction) 除了针对特定
https://codepen.io/m12n/pen/XWNRZMg?editors=0010 mapboxgl.accessToken = "pk.eyJ1IjoiaW50ZWxsaWdlbm
我想在我的 map 上添加一个自定义标记。我正在使用 mapbox gl 脚本。 我发现与此主题相关的唯一文档是这个 https://www.mapbox.com/mapbox-gl-js/examp
我需要mapbox gl的某种Google map “空闲”事件。 当触发每个事件并且 map 停止放大/缩小拖动等并且每个图层都已加载时, map 处于空闲状态。 我必须使用此代码 map.on
有没有办法在离线设置中使用 Mapbox GL(询问 JS 和 native )?使用 MBTiles,您可以使用 MBTiles 文件或提取光栅图像。我想知道是否有任何类似的东西可以让 Mapbox
我有一个矩形,需要用正方形填充它。我找到中心线并想沿着该线放置方 block 。但是有没有简单的方法可以在 mapboxgl 中与 turfjs 等其他库一起绘制正方形?就像设置正方形的中心和边长并获
我对 MapBox 中的标记有疑问。我有多个标记,我想对其进行聚类。我使用 MapBox SDK for android。请帮我。非常感谢。 我在 Google Service Map Android
我建立了一个新的 react-native 项目并使用 yarn add @react-native-mapbox-gl/maps 添加了 Mapbox。 这个 Notice, that if you
我建立了一个新的 react-native 项目并使用 yarn add @react-native-mapbox-gl/maps 添加了 Mapbox。 这个 Notice, that if you
是否可以获取对应于 Mapbox 缩放级别的仪表列表?就像下面从 Bing map 中列出的一样:here 最佳答案 是的,就在 Mapbox 文档中: https://docs.mapbox.com
由于 Mapbox GL 文档没有讨论任何关于向 LngLat 坐标添加简单标记的内容,而且实际上只有关于如何添加自定义标记的文档,我希望有人能告诉我您应该如何获取 Mapbox-gl.js实际上为传
我有一个图层将 geojson 源中的点要素渲染为圆圈。以下是其中一项功能的示例: { type: 'Feature', properties: { color: 'red',
如何使用嵌套值以使用 case == 运算符?就像是: this.map.setPaintProperty("somelayer", "fill-color", ["case",
我正在使用 mapbox.js 制作带有地点的 map 。我只是想让 map 返回点击的正确坐标,我使用以下代码成功管理: map.on('click', function(e) { var
我在 style.load 事件上重绘图层并移除图层 map.on('style.load', function() { loadByBounds(tempBou
我正在努力实现更好的文本大小调整,相信通过插值,我也许能够将我当前的文本标签更新为更高效的格式。目前我们正在创建“静态文本”,本质上我们获得了特定缩放级别的理想文本大小,然后在每个缩放级别使用停止缩放
我是一名优秀的程序员,十分优秀!