【发布时间】:2017-02-15 14:00:31
【问题描述】:
背景:
我正在开发一个基于网络的远足地图应用程序。因此,基于传单的地图提供了带有标签的远足径路线。由于任何远足路径都可以是多条路线的一部分,因此路线(分别代表路线的相应折线)可以重叠。
问题:
每条路线都有其工具提示(由鼠标悬停触发,{sticky:true})显示其标签,该标签对非重叠折线按预期工作,但只要两条或更多路线重叠,只有“顶部”的折线会打开其工具提示。这种行为本身并不坏,但由于所有路线都同样重要,我想在指针位置显示路线的所有标签(或最多 5 个标签 + x 更多)。我找不到与此主题相关的任何问题。
我尝试了什么:
- 为所有路线创建一个特征组,将工具提示绑定到该组,希望工具提示功能提供一个包含所有穿过指针位置的折线的数组。事实证明,我只得到顶部折线的信息
- 我在地图上尝试了 mousemove 事件,但没有成功
- 将指针的 layerPoint 坐标与所有路线的 _rings & _parts layoutPoint 数组进行比较以找到匹配的 layerPoints,但成功率仅为 5% 左右,因为这些 layerPoints 仅覆盖折线的实际点,而不是两点之间的连接。此外,每条折线周围都有一个边距,会在指针甚至接触折线之前触发提示(我猜这也改善了触摸操作)
- 边距问题的解决方案是在将每个折线点与指针坐标进行比较之前为每个折线点添加正边距和负边距,这可以改善结果但不能解决主要问题。
旁注:
- 所有路线都被绘制到一个画布中
长话短说,我需要外部帮助来实现目标。也许你们中的一些人有一个想法或可以提供一个解决方案。任何意见表示赞赏。
** 更新: **
一个有效但效率很低的解决方案如下
方法:
计算从指针到视口中所有路线的最短距离。如果指针到路线的距离低于某个阈值,则将它们添加到应显示的路线标签数组中。
步骤:
1.) 将空白工具提示绑定到包含所有路线的功能组
2.) 使用以下函数将 mousemove 事件绑定到特征组
var routesFeatureGroup = L.featureGroup(routesGroup)
.bindTooltip('', {sticky: true})
.on('mousemove', function(e){
var routeLabels = [e.layer.options.label]; // add triggering route's label by default
var mouseCoordAbs = el.$map.project(e.latlng);
$.each(vars.objectsInViewport.routes, function(i, v){
if (e.layer.options.id != el.$routes[i].options.id && el.$routes[i]._pxBounds.contains(e.layerPoint)){
var nearestLatlngOnPolyline = getNearestPolylinePoint(e.latlng, el.$routes[i]);
var polyPointCoordAbs = el.$map.project(nearestLatlngOnPolyline);
var distToMouseX = polyPointCoordAbs.x - mouseCoordAbs.x;
var distToMouseY = polyPointCoordAbs.y - mouseCoordAbs.y;
var distToMouse = Math.sqrt(distToMouseX*distToMouseX + distToMouseY*distToMouseY);
if (distToMouse < 15) {
routeLabels.push(el.$routes[i].options.label);
}
}
})
var routesFeatureGroup.setTooltipContent(routeLabels.join('<br>'));
})
说明:
我已经为应用程序的另一部分收集了当前视口中的所有对象(路线和标记)。当前可见的所有路由都存储在 vars.objectsInViewport.routes (分别是它们的 id)中,所以我不必遍历所有路由。默认添加触发 mousemove 事件的图层。然后,如果出现以下情况,我会检查当前可见的每条路线:
- 它们的 id 与触发 mousemove 事件的层不同(因为默认添加了此标签)
- 如果它们的边界(在笛卡尔坐标中:“_pxBounds”)包含 mousemove 事件的笛卡尔 layerPoint(用于排除不相交的路线的粗略方法)
如果路线满足这些条件,则计算从指针到路线的最近纬度点。我使用自定义函数执行此操作,在此上下文中发布它有点长。 (如果有人要求,我会这样做)
然后使用map-project方法将折线/路线上的鼠标位置和纬度点转换为绝对坐标 http://leafletjs.com/reference.html#map-project
最后,使用毕达哥拉斯计算这些到点之间的距离。它是基于像素的,因此缩放级别不是一个因素。如果距离低于某个阈值 (15px),则它们与指针足够接近以被视为悬停(折线周围有默认边距),因此路线的标签将添加到标签数组中。
最后,特征组的工具提示被所有标签填充。
即使手术成本很高,结果也很有希望。我添加了 50ms 的超时来减少函数调用:
var tooltipTimeout;
var routesFeatureGroup = L.featureGroup(routesGroup)
.bindTooltip('', {sticky: true})
.on('mousemove', function(e){
clearTimeout(tooltipTimeout);
tooltipTimeout = setTimeout(function(){
// collect labels
// ...
},50);
.on('mouseout', function(){
clearTimeout(tooltipTimeout);
})
【问题讨论】:
标签: leaflet tooltip polyline overlapping