diff --git a/build/deps.js b/build/deps.js
index ec5136d0cff..cdbb00a355c 100644
--- a/build/deps.js
+++ b/build/deps.js
@@ -69,7 +69,7 @@ var deps = {
Popup: {
src: [
- 'layer/PopupBase.js',
+ 'layer/DivOverlay.js',
'layer/Popup.js',
'layer/Layer.Popup.js',
'layer/marker/Marker.Popup.js'
@@ -78,14 +78,14 @@ var deps = {
desc: 'Used to display the map popup (used mostly for binding HTML data to markers and paths on click).'
},
- Label: {
+ Tooltip: {
src: [
- 'layer/Label.js',
- 'layer/Layer.Label.js',
- 'layer/marker/Marker.Label.js'
+ 'layer/Tooltip.js',
+ 'layer/Layer.Tooltip.js',
+ 'layer/marker/Marker.Tooltip.js'
],
deps: ['Popup', 'Marker'],
- desc: 'Used to display the map label (used mostly for binding short descriptions to markers and paths on mouseover).'
+ desc: 'Used to display the map tooltip (used mostly for binding short descriptions to markers and paths on mouseover).'
},
LayerGroup: {
diff --git a/build/docs-index.leafdoc b/build/docs-index.leafdoc
index af7f6f61ff7..a2daea29e9e 100644
--- a/build/docs-index.leafdoc
+++ b/build/docs-index.leafdoc
@@ -7,7 +7,7 @@ This file just defines the order of the classes in the docs.
@class Marker
@class Popup
-@class Label
+@class Tooltip
@class TileLayer
@class TileLayer.WMS
diff --git a/build/leafdoc-templates/html.hbs b/build/leafdoc-templates/html.hbs
index e7068563aa1..8cd19541ee4 100644
--- a/build/leafdoc-templates/html.hbs
+++ b/build/leafdoc-templates/html.hbs
@@ -43,7 +43,7 @@
Raster Layers
diff --git a/debug/map/label.html b/debug/map/label.html
deleted file mode 100644
index 67aeee499d1..00000000000
--- a/debug/map/label.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
- Leaflet debug page
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/debug/map/tooltip.html b/debug/map/tooltip.html
new file mode 100644
index 00000000000..73d799297e4
--- /dev/null
+++ b/debug/map/tooltip.html
@@ -0,0 +1,69 @@
+
+
+
+ Leaflet debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dist/leaflet.css b/dist/leaflet.css
index ed58635f5b3..32ea2246e4d 100644
--- a/dist/leaflet.css
+++ b/dist/leaflet.css
@@ -84,7 +84,7 @@
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
-.leaflet-label-pane { z-index: 650; }
+.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
@@ -539,9 +539,9 @@
}
-/* Label */
+/* Tooltip */
/* Base styles for the element that has a tooltip */
-.leaflet-label {
+.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
@@ -555,14 +555,14 @@
user-select: none;
pointer-events: none;
}
-.leaflet-label.leaflet-clickable {
+.leaflet-tooltip.leaflet-clickable {
cursor: pointer;
pointer-events: auto;
}
-.leaflet-label-top:before,
-.leaflet-label-bottom:before,
-.leaflet-label-left:before,
-.leaflet-label-right:before {
+.leaflet-tooltip-top:before,
+.leaflet-tooltip-bottom:before,
+.leaflet-tooltip-left:before,
+.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
@@ -572,33 +572,33 @@
/* Directions */
-.leaflet-label-bottom:before,
-.leaflet-label-top:before {
+.leaflet-tooltip-bottom:before,
+.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
-.leaflet-label-top:before {
+.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
-.leaflet-label-bottom:before {
+.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
-.leaflet-label-left:before,
-.leaflet-label-right:before {
+.leaflet-tooltip-left:before,
+.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
-.leaflet-label-left:before {
+.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
-.leaflet-label-right:before {
+.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
diff --git a/spec/index.html b/spec/index.html
index 320a8033f67..781e17d2e4f 100644
--- a/spec/index.html
+++ b/spec/index.html
@@ -67,7 +67,7 @@
-
+
diff --git a/spec/suites/layer/LabelSpec.js b/spec/suites/layer/TooltipSpec.js
similarity index 61%
rename from spec/suites/layer/LabelSpec.js
rename to spec/suites/layer/TooltipSpec.js
index d0d0197524c..58e99b363f7 100644
--- a/spec/suites/layer/LabelSpec.js
+++ b/spec/suites/layer/TooltipSpec.js
@@ -1,4 +1,4 @@
-describe('Label', function () {
+describe('Tooltip', function () {
var c, map, p2ll,
center = [55.8, 37.6];
@@ -26,30 +26,30 @@ describe('Label', function () {
it("opens on marker mouseover and close on mouseout", function () {
var layer = new L.Marker(center).addTo(map);
- layer.bindLabel('Label');
+ layer.bindTooltip('Tooltip');
happen.mouseover(layer._icon, {relatedTarget: map._container});
- expect(map.hasLayer(layer._label)).to.be(true);
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.mouseout(layer._icon, {relatedTarget: map._container});
- expect(map.hasLayer(layer._label)).to.be(false);
+ expect(map.hasLayer(layer._tooltip)).to.be(false);
});
it("stays open on marker when permanent", function () {
var layer = new L.Marker(center).addTo(map);
- layer.bindLabel('Label', {permanent: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('Tooltip', {permanent: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
});
it("is removed when removing marker", function () {
var layer = new L.Marker(center).addTo(map);
- layer.bindLabel('Label', {permanent: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('Tooltip', {permanent: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
layer.remove();
- expect(map.hasLayer(layer._label)).to.be(false);
+ expect(map.hasLayer(layer._tooltip)).to.be(false);
});
it("can be made interactive", function () {
@@ -57,8 +57,8 @@ describe('Label', function () {
var spy = sinon.spy();
layer.on('click', spy);
- layer.bindLabel('Label', {permanent: true, interactive: true});
- happen.click(layer._label._container);
+ layer.bindTooltip('Tooltip', {permanent: true, interactive: true});
+ happen.click(layer._tooltip._container);
expect(spy.calledOnce).to.be(true);
});
@@ -67,8 +67,8 @@ describe('Label', function () {
var spy = sinon.spy();
layer.on('click', spy);
- layer.bindLabel('A long label that should be displayed on the left', {permanent: true, direction: 'left', interactive: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('A long tooltip that should be displayed on the left', {permanent: true, direction: 'left', interactive: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.at('click', 150, 180); // Marker is on the map center, which is 400px large.
expect(spy.calledOnce).to.be(true);
});
@@ -78,8 +78,8 @@ describe('Label', function () {
var spy = sinon.spy();
layer.on('click', spy);
- layer.bindLabel('A label that should be displayed on the top', {permanent: true, direction: 'top', interactive: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('A tooltip that should be displayed on the top', {permanent: true, direction: 'top', interactive: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.at('click', 200, 170); // Marker is on the map center, which is 400px large.
expect(spy.calledOnce).to.be(true);
});
@@ -89,8 +89,8 @@ describe('Label', function () {
var spy = sinon.spy();
layer.on('click', spy);
- layer.bindLabel('A label that should be displayed on the top', {permanent: true, direction: 'bottom', interactive: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('A tooltip that should be displayed on the top', {permanent: true, direction: 'bottom', interactive: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.at('click', 200, 210); // Marker is on the map center, which is 400px large.
expect(spy.calledOnce).to.be(true);
});
@@ -100,84 +100,84 @@ describe('Label', function () {
var spy = sinon.spy();
layer.on('click', spy);
- layer.bindLabel('A label that should be displayed on the center', {permanent: true, direction: 'center', interactive: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('A tooltip that should be displayed on the center', {permanent: true, direction: 'center', interactive: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.at('click', 150, 180); // Marker is on the map center, which is 400px large.
expect(spy.calledOnce).to.be(true);
});
it("honours opacity option", function () {
var layer = new L.Marker(center).addTo(map);
- layer.bindLabel('Label', {permanent: true, opacity: 0.57});
- expect(layer._label._container.style.opacity).to.eql(0.57);
+ layer.bindTooltip('Tooltip', {permanent: true, opacity: 0.57});
+ expect(layer._tooltip._container.style.opacity).to.eql(0.57);
});
it("can change opacity with setOpacity", function () {
var layer = new L.Marker(center).addTo(map);
- layer.bindLabel('Label', {permanent: true});
- expect(layer._label._container.style.opacity).to.eql(0.9);
- layer._label.setOpacity(0.57);
- expect(layer._label._container.style.opacity).to.eql(0.57);
+ layer.bindTooltip('Tooltip', {permanent: true});
+ expect(layer._tooltip._container.style.opacity).to.eql(0.9);
+ layer._tooltip.setOpacity(0.57);
+ expect(layer._tooltip._container.style.opacity).to.eql(0.57);
});
- it("it should use a label with a function as content with a FeatureGroup", function () {
+ it("it should use a tooltip with a function as content with a FeatureGroup", function () {
var marker1 = new L.Marker(new L.LatLng(55.8, 37.6), {description: "I'm marker 1."});
var marker2 = new L.Marker(new L.LatLng(54.6, 38.2), {description: "I'm marker 2."});
var group = new L.FeatureGroup([marker1, marker2]).addTo(map);
- group.bindLabel(function (layer) {
+ group.bindTooltip(function (layer) {
return layer.options.description;
});
// toggle popup on marker1
happen.mouseover(marker1._icon, {relatedTarget: map._container});
- expect(map.hasLayer(group._label)).to.be(true);
- expect(group._label._container.innerHTML).to.be("I'm marker 1.");
+ expect(map.hasLayer(group._tooltip)).to.be(true);
+ expect(group._tooltip._container.innerHTML).to.be("I'm marker 1.");
// toggle popup on marker2
happen.mouseover(marker2._icon, {relatedTarget: map._container});
- expect(map.hasLayer(group._label)).to.be(true);
- expect(group._label._container.innerHTML).to.be("I'm marker 2.");
+ expect(map.hasLayer(group._tooltip)).to.be(true);
+ expect(group._tooltip._container.innerHTML).to.be("I'm marker 2.");
});
it("opens on polygon mouseover and close on mouseout", function () {
var layer = new L.Polygon([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map);
- layer.bindLabel('Label');
+ layer.bindTooltip('Tooltip');
happen.mouseover(layer._path, {relatedTarget: map._container});
- expect(map.hasLayer(layer._label)).to.be(true);
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.mouseout(layer._path, {relatedTarget: map._container});
- expect(map.hasLayer(layer._label)).to.be(false);
+ expect(map.hasLayer(layer._tooltip)).to.be(false);
});
it("stays open on polygon when permanent", function () {
var layer = new L.Polygon([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map);
- layer.bindLabel('Label', {permanent: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('Tooltip', {permanent: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
});
it("opens on polyline mouseover and close on mouseout", function () {
var layer = new L.Polyline([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map);
- layer.bindLabel('Label');
+ layer.bindTooltip('Tooltip');
happen.mouseover(layer._path, {relatedTarget: map._container});
- expect(map.hasLayer(layer._label)).to.be(true);
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
happen.mouseout(layer._path, {relatedTarget: map._container});
- expect(map.hasLayer(layer._label)).to.be(false);
+ expect(map.hasLayer(layer._tooltip)).to.be(false);
});
it("stays open on marker when permanent", function () {
var layer = new L.Polyline([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map);
- layer.bindLabel('Label', {permanent: true});
- expect(map.hasLayer(layer._label)).to.be(true);
+ layer.bindTooltip('Tooltip', {permanent: true});
+ expect(map.hasLayer(layer._tooltip)).to.be(true);
});
});
diff --git a/src/core/Events.leafdoc b/src/core/Events.leafdoc
index 0b29e016e6d..097d48aa080 100644
--- a/src/core/Events.leafdoc
+++ b/src/core/Events.leafdoc
@@ -114,10 +114,10 @@ GeoJSON ID of the feature (if present).
@property popup: Popup
The popup that was opened or closed.
-@miniclass LabelEvent (Event objects)
+@miniclass TooltipEvent (Event objects)
@inherits Event
-@property label: Label
-The label that was opened or closed.
+@property tooltip: Tooltip
+The tooltip that was opened or closed.
@miniclass DragEndEvent (Event objects)
@inherits Event
diff --git a/src/layer/PopupBase.js b/src/layer/DivOverlay.js
similarity index 92%
rename from src/layer/PopupBase.js
rename to src/layer/DivOverlay.js
index 69dea1c4664..435511da05a 100644
--- a/src/layer/PopupBase.js
+++ b/src/layer/DivOverlay.js
@@ -1,8 +1,8 @@
/*
- * @class PopupBase
+ * @class DivOverlay
* @inherits Layer
- * @aka L.PopupBase
- * Base model for L.Popup and L.Label. Inherit from it for very custom popup like plugins.
+ * @aka L.DivOverlay
+ * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
*/
/* @namespace Map
@@ -14,11 +14,11 @@ L.Map.mergeOptions({
closePopupOnClick: true
});
-// @namespace PopupBase
-L.PopupBase = L.Layer.extend({
+// @namespace DivOverlay
+L.DivOverlay = L.Layer.extend({
// @section
- // @aka PopupBase options
+ // @aka DivOverlay options
options: {
// @option offset: Point = Point(0, 7)
// The offset of the popup position. Useful to control the anchor
diff --git a/src/layer/Label.js b/src/layer/Label.js
deleted file mode 100644
index 0c90dc39e69..00000000000
--- a/src/layer/Label.js
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * @class Label
- * @inherits PopupBase
- * @aka L.Label
- * Used to display small texts on top of map layers.
- *
- * @example
- *
- * ```js
- * marker.bindLabel("my label text").openLabel();
- * ```
- * Note about label offset. Leaflet takes two options in consideration
- * for computing label offseting:
- * - the `offset` Label option: it defaults to [6, -6], because the label
- * tip is 6px width and height. Remember to change this value if you override
- * the tip in CSS.
- * - the `labelAnchor` Icon option: this will only be considered for Marker. You
- * should adapt this value if you use a custom icon.
- */
-
-
-// @namespace Label
-L.Label = L.PopupBase.extend({
-
- // @section
- // @aka Label options
- options: {
- // @option pane: String = 'labelPane'
- // `Map pane` where the label will be added.
- pane: 'labelPane',
-
- // @option offset: Point = Point(6, -6)
- // The offset of the label position. Update it if you customize the
- // label tip in CSS.
- offset: [6, -6],
-
- // @option direction: String = 'auto'
- // Direction where to open the label. Possible values are: `right`, `left`,
- // `top`, `bottom`, `center`, `auto`.
- // `auto` will dynamicaly switch between `right` and `left` according to the label
- // position on the map.
- direction: 'auto',
-
- // @option permanent: Boolean = false
- // Whether to open the label permanently or only on mouseover.
- permanent: false,
-
- // @option sticky: Boolean = false
- // If true, the label will follow the mouse instead of being fixed at the feature center.
- sticky: false,
-
- // @option interactive: Boolean = false
- // If true, the label will listen to the feature events.
- interactive: false,
-
- // @option opacity: Number = 0.9
- // Label container opacity.
- opacity: 0.9
- },
-
- onAdd: function (map) {
- L.PopupBase.prototype.onAdd.call(this, map);
- this.setOpacity(this.options.opacity);
-
- // @namespace Map
- // @section Label events
- // @event labelopen: LabelEvent
- // Fired when a label is opened in the map.
- map.fire('labelopen', {label: this});
-
- if (this._source) {
- // @namespace Layer
- // @section Label events
- // @event labelopen: LabelEvent
- // Fired when a label bound to this layer is opened.
- this._source.fire('labelopen', {label: this}, true);
- }
- },
-
- onRemove: function (map) {
- L.PopupBase.prototype.onRemove.call(this, map);
-
- // @namespace Map
- // @section Label events
- // @event labelclose: LabelEvent
- // Fired when a label in the map is closed.
- map.fire('labelclose', {label: this});
-
- if (this._source) {
- // @namespace Layer
- // @section Label events
- // @event labelclose: LabelEvent
- // Fired when a label bound to this layer is closed.
- this._source.fire('labelclose', {label: this}, true);
- }
- },
-
- _close: function () {
- if (this._map) {
- this._map.closeLabel(this);
- }
- },
-
- _initLayout: function () {
- var prefix = 'leaflet-label',
- className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
-
- this._contentNode = this._container = L.DomUtil.create('div', className);
- },
-
- _updateLayout: function () {},
-
- _adjustPan: function () {},
-
- _updatePosition: function () {
- var map = this._map,
- pos = map.latLngToLayerPoint(this._latlng),
- container = this._container,
- centerPoint = map.latLngToContainerPoint(map.getCenter()),
- labelPoint = map.layerPointToContainerPoint(pos),
- direction = this.options.direction,
- labelWidth = container.offsetWidth,
- labelHeight = container.offsetHeight,
- offset = L.point(this.options.offset),
- anchor = this._getAnchor();
-
- if (direction === 'top') {
- pos = pos.add(L.point(-labelWidth / 2, -labelHeight + offset.y + anchor.y));
- } else if (direction === 'bottom') {
- pos = pos.subtract(L.point(labelWidth / 2, offset.y));
- } else if (direction === 'center') {
- pos = pos.subtract(L.point(labelWidth / 2, labelHeight / 2 - anchor.y));
- } else if (direction === 'right' || direction === 'auto' && labelPoint.x < centerPoint.x) {
- direction = 'right';
- pos = pos.add([offset.x + anchor.x, anchor.y - labelHeight / 2]);
- } else {
- direction = 'left';
- pos = pos.subtract(L.point(offset.x + labelWidth + anchor.x, labelHeight / 2 - anchor.y));
- }
-
- L.DomUtil.removeClass(container, 'leaflet-label-right');
- L.DomUtil.removeClass(container, 'leaflet-label-left');
- L.DomUtil.removeClass(container, 'leaflet-label-top');
- L.DomUtil.removeClass(container, 'leaflet-label-bottom');
- L.DomUtil.addClass(container, 'leaflet-label-' + direction);
- L.DomUtil.setPosition(container, pos);
- },
-
- setOpacity: function (opacity) {
- this.options.opacity = opacity;
-
- if (this._container) {
- L.DomUtil.setOpacity(this._container, opacity);
- }
- },
-
- _animateZoom: function (e) {
- var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center), offset;
- if (this.options.offset) {
- offset = L.point(this.options.offset);
- pos = pos.add(offset);
- }
- L.DomUtil.setPosition(this._container, pos);
- },
-
- _getAnchor: function () {
- // Where should we anchor the label on the source layer?
- return L.point(this._source._getLabelAnchor && !this.options.sticky ? this._source._getLabelAnchor() : [0, 0]);
- }
-
-});
-
-// @namespace Label
-// @factory L.label(options?: Label options, source?: Layer)
-// Instantiates a Label object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the label with a reference to the Layer to which it refers.
-L.label = function (options, source) {
- return new L.Label(options, source);
-};
-
-// @namespace Map
-// @section Methods for Layers and Controls
-L.Map.include({
-
- // @method openLabel(label: Label): this
- // Opens the specified label.
- // @alternative
- // @method openLabel(content: String|HTMLElement, latlng: LatLng, options?: Label options): this
- // Creates a label with the specified content and options and open it.
- openLabel: function (label, latlng, options) {
- if (!(label instanceof L.Label)) {
- label = new L.Label(options).setContent(label);
- }
-
- if (latlng) {
- label.setLatLng(latlng);
- }
-
- if (this.hasLayer(label)) {
- return this;
- }
-
- return this.addLayer(label);
- },
-
- // @method closeLabel(label?: Label): this
- // Closes the label given as parameter.
- closeLabel: function (label) {
- if (label) {
- this.removeLayer(label);
- }
- return this;
- }
-
-});
diff --git a/src/layer/Layer.Label.js b/src/layer/Layer.Label.js
deleted file mode 100644
index b4a7cab7dbf..00000000000
--- a/src/layer/Layer.Label.js
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * @namespace Layer
- * @section Label methods example
- *
- * All layers share a set of methods convenient for binding labels to it.
- *
- * ```js
- * var layer = L.Polygon(latlngs).bindLabel('Hi There!').addTo(map);
- * layer.openLabel();
- * layer.closeLabel();
- * ```
- */
-
-// @section Label methods
-L.Layer.include({
-
- // @method bindLabel(content: String|HTMLElement|Function|Label, options?: Label options): this
- // Binds a label to the layer with the passed `content` and sets up the
- // neccessary event listeners. If a `Function` is passed it will receive
- // the layer as the first argument and should return a `String` or `HTMLElement`.
- bindLabel: function (content, options) {
-
- if (content instanceof L.Label) {
- L.setOptions(content, options);
- this._label = content;
- content._source = this;
- } else {
- if (!this._label || options) {
- this._label = L.label(options, this);
- }
- this._label.setContent(content);
-
- }
-
- this._initLabelInteractions();
-
- if (this._label.options.permanent) { this.openLabel(); }
-
- return this;
- },
-
- // @method unbindLabel(): this
- // Removes the label previously bound with `bindLabel`.
- unbindLabel: function () {
- if (this._label) {
- this._initLabelInteractions(true);
- this.closeLabel();
- this._label = null;
- }
- return this;
- },
-
- _initLabelInteractions: function (remove) {
- if (!remove && this._labelHandlersAdded) { return; }
- var onOff = remove ? 'off' : 'on',
- events = {
- remove: this.closeLabel,
- move: this._moveLabel
- };
- if (!this._label.options.permanent) {
- events.mouseover = this._openLabel;
- events.mouseout = this.closeLabel;
- if (this._label.options.sticky) {
- events.mousemove = this._moveLabel;
- }
- if (L.Browser.touch) {
- events.click = this._openLabel;
- }
- }
- this[onOff](events);
- this._labelHandlersAdded = !remove;
- },
-
- // @method openLabel(latlng?: LatLng): this
- // Opens the bound label at the specificed `latlng` or at the default label anchor if no `latlng` is passed.
- openLabel: function (layer, latlng) {
- if (!(layer instanceof L.Layer)) {
- latlng = layer;
- layer = this;
- }
-
- if (layer instanceof L.FeatureGroup) {
- for (var id in this._layers) {
- layer = this._layers[id];
- break;
- }
- }
-
- if (!latlng) {
- latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
- }
-
- if (this._label && this._map) {
-
- // set label source to this layer
- this._label._source = layer;
-
- // update the label (content, layout, ect...)
- this._label.update();
-
- // open the label on the map
- this._map.openLabel(this._label, latlng);
-
- // Label container may not be defined if not permanent and never
- // opened.
- if (this._label.options.interactive && this._label._container) {
- L.DomUtil.addClass(this._label._container, 'leaflet-clickable');
- this.addInteractiveTarget(this._label._container);
- }
- }
-
- return this;
- },
-
- // @method closeLabel(): this
- // Closes the label bound to this layer if it is open.
- closeLabel: function () {
- if (this._label) {
- this._label._close();
- if (this._label.options.interactive) {
- L.DomUtil.removeClass(this._label._container, 'leaflet-clickable');
- this.removeInteractiveTarget(this._label._container);
- }
- }
- return this;
- },
-
- // @method toggleLabel(): this
- // Opens or closes the label bound to this layer depending on its current state.
- toggleLabel: function (target) {
- if (this._label) {
- if (this._label._map) {
- this.closeLabel();
- } else {
- this.openLabel(target);
- }
- }
- return this;
- },
-
- // @method isLabelOpen(): boolean
- // Returns `true` if the label bound to this layer is currently open.
- isLabelOpen: function () {
- return this._label.isOpen();
- },
-
- // @method setLabelContent(content: String|HTMLElement|Label): this
- // Sets the content of the label bound to this layer.
- setLabelContent: function (content) {
- if (this._label) {
- this._label.setContent(content);
- }
- return this;
- },
-
- // @method getLabel(): Label
- // Returns the label bound to this layer.
- getLabel: function () {
- return this._label;
- },
-
- _openLabel: function (e) {
- var layer = e.layer || e.target;
-
- if (!this._label || !this._map) {
- return;
- }
- this.openLabel(layer, this._label.options.sticky ? e.latlng : undefined);
- },
-
- _moveLabel: function (e) {
- var latlng = e.latlng, containerPoint, layerPoint;
- if (this._label.options.sticky && e.originalEvent) {
- containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
- layerPoint = this._map.containerPointToLayerPoint(containerPoint);
- latlng = this._map.layerPointToLatLng(layerPoint);
- }
- this._label.setLatLng(latlng);
- }
-});
diff --git a/src/layer/Layer.Tooltip.js b/src/layer/Layer.Tooltip.js
new file mode 100644
index 00000000000..57e8dd56a59
--- /dev/null
+++ b/src/layer/Layer.Tooltip.js
@@ -0,0 +1,180 @@
+/*
+ * @namespace Layer
+ * @section Tooltip methods example
+ *
+ * All layers share a set of methods convenient for binding tooltips to it.
+ *
+ * ```js
+ * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
+ * layer.openTooltip();
+ * layer.closeTooltip();
+ * ```
+ */
+
+// @section Tooltip methods
+L.Layer.include({
+
+ // @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
+ // Binds a tooltip to the layer with the passed `content` and sets up the
+ // neccessary event listeners. If a `Function` is passed it will receive
+ // the layer as the first argument and should return a `String` or `HTMLElement`.
+ bindTooltip: function (content, options) {
+
+ if (content instanceof L.Tooltip) {
+ L.setOptions(content, options);
+ this._tooltip = content;
+ content._source = this;
+ } else {
+ if (!this._tooltip || options) {
+ this._tooltip = L.tooltip(options, this);
+ }
+ this._tooltip.setContent(content);
+
+ }
+
+ this._initTooltipInteractions();
+
+ if (this._tooltip.options.permanent) { this.openTooltip(); }
+
+ return this;
+ },
+
+ // @method unbindTooltip(): this
+ // Removes the tooltip previously bound with `bindTooltip`.
+ unbindTooltip: function () {
+ if (this._tooltip) {
+ this._initTooltipInteractions(true);
+ this.closeTooltip();
+ this._tooltip = null;
+ }
+ return this;
+ },
+
+ _initTooltipInteractions: function (remove) {
+ if (!remove && this._tooltipHandlersAdded) { return; }
+ var onOff = remove ? 'off' : 'on',
+ events = {
+ remove: this.closeTooltip,
+ move: this._moveTooltip
+ };
+ if (!this._tooltip.options.permanent) {
+ events.mouseover = this._openTooltip;
+ events.mouseout = this.closeTooltip;
+ if (this._tooltip.options.sticky) {
+ events.mousemove = this._moveTooltip;
+ }
+ if (L.Browser.touch) {
+ events.click = this._openTooltip;
+ }
+ }
+ this[onOff](events);
+ this._tooltipHandlersAdded = !remove;
+ },
+
+ // @method openTooltip(latlng?: LatLng): this
+ // Opens the bound tooltip at the specificed `latlng` or at the default tooltip anchor if no `latlng` is passed.
+ openTooltip: function (layer, latlng) {
+ if (!(layer instanceof L.Layer)) {
+ latlng = layer;
+ layer = this;
+ }
+
+ if (layer instanceof L.FeatureGroup) {
+ for (var id in this._layers) {
+ layer = this._layers[id];
+ break;
+ }
+ }
+
+ if (!latlng) {
+ latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
+ }
+
+ if (this._tooltip && this._map) {
+
+ // set tooltip source to this layer
+ this._tooltip._source = layer;
+
+ // update the tooltip (content, layout, ect...)
+ this._tooltip.update();
+
+ // open the tooltip on the map
+ this._map.openTooltip(this._tooltip, latlng);
+
+ // Tooltip container may not be defined if not permanent and never
+ // opened.
+ if (this._tooltip.options.interactive && this._tooltip._container) {
+ L.DomUtil.addClass(this._tooltip._container, 'leaflet-clickable');
+ this.addInteractiveTarget(this._tooltip._container);
+ }
+ }
+
+ return this;
+ },
+
+ // @method closeTooltip(): this
+ // Closes the tooltip bound to this layer if it is open.
+ closeTooltip: function () {
+ if (this._tooltip) {
+ this._tooltip._close();
+ if (this._tooltip.options.interactive) {
+ L.DomUtil.removeClass(this._tooltip._container, 'leaflet-clickable');
+ this.removeInteractiveTarget(this._tooltip._container);
+ }
+ }
+ return this;
+ },
+
+ // @method toggleTooltip(): this
+ // Opens or closes the tooltip bound to this layer depending on its current state.
+ toggleTooltip: function (target) {
+ if (this._tooltip) {
+ if (this._tooltip._map) {
+ this.closeTooltip();
+ } else {
+ this.openTooltip(target);
+ }
+ }
+ return this;
+ },
+
+ // @method isTooltipOpen(): boolean
+ // Returns `true` if the tooltip bound to this layer is currently open.
+ isTooltipOpen: function () {
+ return this._tooltip.isOpen();
+ },
+
+ // @method setTooltipContent(content: String|HTMLElement|Tooltip): this
+ // Sets the content of the tooltip bound to this layer.
+ setTooltipContent: function (content) {
+ if (this._tooltip) {
+ this._tooltip.setContent(content);
+ }
+ return this;
+ },
+
+ // @method getTooltip(): Tooltip
+ // Returns the tooltip bound to this layer.
+ getTooltip: function () {
+ return this._tooltip;
+ },
+
+ _openTooltip: function (e) {
+ var layer = e.layer || e.target;
+
+ if (!this._tooltip || !this._map) {
+ return;
+ }
+ this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
+ },
+
+ _moveTooltip: function (e) {
+ var latlng = e.latlng, containerPoint, layerPoint;
+ if (this._tooltip.options.sticky && e.originalEvent) {
+ containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
+ layerPoint = this._map.containerPointToLayerPoint(containerPoint);
+ latlng = this._map.layerPointToLatLng(layerPoint);
+ }
+ this._tooltip.setLatLng(latlng);
+ }
+});
diff --git a/src/layer/Popup.js b/src/layer/Popup.js
index 1969b33edbd..138c146317f 100644
--- a/src/layer/Popup.js
+++ b/src/layer/Popup.js
@@ -1,6 +1,6 @@
/*
* @class Popup
- * @inherits PopupBase
+ * @inherits DivOverlay
* @aka L.Popup
* Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
* open popups while making sure that only one popup is open at one time
@@ -26,7 +26,7 @@
// @namespace Popup
-L.Popup = L.PopupBase.extend({
+L.Popup = L.DivOverlay.extend({
// @section
// @aka Popup options
@@ -88,7 +88,7 @@ L.Popup = L.PopupBase.extend({
},
onAdd: function (map) {
- L.PopupBase.prototype.onAdd.call(this, map);
+ L.DivOverlay.prototype.onAdd.call(this, map);
// @namespace Map
// @section Popup events
@@ -107,7 +107,7 @@ L.Popup = L.PopupBase.extend({
},
onRemove: function (map) {
- L.PopupBase.prototype.onRemove.call(this, map);
+ L.DivOverlay.prototype.onRemove.call(this, map);
// @namespace Map
// @section Popup events
@@ -126,7 +126,7 @@ L.Popup = L.PopupBase.extend({
},
getEvents: function () {
- var events = L.PopupBase.prototype.getEvents.call(this);
+ var events = L.DivOverlay.prototype.getEvents.call(this);
if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
events.preclick = this._close;
diff --git a/src/layer/Tooltip.js b/src/layer/Tooltip.js
new file mode 100644
index 00000000000..f3928d5f353
--- /dev/null
+++ b/src/layer/Tooltip.js
@@ -0,0 +1,214 @@
+/*
+ * @class Tooltip
+ * @inherits DivOverlay
+ * @aka L.Tooltip
+ * Used to display small texts on top of map layers.
+ *
+ * @example
+ *
+ * ```js
+ * marker.bindTooltip("my tooltip text").openTooltip();
+ * ```
+ * Note about tooltip offset. Leaflet takes two options in consideration
+ * for computing tooltip offseting:
+ * - the `offset` Tooltip option: it defaults to [6, -6], because the tooltip
+ * tip is 6px width and height. Remember to change this value if you override
+ * the tip in CSS.
+ * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
+ * should adapt this value if you use a custom icon.
+ */
+
+
+// @namespace Tooltip
+L.Tooltip = L.DivOverlay.extend({
+
+ // @section
+ // @aka Tooltip options
+ options: {
+ // @option pane: String = 'tooltipPane'
+ // `Map pane` where the tooltip will be added.
+ pane: 'tooltipPane',
+
+ // @option offset: Point = Point(6, -6)
+ // The offset of the tooltip position. Update it if you customize the
+ // tooltip tip in CSS.
+ offset: [6, -6],
+
+ // @option direction: String = 'auto'
+ // Direction where to open the tooltip. Possible values are: `right`, `left`,
+ // `top`, `bottom`, `center`, `auto`.
+ // `auto` will dynamicaly switch between `right` and `left` according to the tooltip
+ // position on the map.
+ direction: 'auto',
+
+ // @option permanent: Boolean = false
+ // Whether to open the tooltip permanently or only on mouseover.
+ permanent: false,
+
+ // @option sticky: Boolean = false
+ // If true, the tooltip will follow the mouse instead of being fixed at the feature center.
+ sticky: false,
+
+ // @option interactive: Boolean = false
+ // If true, the tooltip will listen to the feature events.
+ interactive: false,
+
+ // @option opacity: Number = 0.9
+ // Tooltip container opacity.
+ opacity: 0.9
+ },
+
+ onAdd: function (map) {
+ L.DivOverlay.prototype.onAdd.call(this, map);
+ this.setOpacity(this.options.opacity);
+
+ // @namespace Map
+ // @section Tooltip events
+ // @event tooltipopen: TooltipEvent
+ // Fired when a tooltip is opened in the map.
+ map.fire('tooltipopen', {tooltip: this});
+
+ if (this._source) {
+ // @namespace Layer
+ // @section Tooltip events
+ // @event tooltipopen: TooltipEvent
+ // Fired when a tooltip bound to this layer is opened.
+ this._source.fire('tooltipopen', {tooltip: this}, true);
+ }
+ },
+
+ onRemove: function (map) {
+ L.DivOverlay.prototype.onRemove.call(this, map);
+
+ // @namespace Map
+ // @section Tooltip events
+ // @event tooltipclose: TooltipEvent
+ // Fired when a tooltip in the map is closed.
+ map.fire('tooltipclose', {tooltip: this});
+
+ if (this._source) {
+ // @namespace Layer
+ // @section Tooltip events
+ // @event tooltipclose: TooltipEvent
+ // Fired when a tooltip bound to this layer is closed.
+ this._source.fire('tooltipclose', {tooltip: this}, true);
+ }
+ },
+
+ _close: function () {
+ if (this._map) {
+ this._map.closeTooltip(this);
+ }
+ },
+
+ _initLayout: function () {
+ var prefix = 'leaflet-tooltip',
+ className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
+
+ this._contentNode = this._container = L.DomUtil.create('div', className);
+ },
+
+ _updateLayout: function () {},
+
+ _adjustPan: function () {},
+
+ _updatePosition: function () {
+ var map = this._map,
+ pos = map.latLngToLayerPoint(this._latlng),
+ container = this._container,
+ centerPoint = map.latLngToContainerPoint(map.getCenter()),
+ tooltipPoint = map.layerPointToContainerPoint(pos),
+ direction = this.options.direction,
+ tooltipWidth = container.offsetWidth,
+ tooltipHeight = container.offsetHeight,
+ offset = L.point(this.options.offset),
+ anchor = this._getAnchor();
+
+ if (direction === 'top') {
+ pos = pos.add(L.point(-tooltipWidth / 2, -tooltipHeight + offset.y + anchor.y));
+ } else if (direction === 'bottom') {
+ pos = pos.subtract(L.point(tooltipWidth / 2, offset.y));
+ } else if (direction === 'center') {
+ pos = pos.subtract(L.point(tooltipWidth / 2, tooltipHeight / 2 - anchor.y));
+ } else if (direction === 'right' || direction === 'auto' && tooltipPoint.x < centerPoint.x) {
+ direction = 'right';
+ pos = pos.add([offset.x + anchor.x, anchor.y - tooltipHeight / 2]);
+ } else {
+ direction = 'left';
+ pos = pos.subtract(L.point(offset.x + tooltipWidth + anchor.x, tooltipHeight / 2 - anchor.y));
+ }
+
+ L.DomUtil.removeClass(container, 'leaflet-tooltip-right');
+ L.DomUtil.removeClass(container, 'leaflet-tooltip-left');
+ L.DomUtil.removeClass(container, 'leaflet-tooltip-top');
+ L.DomUtil.removeClass(container, 'leaflet-tooltip-bottom');
+ L.DomUtil.addClass(container, 'leaflet-tooltip-' + direction);
+ L.DomUtil.setPosition(container, pos);
+ },
+
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+
+ if (this._container) {
+ L.DomUtil.setOpacity(this._container, opacity);
+ }
+ },
+
+ _animateZoom: function (e) {
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center), offset;
+ if (this.options.offset) {
+ offset = L.point(this.options.offset);
+ pos = pos.add(offset);
+ }
+ L.DomUtil.setPosition(this._container, pos);
+ },
+
+ _getAnchor: function () {
+ // Where should we anchor the tooltip on the source layer?
+ return L.point(this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
+ }
+
+});
+
+// @namespace Tooltip
+// @factory L.tooltip(options?: Tooltip options, source?: Layer)
+// Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
+L.tooltip = function (options, source) {
+ return new L.Tooltip(options, source);
+};
+
+// @namespace Map
+// @section Methods for Layers and Controls
+L.Map.include({
+
+ // @method openTooltip(tooltip: Tooltip): this
+ // Opens the specified tooltip.
+ // @alternative
+ // @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
+ // Creates a tooltip with the specified content and options and open it.
+ openTooltip: function (tooltip, latlng, options) {
+ if (!(tooltip instanceof L.Tooltip)) {
+ tooltip = new L.Tooltip(options).setContent(tooltip);
+ }
+
+ if (latlng) {
+ tooltip.setLatLng(latlng);
+ }
+
+ if (this.hasLayer(tooltip)) {
+ return this;
+ }
+
+ return this.addLayer(tooltip);
+ },
+
+ // @method closeTooltip(tooltip?: Tooltip): this
+ // Closes the tooltip given as parameter.
+ closeTooltip: function (tooltip) {
+ if (tooltip) {
+ this.removeLayer(tooltip);
+ }
+ return this;
+ }
+
+});
diff --git a/src/layer/marker/Icon.Default.js b/src/layer/marker/Icon.Default.js
index 994df8051ce..29816bfd585 100644
--- a/src/layer/marker/Icon.Default.js
+++ b/src/layer/marker/Icon.Default.js
@@ -8,7 +8,7 @@ L.Icon.Default = L.Icon.extend({
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
- labelAnchor: [16, -28],
+ tooltipAnchor: [16, -28],
shadowSize: [41, 41]
},
diff --git a/src/layer/marker/Marker.Label.js b/src/layer/marker/Marker.Label.js
deleted file mode 100644
index 368ed8297bd..00000000000
--- a/src/layer/marker/Marker.Label.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Label extension to L.Marker, adding label-related methods.
- */
-
-L.Marker.include({
- _getLabelAnchor: function () {
- return this.options.icon.options.labelAnchor || [0, 0];
- }
-});
diff --git a/src/layer/marker/Marker.Tooltip.js b/src/layer/marker/Marker.Tooltip.js
new file mode 100644
index 00000000000..3b4981fae47
--- /dev/null
+++ b/src/layer/marker/Marker.Tooltip.js
@@ -0,0 +1,9 @@
+/*
+ * Tooltip extension to L.Marker, adding tooltip-related methods.
+ */
+
+L.Marker.include({
+ _getTooltipAnchor: function () {
+ return this.options.icon.options.tooltipAnchor || [0, 0];
+ }
+});
diff --git a/src/map/Map.js b/src/map/Map.js
index 17c464d568b..edb7d18c600 100644
--- a/src/map/Map.js
+++ b/src/map/Map.js
@@ -776,9 +776,9 @@ L.Map = L.Evented.extend({
// @pane markerPane: HTMLElement = 600
// Pane for `Icon`s of `Marker`s
this.createPane('markerPane');
- // @pane labelPane: HTMLElement = 700
- // Pane for labels.
- this.createPane('labelPane');
+ // @pane tooltipPane: HTMLElement = 650
+ // Pane for tooltip.
+ this.createPane('tooltipPane');
// @pane popupPane: HTMLElement = 700
// Pane for `Popup`s.
this.createPane('popupPane');