2016-07-01 3 views
2

Я использую Листовку, и она работает хорошо. Я также использую leaflet.label, и это хорошо работает. Проблема в том, что я хотел бы отобразить две метки справа от маркера. Если я вызываю bindLabel дважды, то второй переопределяет первый. Как я могу убедиться, что у меня есть две метки, как справа от маркера, так и вторая надпись выше первой?Как связать несколько меток с помощью leaflet.label?

Это, как я попробовал:

newMarker.bindLabel(result, { noHide: true }).bindLabel("secondlabel", { noHide: true }); 

Благодаря

EDIT:

мне удалось отобразить текст, используя один вызов bindLabel, как это:

newMarker.bindLabel(result + "<br>secondLabel", { noHide: true }); 

, но это, кажется, слишком хакерское решение. Here говорят, что это невозможно, но это было написано в 2014 году. С тех пор это возможно.

+1

Лично я не вижу ничего плохого в использовании HTML-кода (в том числе '
' тег для разрыва строки) в содержимое этикетки, чтобы предоставить больше информации ... Что касается нескольких этикеток , Я думаю, что по-прежнему нет ничего из коробки. – ghybs

+0

@ghybs, спасибо за комментарий. Если у нас нет возможности связывать несколько ярлыков, невозможно будет нарисовать один влево, а один - вправо. Я знаю, что это не мое нынешнее желание, но недостаток этой возможности не слишком хорош. Возможно, стоит заглянуть в код плагина и посмотреть, как работает bindLabel и сделать это множественное число. Я знаю, что это взломать, но если это элегантный код, он может добавить его в будущие версии. –

+1

Действительно, может быть интересно иметь как вариант «группа», чтобы каждая метка могла быть прикреплена к группе с определенной позицией, например. Теперь этот плагин - Open Source, что означает, что «они» были бы более чем счастливы получить Pull Requests! :-) – ghybs

ответ

4

Мне это удалось. Я ленив, чтобы подтолкнуть его к своему репо прямо сейчас, но я, вероятно, сделаю это в будущем. Логика решения заключается в следующем:

  • this.label ->this.labels
  • this.labels представляет собой массив LeafletLabel с
  • применить изменения для методов, содержащих this.label
  • ход this._labelNoHide = options.noHide в if к предотвращать ошибки

The labe ls будет действовать аналогично для подмножества options, который обрабатывается сингулярно/маркером. К сожалению, люди, особенности noHide или opacity для уровня метки, а не уровня маркера, выходят за рамки этого вопроса. Однако я могу решить эти проблемы позже.

Код выглядит следующим образом:

/* 
    Leaflet.label, a plugin that adds labels to markers and vectors for Leaflet powered maps. 
    (c) 2012-2013, Jacob Toye, Smartrak 

    https://github.com/Leaflet/Leaflet.label 
    http://leafletjs.com 
    https://github.com/jacobtoye 
*/ 
(function (factory, window) { 

    // define an AMD module that relies on 'leaflet' 
    if (typeof define === 'function' && define.amd) { 
     define(['leaflet'], factory); 

     // define a Common JS module that relies on 'leaflet' 
    } else if (typeof exports === 'object') { 
     module.exports = factory(require('leaflet')); 
    } 

    // attach your plugin to the global 'L' variable 
    if (typeof window !== 'undefined' && window.L) { 
     window.LeafletLabel = factory(L); 
    } 
}(function (L) { 
    L.labelVersion = '0.2.4'; 


    var LeafletLabel = L.Class.extend({ 

     includes: L.Mixin.Events, 

     options: { 
      className: '', 
      clickable: false, 
      direction: 'right', 
      noHide: false, 
      offset: [12, -15], // 6 (width of the label triangle) + 6 (padding) 
      opacity: 1, 
      zoomAnimation: true 
     }, 

     initialize: function (options, source) { 
      L.setOptions(this, options); 

      this._source = source; 
      this._animated = L.Browser.any3d && this.options.zoomAnimation; 
      this._isOpen = false; 
     }, 

     onAdd: function (map) { 
      this._map = map; 

      this._pane = this.options.pane ? map._panes[this.options.pane] : 
       this._source instanceof L.Marker ? map._panes.markerPane : map._panes.popupPane; 

      if (!this._container) { 
       this._initLayout(); 
      } 

      this._pane.appendChild(this._container); 

      this._initInteraction(); 

      this._update(); 

      this.setOpacity(this.options.opacity); 

      map 
       .on('moveend', this._onMoveEnd, this) 
       .on('viewreset', this._onViewReset, this); 

      if (this._animated) { 
       map.on('zoomanim', this._zoomAnimation, this); 
      } 

      if (L.Browser.touch && !this.options.noHide) { 
       L.DomEvent.on(this._container, 'click', this.close, this); 
       map.on('click', this.close, this); 
      } 
     }, 

     onRemove: function (map) { 
      this._pane.removeChild(this._container); 

      map.off({ 
       zoomanim: this._zoomAnimation, 
       moveend: this._onMoveEnd, 
       viewreset: this._onViewReset 
      }, this); 

      this._removeInteraction(); 

      this._map = null; 
     }, 

     setLatLng: function (latlng) { 
      this._latlng = L.latLng(latlng); 
      if (this._map) { 
       this._updatePosition(); 
      } 
      return this; 
     }, 

     setContent: function (content) { 
      // Backup previous content and store new content 
      this._previousContent = this._content; 
      this._content = content; 

      this._updateContent(); 

      return this; 
     }, 

     close: function() { 
      var map = this._map; 

      if (map) { 
       if (L.Browser.touch && !this.options.noHide) { 
        L.DomEvent.off(this._container, 'click', this.close); 
        map.off('click', this.close, this); 
       } 

       map.removeLayer(this); 
      } 
     }, 

     updateZIndex: function (zIndex) { 
      this._zIndex = zIndex; 

      if (this._container && this._zIndex) { 
       this._container.style.zIndex = zIndex; 
      } 
     }, 

     setOpacity: function (opacity) { 
      this.options.opacity = opacity; 

      if (this._container) { 
       L.DomUtil.setOpacity(this._container, opacity); 
      } 
     }, 

     _initLayout: function() { 
      this._container = L.DomUtil.create('div', 'leaflet-label ' + this.options.className + ' leaflet-zoom-animated'); 
      this.updateZIndex(this._zIndex); 
     }, 

     _update: function() { 
      if (!this._map) { return; } 

      this._container.style.visibility = 'hidden'; 

      this._updateContent(); 
      this._updatePosition(); 

      this._container.style.visibility = ''; 
     }, 

     _updateContent: function() { 
      if (!this._content || !this._map || this._prevContent === this._content) { 
       return; 
      } 

      if (typeof this._content === 'string') { 
       this._container.innerHTML = this._content; 

       this._prevContent = this._content; 

       this._labelWidth = this._container.offsetWidth; 
      } 
     }, 

     _updatePosition: function() { 
      var pos = this._map.latLngToLayerPoint(this._latlng); 

      this._setPosition(pos); 
     }, 

     _setPosition: function (pos) { 
      var map = this._map, 
       container = this._container, 
       centerPoint = map.latLngToContainerPoint(map.getCenter()), 
       labelPoint = map.layerPointToContainerPoint(pos), 
       direction = this.options.direction, 
       labelWidth = this._labelWidth, 
       offset = L.point(this.options.offset); 

      // position to the right (right or auto & needs to) 
      if (direction === 'right' || direction === 'auto' && labelPoint.x < centerPoint.x) { 
       L.DomUtil.addClass(container, 'leaflet-label-right'); 
       L.DomUtil.removeClass(container, 'leaflet-label-left'); 

       pos = pos.add(offset); 
      } else { // position to the left 
       L.DomUtil.addClass(container, 'leaflet-label-left'); 
       L.DomUtil.removeClass(container, 'leaflet-label-right'); 

       pos = pos.add(L.point(-offset.x - labelWidth, offset.y)); 
      } 

      L.DomUtil.setPosition(container, pos); 
     }, 

     _zoomAnimation: function (opt) { 
      var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round(); 

      this._setPosition(pos); 
     }, 

     _onMoveEnd: function() { 
      if (!this._animated || this.options.direction === 'auto') { 
       this._updatePosition(); 
      } 
     }, 

     _onViewReset: function (e) { 
      /* if map resets hard, we must update the label */ 
      if (e && e.hard) { 
       this._update(); 
      } 
     }, 

     _initInteraction: function() { 
      if (!this.options.clickable) { return; } 

      var container = this._container, 
       events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; 

      L.DomUtil.addClass(container, 'leaflet-clickable'); 
      L.DomEvent.on(container, 'click', this._onMouseClick, this); 

      for (var i = 0; i < events.length; i++) { 
       L.DomEvent.on(container, events[i], this._fireMouseEvent, this); 
      } 
     }, 

     _removeInteraction: function() { 
      if (!this.options.clickable) { return; } 

      var container = this._container, 
       events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; 

      L.DomUtil.removeClass(container, 'leaflet-clickable'); 
      L.DomEvent.off(container, 'click', this._onMouseClick, this); 

      for (var i = 0; i < events.length; i++) { 
       L.DomEvent.off(container, events[i], this._fireMouseEvent, this); 
      } 
     }, 

     _onMouseClick: function (e) { 
      if (this.hasEventListeners(e.type)) { 
       L.DomEvent.stopPropagation(e); 
      } 

      this.fire(e.type, { 
       originalEvent: e 
      }); 
     }, 

     _fireMouseEvent: function (e) { 
      this.fire(e.type, { 
       originalEvent: e 
      }); 

      // TODO proper custom event propagation 
      // this line will always be called if marker is in a FeatureGroup 
      if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) { 
       L.DomEvent.preventDefault(e); 
      } 
      if (e.type !== 'mousedown') { 
       L.DomEvent.stopPropagation(e); 
      } else { 
       L.DomEvent.preventDefault(e); 
      } 
     } 
    }); 


    /*global LeafletLabel */ 

    // This object is a mixin for L.Marker and L.CircleMarker. We declare it here as both need to include the contents. 
    L.BaseMarkerMethods = { 
     showLabel: function() { 
      if (this.labels && this._map) { 
       for (var labelIndex in this.labels) { 
        this.labels[labelIndex].setLatLng(this._latlng); 
        this._map.showLabel(this.labels[labelIndex]); 
       } 
      } 

      return this; 
     }, 

     hideLabel: function() { 
      if (this.labels) { 
       for (var labelIndex in this.labels) { 
        this.labels[labelIndex].close(); 
       } 
      } 
      return this; 
     }, 

     setLabelNoHide: function (noHide) { 
      if (this._labelNoHide === noHide) { 
       return; 
      } 

      this._labelNoHide = noHide; 

      if (noHide) { 
       this._removeLabelRevealHandlers(); 
       this.showLabel(); 
      } else { 
       this._addLabelRevealHandlers(); 
       this.hideLabel(); 
      } 
     }, 

     bindLabel: function (content, options) { 
      var labelAnchor = this.options.icon ? this.options.icon.options.labelAnchor : this.options.labelAnchor, 
       anchor = L.point(labelAnchor) || L.point(0, 0); 

      anchor = anchor.add(LeafletLabel.prototype.options.offset); 

      if (options && options.offset) { 
       anchor = anchor.add(options.offset); 
      } 

      options = L.Util.extend({ offset: anchor }, options); 

      if (!this.labels) { 
       this._labelNoHide = options.noHide; 
       this.labels = []; 
       if (!this._labelNoHide) { 
        this._addLabelRevealHandlers(); 
       } 

       this 
        .on('remove', this.hideLabel, this) 
        .on('move', this._moveLabel, this) 
        .on('add', this._onMarkerAdd, this); 

       this._hasLabelHandlers = true; 
      } 

      this.labels.push(new LeafletLabel(options, this).setContent(content)); 

      return this; 
     }, 

     unbindLabel: function() { 
      if (this.labels) { 
       this.hideLabel(); 

       this.labels = null; 

       if (this._hasLabelHandlers) { 
        if (!this._labelNoHide) { 
         this._removeLabelRevealHandlers(); 
        } 

        this 
         .off('remove', this.hideLabel, this) 
         .off('move', this._moveLabel, this) 
         .off('add', this._onMarkerAdd, this); 
       } 

       this._hasLabelHandlers = false; 
      } 
      return this; 
     }, 

     updateLabelContent: function (content, index) { 
      if ((this.labels) && (index < this.labels.length)) { 
       this.labels[index].setContent(content); 
      } 
     }, 

     getLabels: function() { 
      return this.labels; 
     }, 

     _onMarkerAdd: function() { 
      if (this._labelNoHide) { 
       this.showLabel(); 
      } 
     }, 

     _addLabelRevealHandlers: function() { 
      this 
       .on('mouseover', this.showLabel, this) 
       .on('mouseout', this.hideLabel, this); 

      if (L.Browser.touch) { 
       this.on('click', this.showLabel, this); 
      } 
     }, 

     _removeLabelRevealHandlers: function() { 
      this 
       .off('mouseover', this.showLabel, this) 
       .off('mouseout', this.hideLabel, this); 

      if (L.Browser.touch) { 
       this.off('click', this.showLabel, this); 
      } 
     }, 

     _moveLabel: function (e) { 
      this.label.setLatLng(e.latlng); 
     } 
    }; 


    // Add in an option to icon that is used to set where the label anchor is 
    L.Icon.Default.mergeOptions({ 
     labelAnchor: new L.Point(9, -20) 
    }); 

    // Have to do this since Leaflet is loaded before this plugin and initializes 
    // L.Marker.options.icon therefore missing our mixin above. 
    L.Marker.mergeOptions({ 
     icon: new L.Icon.Default() 
    }); 

    L.Marker.include(L.BaseMarkerMethods); 
    L.Marker.include({ 
     _originalUpdateZIndex: L.Marker.prototype._updateZIndex, 

     _updateZIndex: function (offset) { 
      var zIndex = this._zIndex + offset; 

      this._originalUpdateZIndex(offset); 

      if (this.labels) { 
       for (var labelIndex in this.labels) { 
        this.labels[labelIndex].updateZIndex(zIndex); 
       } 
      } 
     }, 

     _originalSetOpacity: L.Marker.prototype.setOpacity, 

     setOpacity: function (opacity, labelHasSemiTransparency) { 
      this.options.labelHasSemiTransparency = labelHasSemiTransparency; 

      this._originalSetOpacity(opacity); 
     }, 

     _originalUpdateOpacity: L.Marker.prototype._updateOpacity, 

     _updateOpacity: function() { 
      var absoluteOpacity = this.options.opacity === 0 ? 0 : 1; 

      this._originalUpdateOpacity(); 

      if (this.labels) { 
       for (var labelIndex in labels) { 
        this.labels[labelIndex].setOpacity(this.options.labelHasSemiTransparency ? this.options.opacity : absoluteOpacity); 
       } 
      } 
     }, 

     _originalSetLatLng: L.Marker.prototype.setLatLng, 

     setLatLng: function (latlng) { 
      if (this.labels && !this._labelNoHide) { 
       this.hideLabel(); 
      } 

      return this._originalSetLatLng(latlng); 
     } 
    }); 

    // Add in an option to icon that is used to set where the label anchor is 
    L.CircleMarker.mergeOptions({ 
     labelAnchor: new L.Point(0, 0) 
    }); 


    L.CircleMarker.include(L.BaseMarkerMethods); 

    /*global LeafletLabel */ 

    L.Path.include({ 
     bindLabel: function (content, options) { 
      if (!this.label || this.label.options !== options) { 
       this.label = new LeafletLabel(options, this); 
      } 

      this.label.setContent(content); 

      if (!this._showLabelAdded) { 
       this 
        .on('mouseover', this._showLabel, this) 
        .on('mousemove', this._moveLabel, this) 
        .on('mouseout remove', this._hideLabel, this); 

       if (L.Browser.touch) { 
        this.on('click', this._showLabel, this); 
       } 
       this._showLabelAdded = true; 
      } 

      return this; 
     }, 

     unbindLabel: function() { 
      if (this.label) { 
       this._hideLabel(); 
       this.label = null; 
       this._showLabelAdded = false; 
       this 
        .off('mouseover', this._showLabel, this) 
        .off('mousemove', this._moveLabel, this) 
        .off('mouseout remove', this._hideLabel, this); 
      } 
      return this; 
     }, 

     updateLabelContent: function (content) { 
      if (this.label) { 
       this.label.setContent(content); 
      } 
     }, 

     _showLabel: function (e) { 
      this.label.setLatLng(e.latlng); 
      this._map.showLabel(this.label); 
     }, 

     _moveLabel: function (e) { 
      this.label.setLatLng(e.latlng); 
     }, 

     _hideLabel: function() { 
      this.label.close(); 
     } 
    }); 


    L.Map.include({ 
     showLabel: function (label) { 
      return this.addLayer(label); 
     } 
    }); 

    L.FeatureGroup.include({ 
     // TODO: remove this when AOP is supported in Leaflet, need this as we cannot put code in removeLayer() 
     clearLayers: function() { 
      this.unbindLabel(); 
      this.eachLayer(this.removeLayer, this); 
      return this; 
     }, 

     bindLabel: function (content, options) { 
      return this.invoke('bindLabel', content, options); 
     }, 

     unbindLabel: function() { 
      return this.invoke('unbindLabel'); 
     }, 

     updateLabelContent: function (content) { 
      this.invoke('updateLabelContent', content); 
     } 
    }); 

    return LeafletLabel; 
}, window)); 
Смежные вопросы