Leaflet.label.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. var LeafletLabel = L.Class.extend({
  2. includes: L.Mixin.Events,
  3. options: {
  4. className: '',
  5. clickable: false,
  6. direction: 'right',
  7. noHide: false,
  8. offset: [12, -15], // 6 (width of the label triangle) + 6 (padding)
  9. opacity: 1,
  10. zoomAnimation: true
  11. },
  12. initialize: function (options, source) {
  13. L.setOptions(this, options);
  14. this._source = source;
  15. this._animated = L.Browser.any3d && this.options.zoomAnimation;
  16. this._isOpen = false;
  17. },
  18. onAdd: function (map) {
  19. this._map = map;
  20. this._pane = this.options.pane ? map._panes[this.options.pane] :
  21. this._source instanceof L.Marker ? map._panes.markerPane : map._panes.popupPane;
  22. if (!this._container) {
  23. this._initLayout();
  24. }
  25. this._pane.appendChild(this._container);
  26. this._initInteraction();
  27. this._update();
  28. this.setOpacity(this.options.opacity);
  29. map
  30. .on('moveend', this._onMoveEnd, this)
  31. .on('viewreset', this._onViewReset, this);
  32. if (this._animated) {
  33. map.on('zoomanim', this._zoomAnimation, this);
  34. }
  35. if (L.Browser.touch && !this.options.noHide) {
  36. L.DomEvent.on(this._container, 'click', this.close, this);
  37. map.on('click', this.close, this);
  38. }
  39. },
  40. onRemove: function (map) {
  41. this._pane.removeChild(this._container);
  42. map.off({
  43. zoomanim: this._zoomAnimation,
  44. moveend: this._onMoveEnd,
  45. viewreset: this._onViewReset
  46. }, this);
  47. this._removeInteraction();
  48. this._map = null;
  49. },
  50. setLatLng: function (latlng) {
  51. this._latlng = L.latLng(latlng);
  52. if (this._map) {
  53. this._updatePosition();
  54. }
  55. return this;
  56. },
  57. setContent: function (content) {
  58. // Backup previous content and store new content
  59. this._previousContent = this._content;
  60. this._content = content;
  61. this._updateContent();
  62. return this;
  63. },
  64. close: function () {
  65. var map = this._map;
  66. if (map) {
  67. if (L.Browser.touch && !this.options.noHide) {
  68. L.DomEvent.off(this._container, 'click', this.close);
  69. map.off('click', this.close, this);
  70. }
  71. map.removeLayer(this);
  72. }
  73. },
  74. updateZIndex: function (zIndex) {
  75. this._zIndex = zIndex;
  76. if (this._container && this._zIndex) {
  77. this._container.style.zIndex = zIndex;
  78. }
  79. },
  80. setOpacity: function (opacity) {
  81. this.options.opacity = opacity;
  82. if (this._container) {
  83. L.DomUtil.setOpacity(this._container, opacity);
  84. }
  85. },
  86. _initLayout: function () {
  87. this._container = L.DomUtil.create('div', 'leaflet-label ' + this.options.className + ' leaflet-zoom-animated');
  88. this.updateZIndex(this._zIndex);
  89. },
  90. _update: function () {
  91. if (!this._map) { return; }
  92. this._container.style.visibility = 'hidden';
  93. this._updateContent();
  94. this._updatePosition();
  95. this._container.style.visibility = '';
  96. },
  97. _updateContent: function () {
  98. if (!this._content || !this._map || this._prevContent === this._content) {
  99. return;
  100. }
  101. if (typeof this._content === 'string') {
  102. this._container.innerHTML = this._content;
  103. this._prevContent = this._content;
  104. this._labelWidth = this._container.offsetWidth;
  105. }
  106. },
  107. _updatePosition: function () {
  108. var pos = this._map.latLngToLayerPoint(this._latlng);
  109. this._setPosition(pos);
  110. },
  111. _setPosition: function (pos) {
  112. var map = this._map,
  113. container = this._container,
  114. centerPoint = map.latLngToContainerPoint(map.getCenter()),
  115. labelPoint = map.layerPointToContainerPoint(pos),
  116. direction = this.options.direction,
  117. labelWidth = this._labelWidth,
  118. offset = L.point(this.options.offset);
  119. // position to the right (right or auto & needs to)
  120. if (direction === 'right' || direction === 'auto' && labelPoint.x < centerPoint.x) {
  121. L.DomUtil.addClass(container, 'leaflet-label-right');
  122. L.DomUtil.removeClass(container, 'leaflet-label-left');
  123. pos = pos.add(offset);
  124. } else { // position to the left
  125. L.DomUtil.addClass(container, 'leaflet-label-left');
  126. L.DomUtil.removeClass(container, 'leaflet-label-right');
  127. pos = pos.add(L.point(-offset.x - labelWidth, offset.y));
  128. }
  129. L.DomUtil.setPosition(container, pos);
  130. },
  131. _zoomAnimation: function (opt) {
  132. var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
  133. this._setPosition(pos);
  134. },
  135. _onMoveEnd: function () {
  136. if (!this._animated || this.options.direction === 'auto') {
  137. this._updatePosition();
  138. }
  139. },
  140. _onViewReset: function (e) {
  141. /* if map resets hard, we must update the label */
  142. if (e && e.hard) {
  143. this._update();
  144. }
  145. },
  146. _initInteraction: function () {
  147. if (!this.options.clickable) { return; }
  148. var container = this._container,
  149. events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
  150. L.DomUtil.addClass(container, 'leaflet-clickable');
  151. L.DomEvent.on(container, 'click', this._onMouseClick, this);
  152. for (var i = 0; i < events.length; i++) {
  153. L.DomEvent.on(container, events[i], this._fireMouseEvent, this);
  154. }
  155. },
  156. _removeInteraction: function () {
  157. if (!this.options.clickable) { return; }
  158. var container = this._container,
  159. events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
  160. L.DomUtil.removeClass(container, 'leaflet-clickable');
  161. L.DomEvent.off(container, 'click', this._onMouseClick, this);
  162. for (var i = 0; i < events.length; i++) {
  163. L.DomEvent.off(container, events[i], this._fireMouseEvent, this);
  164. }
  165. },
  166. _onMouseClick: function (e) {
  167. if (this.hasEventListeners(e.type)) {
  168. L.DomEvent.stopPropagation(e);
  169. }
  170. this.fire(e.type, {
  171. originalEvent: e
  172. });
  173. },
  174. _fireMouseEvent: function (e) {
  175. this.fire(e.type, {
  176. originalEvent: e
  177. });
  178. // TODO proper custom event propagation
  179. // this line will always be called if marker is in a FeatureGroup
  180. if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) {
  181. L.DomEvent.preventDefault(e);
  182. }
  183. if (e.type !== 'mousedown') {
  184. L.DomEvent.stopPropagation(e);
  185. } else {
  186. L.DomEvent.preventDefault(e);
  187. }
  188. }
  189. });