2017-02-15 30 views
1

Фон:
Я работаю над веб-картографическим приложением для походов. Таким образом, карта, основанная на листовке, предлагает маршруты по пешеходным тропам, которые обозначены. Поскольку любая пешеходная тропа может быть частью нескольких маршрутов, маршруты - соответственно соответствующие полилинии, представляющие маршруты, могут перекрываться.Листовка - всплывающие подсказки для перекрывающихся полилиний

Проблема:
Каждый маршрут имеет всплывающую подсказку (запускается при наведении курсора, {липким: истинно}), показывая свою метку, которая работает, как ожидалось для непересекающихся ломаных линий, но как только два или более маршрутов перекрываются только полилинии «сверху» получает всплывающую всплывающую подсказку. Это не так плохо, но поскольку все маршруты одинаково важны, я бы хотел показать все метки маршрутов в местоположении указателя (или что-то вроде 5 ярлыков + x больше). Мне не удалось найти проблему, связанную с этой темой.

Что я пробовал:
- Создайте группу функций для всех маршрутов, связать всплывающую подсказку к группе, в надежде, что функция подсказки обеспечивает массив всех ломаных линий, пересекающих положение указателя. Как оказалось, я получаю только информацию о полилинии сверху
- Я пробовал то же самое с событием mousemove на карте, не успел
- Сравнение координат указателя с плавающей точкой со всеми маршрутами _rings & _parts layPoint массивы для поиска соответствия layerPoints, но уровень успеха составляет всего около 5%, так как эти точки слоя охватывают только фактические точки полилинии, но не связь между двумя точками. Кроме того, есть маржа вокруг каждой полилинии, которая запускает tolltip до того, как указатель даже коснется полилинии (возможно, также улучшит сенсорное действие)
- Решение проблемы с запасом заключается в добавлении положительных и отрицательных полей к каждой точке полилинии до сравнивая его с координатами указателя, что улучшает исход, но не решает основной проблемы.

Sidenote:
- Все маршруты втягиваются в одном холсте

Короче говоря, мне нужна внешняя помощь для достижения этой цели. Возможно, некоторые из вас имеют идею или могут предоставить решение. Любой вход оценивается.

** UPDATE: **
рабочие, но довольно неэффективное решение заключается в следующем

подхода:
Вычислить кратчайшее расстояние от указателя на все маршруты в окне просмотра. Если расстояние от указателя до маршрута находится под определенным порогом, добавьте их в массив меток маршрута, которые должны отображаться.

Шагов:
1.) связывает пустую подсказку к полнометражной группе, содержащей все маршрутам
2.) связывают MouseMove события с особенностью группы с функцией follwing

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 (соответственно их идентификаторы), поэтому мне не нужно проходить все маршруты. По умолчанию добавлен слой, который вызвал событие mousemove. Затем я проверяю каждый из маршрутов, видимых в данный момент, если:
- их идентификатор отличается от уровня, запускающего событие mousemove (по мере добавления этой метки по умолчанию) - если их границы (в декартовых координатах: «_pxBounds») содержат декартовы layerPoint события mousemove (для приблизительного соответствия для исключения маршрутов, которые не пересекаются)

Если эти условия выполнены для маршрута, вычислите ближайшую точку привязки от указателя к маршруту. Я делаю это с помощью настраиваемой функции, которая немного длиннее, чтобы опубликовать ее в этом контексте. (Я буду, если кто-то просит для него)

Положение мыши и LatLng точка полилинии/маршрута затем преобразуются в абсолютных координатах с использованием метода с картой проекта http://leafletjs.com/reference.html#map-project

Наконец, расстояние между ними к точкам рассчитывается с использованием пифагора. Он основан на пикселях, поэтому уровень масштабирования не является фактором. Если расстояние ниже определенного порога (15px), они достаточно близко к указателю, который считается зависающим (с полями по умолчанию вокруг полилинии), поэтому метка маршрута добавляется в массив меток.

Наконец, всплывающая подсказка для группы функций заполнена всеми метками.

Результаты довольно перспективны, хотя операция довольно дорога. Я добавил таймаут 50мс, чтобы уменьшить вызов функции немного:

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); 
    }) 

ответ

0

Я могу дать вам представление о том, как это сделать, но я не 100% уверен, что он будет делать эту работу. Существует plugin for Leaflet (Mapbox), который может рассказать вам, находится ли точка в полигоне и возвращает все полигоны, содержащие эту точку.

Если этот плагин не работает для полилиний, вы можете создать многоугольник из полилинии, просто вернувшись с последней точки на первую и закрыв линию (я не уверен, подходит ли это вам решение). Например, если у вас есть полилиния подключенных точек [0, 1, 2, .... n-1, n], вы затем возвращаетесь с подключением [n с n-1, n-1 с n-2,. .. 1 с 0]. Таким образом, вы будете иметь одинаковую форму полилинии, но это будет многоугольник. Это не самое оптимизированное решение, это быстрое решение, которое использует известный и доступный плагин.

Как только вы получите все всплывающие подсказки, вы можете открыть их все сразу для каждого полигона/полилинии. Или, может быть, открыть вспомогательную подсказку, где пользователь может выбрать, какой из них он хочет открыть.

Надеюсь, это поможет! Если вы выясните лучшее решение (или найдите плагин, который выполняет эту работу), отправьте его здесь.

+0

Я видел листовку-плагин (точка в полигоне), но я ожидаю, что проблема с этим подходом: , соединив последнюю точку с первой, многоугольник покрывает область, которая намного больше, чем полилиния, с «вес». Представьте себе длинный круглый маршрут (начало = конец), все точки в маршруте будут соответствовать положительным в этом сценарии, неважно, находится ли курсор на расстоянии 2 пикселя или 400 пикселей от этого маршрута. Я добавил возможное, но дорогое решение для исходного сообщения, которое работает. –

+0

Нет, я не имел в виду, что вы соединяете последнюю точку с первой, но, например, если у вас есть [0,1,2,3,4 ... n-1, n] точки, которые представляют вашу полилинию, назад и соедините [n с n-1, n-1 с n-2, ... 1 с 0]. Я знаю, что это не оптимизированное решение, но это быстрое решение, которое использует известный плагин. –

+1

ах, спасибо за разъяснение.Это, вероятно, будет работать, за исключением «проблемы», что этот подход не учитывает маржу/вес полилиний, что вызывает всплывающую подсказку, чтобы сделать эту функцию более пригодной для использования. –