如何使用leaflet.label绑定多个标签

How to bind multiple labels using leaflet.label?

本文关键字:标签 绑定 label 何使用 leaflet      更新时间:2023-09-26

我正在使用传单,它运行良好。我也在使用leaflet.label,效果也很好。问题是,我想在标记的右侧显示两个标签。如果我调用bindLabel两次,那么第二次会覆盖第一次。我如何确保我有两个标签,都在标记的右边,第二个标签在第一个标签的上方?

我就是这样尝试的:

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

感谢

编辑:

我已经设法使用对bindLabel的一次调用来显示文本,如下所示:

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

但这似乎是一个过于棘手的解决方案。在这里,他们说这是不可能的,但这是在2014年写的。从那时起也许是可能的。

我已经设法解决了这个问题。我现在懒得把它推到他们的回购中,但我将来可能会这么做。解决方案的逻辑如下:

  • this.label->this.labels
  • this.labelsLeafletLabel的数组
  • 将更改应用于包含this.label的方法
  • this._labelNoHide=options.noHide移动到if中以防止错误

标签将类似地用于单独处理/标记的options的子集。抱歉,伙计们,将noHideopacity单独化为标签级别而不是标记级别超出了这个问题的范围。不过我以后可能会解决这些问题。

代码如下:

/*
    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));