繁体   English   中英

D3js地图标记碰撞检测

[英]D3js map marker collision detection

有没有一个碰撞检测示例可以通过操纵半径而不是x,y坐标来避免碰撞呢? 我知道Mike Bostock和其他人放在一起的示例,但是我没有使用力图,我的点是地理的,无法操纵其坐标。

我最好的猜测是从半径为0的圆开始,对其进行迭代,并增加它们的半径,只要它们不与另一个圆碰撞。 我认为这可以实现出色的可视化效果,但是我不确定如何有效地确定一个圆是否与另一个圆发生碰撞。


我的带有内联D3js的地图的JSBin(JavaScript选项卡仅包含600kb的GeoJSON数据集): http ://jsbin.com/tapuhefamu/1/edit?html,输出

请注意,标记在缩放时是如何重叠的,在拨弄中似乎没什么大不了的(只是进一步放大,对吗?),但是我正在使用的地图仅在少数几个县中聚集了约2,000个引脚单击时显示信息丰富的DIV。 一些引脚几乎完全被遮盖,并且由于重叠而无法与之交互。

我已经为您编码了一些东西。 检测碰撞非常容易,基本上可以计算两个中心点之间的距离,如果该距离小于两个半径相加的总和,那么它们一定已经发生碰撞。

我在jsbin中遇到了一些问题,因此我将其变成了要点,您可以在http://bl.ocks.org/benlyall/6a81499abf7a0e2ad304中查看

有趣的是:

  1. 添加radiusStep参数-使用此参数可以在迭代次数和节点之间潜在重叠量之间进行权衡。

     radiusStep = 0.01, 
  2. 从缩放处理程序中删除半径缩放:

     zoom = d3.behavior.zoom().on("zoom",function() { g.attr("transform","translate("+ d3.event.translate.join(",")+")scale("+d3.event.scale+")"); //g.selectAll("circle") //.attr("r", nodeRadius / d3.event.scale); g.selectAll("path") .style('stroke-width', countyBorderWidth / d3.event.scale ) .attr("d", path.projection(projection)); }), 
  3. 创建一个新结构以跟踪一个节点是否与另一个节点发生碰撞,半径以及x和y位置(通过投影预先计算)

     nodes = nodeGeoData.map(function(n) { var pos = projection(n); return { collided: false, x: pos[0], y: pos[1], r: 0 }; }); 
  4. 有两个新功能可用于检测碰撞并扩展半径,直到检测到碰撞为止。

     function tick() { nodes.forEach(collided); nodes.forEach(function(n) { if (!n.collided) { nr += radiusStep; if (nr > nodeRadius) { nr = nodeRadius; n.collided = true; } } }); } 

    tick函数首先在每个节点上调用碰撞以确定其是否与其他节点碰撞。 然后,它radiusStep尚未碰撞的任何节点的半径按radiusStep增加。 如果半径变得大于nodeRadius参数,则它将半径设置为该值并将其标记为碰撞以阻止其增大。

     function collided(node, i) { if (node.collided) return; nodes.forEach(function(n, j) { if (n !== node) { var dx = node.x - nx, dy = node.y - ny, l = Math.sqrt(dx*dx+dy*dy); if (l < node.r + nr) { node.collided = true; n.collided = true; } } }); } 

    collided函数会检查每个节点以查看是否与其他任何节点发生碰撞(出于明显原因,除了自身之外)。 如果它检测到碰撞,则比较中的两个节点都标记为已碰撞。 为了检测实际的碰撞,计算x和y位置的差异,然后使用毕达哥拉斯计算它们之间的距离。 如果该距离小于两个节点加在一起的半径,则会发生碰撞。

  5. 在绘制节点之前,将更新drawMap函数以计算半径。

     while (nodes.filter(function(n) { return n.collided; }).length < nodes.length) { tick(); } 

    基本上,这只会调用tick函数,直到所有节点都标记为已碰撞。

  6. drawNodes函数已更新为使用新的nodes数据结构:

     function drawNodes(nodes) { g.selectAll('circle').data(nodes).enter().append("circle") .attr("cx", function (d) { return dx; }) .attr("cy", function (d) { return dy; }) .attr("r", function(d, i) { return dr; }) .attr("class", "map-marker"); } 

    此处的更改仅引用先前创建的每个节点对象的xyr属性。

尽管这行之有效,而且似乎很有效,但它很幼稚,很快就会陷入困境,因为tickcollided函数的组合为O(n^2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM