foliage 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +9 -0
  4. data/app/assets/images/.keep +0 -0
  5. data/app/assets/images/map/marker/icon-2x.png +0 -0
  6. data/app/assets/images/map/marker/icon.png +0 -0
  7. data/app/assets/images/map/marker/icon.svg +67 -0
  8. data/app/assets/images/map/marker/shadow.png +0 -0
  9. data/app/assets/javascripts/core_ext.js.coffee +61 -0
  10. data/app/assets/javascripts/foliage.js.coffee +23 -0
  11. data/app/assets/javascripts/foliage/band.js.coffee +99 -0
  12. data/app/assets/javascripts/foliage/bubbles.js.coffee +77 -0
  13. data/app/assets/javascripts/foliage/categories.js.coffee +70 -0
  14. data/app/assets/javascripts/foliage/choropleth.js.coffee +51 -0
  15. data/app/assets/javascripts/foliage/color.js.coffee +39 -0
  16. data/app/assets/javascripts/foliage/gradient.js.coffee +72 -0
  17. data/app/assets/javascripts/foliage/heatmap.js.coffee +49 -0
  18. data/app/assets/javascripts/foliage/leaf.js.coffee +422 -0
  19. data/app/assets/javascripts/foliage/path.js.coffee +76 -0
  20. data/app/assets/javascripts/foliage/paths.js.coffee +131 -0
  21. data/app/assets/javascripts/foliage/point_group.js.coffee +83 -0
  22. data/app/assets/javascripts/foliage/points.js.coffee +79 -0
  23. data/app/assets/javascripts/foliage/simple.js.coffee +35 -0
  24. data/app/assets/javascripts/leaflet/geographic_util.js.coffee +23 -0
  25. data/app/assets/javascripts/leaflet/ghost_label.js.coffee +100 -0
  26. data/app/assets/javascripts/leaflet/ghost_label_cluster.js.coffee +192 -0
  27. data/app/assets/javascripts/leaflet/layers_scheduler.js.coffee +57 -0
  28. data/app/assets/javascripts/leaflet/reactive_measure.js.coffee +414 -0
  29. data/app/assets/stylesheets/all.scss +16 -0
  30. data/app/assets/stylesheets/application.css +15 -0
  31. data/app/assets/stylesheets/compass/reset.scss +3 -0
  32. data/app/assets/stylesheets/compass/reset/utilities.scss +142 -0
  33. data/app/assets/stylesheets/leaflet.scss +1093 -0
  34. data/app/assets/stylesheets/leaflet/label.scss +40 -0
  35. data/app/assets/stylesheets/leaflet/tooltip.scss +42 -0
  36. data/app/assets/stylesheets/mixins.scss +131 -0
  37. data/app/assets/stylesheets/reset.scss +89 -0
  38. data/app/assets/stylesheets/variables.scss +47 -0
  39. data/app/helpers/foliage_helper.rb +23 -0
  40. data/lib/foliage.rb +9 -0
  41. data/lib/foliage/leaf.rb +235 -0
  42. data/lib/foliage/rails.rb +2 -0
  43. data/lib/foliage/rails/engine.rb +7 -0
  44. data/lib/foliage/rails/integration.rb +8 -0
  45. data/lib/foliage/version.rb +3 -0
  46. data/vendor/assets/javascripts/.keep +0 -0
  47. data/vendor/assets/javascripts/autosize.js +211 -0
  48. data/vendor/assets/javascripts/geographiclib.js +3074 -0
  49. data/vendor/assets/javascripts/leaflet.js.erb +9175 -0
  50. data/vendor/assets/javascripts/leaflet/draw.js +3573 -0
  51. data/vendor/assets/javascripts/leaflet/easy-button.js +366 -0
  52. data/vendor/assets/javascripts/leaflet/fullscreen.js +162 -0
  53. data/vendor/assets/javascripts/leaflet/heatmap.js +142 -0
  54. data/vendor/assets/javascripts/leaflet/label.js +545 -0
  55. data/vendor/assets/javascripts/leaflet/measure.js +6966 -0
  56. data/vendor/assets/javascripts/leaflet/modal.js +364 -0
  57. data/vendor/assets/javascripts/leaflet/providers.js +479 -0
  58. data/vendor/assets/javascripts/rbush.js +621 -0
  59. data/vendor/assets/stylesheets/.keep +0 -0
  60. data/vendor/assets/stylesheets/bootstrap/mixins.scss +55 -0
  61. data/vendor/assets/stylesheets/bootstrap/variables.scss +10 -0
  62. data/vendor/assets/stylesheets/leaflet.scss +479 -0
  63. data/vendor/assets/stylesheets/leaflet/draw.scss +282 -0
  64. data/vendor/assets/stylesheets/leaflet/easy-button.scss +56 -0
  65. data/vendor/assets/stylesheets/leaflet/fullscreen.scss +2 -0
  66. data/vendor/assets/stylesheets/leaflet/measure.scss +168 -0
  67. data/vendor/assets/stylesheets/leaflet/modal.scss +85 -0
  68. metadata +171 -0
@@ -0,0 +1,142 @@
1
+ /*
2
+ * Creative Commons Copyright 2013 Ursudio <info@ursudio.com>
3
+ * http://www.ursudio.com/
4
+ * Please attribute Ursudio in any production associated with this javascript plugin.
5
+ */
6
+
7
+ L.TileLayer.WebGLHeatMap = L.Class.extend({
8
+
9
+ options: {
10
+ size: 30000, // in meters
11
+ opacity: 1,
12
+ gradientTexture: false,
13
+ alphaRange: 1
14
+ },
15
+
16
+ initialize: function (options) {
17
+ this.data = [];
18
+ L.Util.setOptions(this, options);
19
+ },
20
+
21
+ onAdd: function (map) {
22
+ this.map = map;
23
+ var mapsize = map.getSize();
24
+ var options = this.options;
25
+
26
+ var c = document.createElement("canvas");
27
+ c.id = 'webgl-leaflet-' + L.Util.stamp(this);
28
+ c.width = mapsize.x;
29
+ c.height = mapsize.y;
30
+ c.style.opacity = options.opacity;
31
+ c.style.position = 'absolute';
32
+
33
+ map.getPanes().overlayPane.appendChild(c);
34
+
35
+ this.WebGLHeatMap = createWebGLHeatmap({
36
+ canvas: c,
37
+ gradientTexture: options.gradientTexture,
38
+ alphaRange: [0, options.alphaRange]
39
+ });
40
+
41
+ this.canvas = c;
42
+
43
+ map.on("move", this._plot, this);
44
+
45
+ /* hide layer on zoom, because it doesn't animate zoom */
46
+ map.on("zoomstart", this._hide, this);
47
+ map.on("zoomend", this._show, this);
48
+
49
+ this._plot();
50
+ },
51
+
52
+ onRemove: function (map) {
53
+ map.getPanes().overlayPane.removeChild(this.canvas);
54
+ map.off("move", this._plot, this);
55
+ map.off("zoomstart", this._hide, this);
56
+ map.off("zoomend", this._show, this);
57
+ },
58
+
59
+ _hide : function () {
60
+ this.canvas.style.display = 'none';
61
+ },
62
+
63
+ _show : function () {
64
+ this.canvas.style.display = 'block';
65
+ },
66
+
67
+ _clear: function () {
68
+ var heatmap = this.WebGLHeatMap;
69
+ heatmap.clear();
70
+ heatmap.display();
71
+ },
72
+
73
+ _resizeRequest : undefined,
74
+
75
+ _plot: function () {
76
+ this.active = true;
77
+ var map = this.map;
78
+ if (this._resizeRequest !== map._resizeRequest) {
79
+ this.resize();
80
+ this._resizeRequest = map._resizeRequest;
81
+ }
82
+ var heatmap = this.WebGLHeatMap;
83
+ heatmap.clear();
84
+ L.DomUtil.setPosition(this.canvas, map.latLngToLayerPoint(map.getBounds().getNorthWest()));
85
+ var dataLen = this.data.length;
86
+ if (dataLen) {
87
+ for (var i = 0; i < dataLen; i++) {
88
+ var dataVal = this.data[i],
89
+ latlng = new L.LatLng(dataVal[0], dataVal[1]),
90
+ point = map.latLngToContainerPoint(latlng);
91
+ heatmap.addPoint(
92
+ Math.floor(point.x),
93
+ Math.floor(point.y),
94
+ this._scale(latlng),
95
+ dataVal[2]);
96
+ }
97
+ heatmap.update();
98
+ heatmap.display();
99
+ }
100
+ },
101
+
102
+ _scale: function (latlng) {
103
+ // necessary to maintain accurately sized circles
104
+ // to change scale to miles (for example), you will need to convert 40075017 (equatorial circumference of the Earth in metres) to miles
105
+ var lngRadius = (this.options.size / 40075017) * 360 / Math.cos(L.LatLng.DEG_TO_RAD * latlng.lat);
106
+ var latlng2 = new L.LatLng(latlng.lat, latlng.lng - lngRadius);
107
+ var point = this.map.latLngToLayerPoint(latlng);
108
+ var point2 = this.map.latLngToLayerPoint(latlng2);
109
+
110
+ return Math.max(Math.round(point.x - point2.x), 1);
111
+ },
112
+
113
+ resize: function () {
114
+ //helpful for maps that change sizes
115
+ var mapsize = this.map.getSize();
116
+ this.canvas.width = mapsize.x;
117
+ this.canvas.height = mapsize.y;
118
+
119
+ this.WebGLHeatMap.adjustSize();
120
+ },
121
+
122
+ addDataPoint: function (lat, lon, value) {
123
+ this.data.push( [ lat, lon, value / 100 ] );
124
+ },
125
+
126
+ setData: function (dataset) {
127
+ // format: [[lat, lon, intensity],...]
128
+ this.data = dataset;
129
+ },
130
+
131
+ clearData: function () {
132
+ this.data = [];
133
+ },
134
+
135
+ update: function () {
136
+ this._plot();
137
+ }
138
+ });
139
+
140
+ L.TileLayer.webglheatmap = function (options) {
141
+ return new L.TileLayer.WebGLHeatMap(options);
142
+ };
@@ -0,0 +1,545 @@
1
+ /*
2
+ Leaflet.label, a plugin that adds labels to markers and vectors for Leaflet powered maps.
3
+ (c) 2012-2013, Jacob Toye, Smartrak
4
+
5
+ https://github.com/Leaflet/Leaflet.label
6
+ http://leafletjs.com
7
+ https://github.com/jacobtoye
8
+ */
9
+ (function (window, document, undefined) {
10
+ var L = window.L;/*
11
+ * Leaflet.label assumes that you have already included the Leaflet library.
12
+ */
13
+
14
+ L.labelVersion = '0.2.2-dev';
15
+
16
+ L.Label = (L.Layer ? L.Layer : L.Class).extend({
17
+
18
+ includes: L.Mixin.Events,
19
+
20
+ options: {
21
+ className: '',
22
+ clickable: false,
23
+ direction: 'right',
24
+ noHide: false,
25
+ offset: [12, -15], // 6 (width of the label triangle) + 6 (padding)
26
+ opacity: 1,
27
+ zoomAnimation: true
28
+ },
29
+
30
+ initialize: function (options, source) {
31
+ L.setOptions(this, options);
32
+
33
+ this._source = source;
34
+ this._animated = L.Browser.any3d && this.options.zoomAnimation;
35
+ this._isOpen = false;
36
+ },
37
+
38
+ onAdd: function (map) {
39
+ this._map = map;
40
+
41
+ this._pane = this.options.pane ? map._panes[this.options.pane] :
42
+ this._source instanceof L.Marker ? map._panes.markerPane : map._panes.popupPane;
43
+
44
+ if (!this._container) {
45
+ this._initLayout();
46
+ }
47
+
48
+ this._pane.appendChild(this._container);
49
+
50
+ this._initInteraction();
51
+
52
+ this._update();
53
+
54
+ this.setOpacity(this.options.opacity);
55
+
56
+ map
57
+ .on('moveend', this._onMoveEnd, this)
58
+ .on('viewreset', this._onViewReset, this);
59
+
60
+ if (this._animated) {
61
+ map.on('zoomanim', this._zoomAnimation, this);
62
+ }
63
+
64
+ if (L.Browser.touch && !this.options.noHide) {
65
+ L.DomEvent.on(this._container, 'click', this.close, this);
66
+ map.on('click', this.close, this);
67
+ }
68
+ },
69
+
70
+ onRemove: function (map) {
71
+ this._pane.removeChild(this._container);
72
+
73
+ map.off({
74
+ zoomanim: this._zoomAnimation,
75
+ moveend: this._onMoveEnd,
76
+ viewreset: this._onViewReset
77
+ }, this);
78
+
79
+ this._removeInteraction();
80
+
81
+ this._map = null;
82
+ },
83
+
84
+ setLatLng: function (latlng) {
85
+ this._latlng = L.latLng(latlng);
86
+ if (this._map) {
87
+ this._updatePosition();
88
+ }
89
+ return this;
90
+ },
91
+
92
+ setContent: function (content) {
93
+ // Backup previous content and store new content
94
+ this._previousContent = this._content;
95
+ this._content = content;
96
+
97
+ this._updateContent();
98
+
99
+ return this;
100
+ },
101
+
102
+ close: function () {
103
+ var map = this._map;
104
+
105
+ if (map) {
106
+ if (L.Browser.touch && !this.options.noHide) {
107
+ L.DomEvent.off(this._container, 'click', this.close);
108
+ map.off('click', this.close, this);
109
+ }
110
+
111
+ map.removeLayer(this);
112
+ }
113
+ },
114
+
115
+ updateZIndex: function (zIndex) {
116
+ this._zIndex = zIndex;
117
+
118
+ if (this._container && this._zIndex) {
119
+ this._container.style.zIndex = zIndex;
120
+ }
121
+ },
122
+
123
+ setOpacity: function (opacity) {
124
+ this.options.opacity = opacity;
125
+
126
+ if (this._container) {
127
+ L.DomUtil.setOpacity(this._container, opacity);
128
+ }
129
+ },
130
+
131
+ _initLayout: function () {
132
+ this._container = L.DomUtil.create('div', 'leaflet-label ' + this.options.className + ' leaflet-zoom-animated');
133
+ this.updateZIndex(this._zIndex);
134
+ },
135
+
136
+ _update: function () {
137
+ if (!this._map) { return; }
138
+
139
+ this._container.style.visibility = 'hidden';
140
+
141
+ this._updateContent();
142
+ this._updatePosition();
143
+
144
+ this._container.style.visibility = '';
145
+ },
146
+
147
+ _updateContent: function () {
148
+ if (!this._content || !this._map || this._prevContent === this._content) {
149
+ return;
150
+ }
151
+
152
+ if (typeof this._content === 'string') {
153
+ this._container.innerHTML = this._content;
154
+
155
+ this._prevContent = this._content;
156
+
157
+ this._labelWidth = this._container.offsetWidth;
158
+ }
159
+ },
160
+
161
+ _updatePosition: function () {
162
+ var pos = this._map.latLngToLayerPoint(this._latlng);
163
+
164
+ this._setPosition(pos);
165
+ },
166
+
167
+ _setPosition: function (pos) {
168
+ var map = this._map,
169
+ container = this._container,
170
+ centerPoint = map.latLngToContainerPoint(map.getCenter()),
171
+ labelPoint = map.layerPointToContainerPoint(pos),
172
+ direction = this.options.direction,
173
+ labelWidth = this._labelWidth,
174
+ offset = L.point(this.options.offset);
175
+
176
+ // position to the right (right or auto & needs to)
177
+ if (direction === 'right' || direction === 'auto' && labelPoint.x < centerPoint.x) {
178
+ L.DomUtil.addClass(container, 'leaflet-label-right');
179
+ L.DomUtil.removeClass(container, 'leaflet-label-left');
180
+
181
+ pos = pos.add(offset);
182
+ } else { // position to the left
183
+ L.DomUtil.addClass(container, 'leaflet-label-left');
184
+ L.DomUtil.removeClass(container, 'leaflet-label-right');
185
+
186
+ pos = pos.add(L.point(-offset.x - labelWidth, offset.y));
187
+ }
188
+
189
+ L.DomUtil.setPosition(container, pos);
190
+ },
191
+
192
+ _zoomAnimation: function (opt) {
193
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
194
+
195
+ this._setPosition(pos);
196
+ },
197
+
198
+ _onMoveEnd: function () {
199
+ if (!this._animated || this.options.direction === 'auto') {
200
+ this._updatePosition();
201
+ }
202
+ },
203
+
204
+ _onViewReset: function (e) {
205
+ /* if map resets hard, we must update the label */
206
+ if (e && e.hard) {
207
+ this._update();
208
+ }
209
+ },
210
+
211
+ _initInteraction: function () {
212
+ if (!this.options.clickable) { return; }
213
+
214
+ var container = this._container,
215
+ events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
216
+
217
+ L.DomUtil.addClass(container, 'leaflet-clickable');
218
+ L.DomEvent.on(container, 'click', this._onMouseClick, this);
219
+
220
+ for (var i = 0; i < events.length; i++) {
221
+ L.DomEvent.on(container, events[i], this._fireMouseEvent, this);
222
+ }
223
+ },
224
+
225
+ _removeInteraction: function () {
226
+ if (!this.options.clickable) { return; }
227
+
228
+ var container = this._container,
229
+ events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
230
+
231
+ L.DomUtil.removeClass(container, 'leaflet-clickable');
232
+ L.DomEvent.off(container, 'click', this._onMouseClick, this);
233
+
234
+ for (var i = 0; i < events.length; i++) {
235
+ L.DomEvent.off(container, events[i], this._fireMouseEvent, this);
236
+ }
237
+ },
238
+
239
+ _onMouseClick: function (e) {
240
+ if (this.hasEventListeners(e.type)) {
241
+ L.DomEvent.stopPropagation(e);
242
+ }
243
+
244
+ this.fire(e.type, {
245
+ originalEvent: e
246
+ });
247
+ },
248
+
249
+ _fireMouseEvent: function (e) {
250
+ this.fire(e.type, {
251
+ originalEvent: e
252
+ });
253
+
254
+ // TODO proper custom event propagation
255
+ // this line will always be called if marker is in a FeatureGroup
256
+ if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) {
257
+ L.DomEvent.preventDefault(e);
258
+ }
259
+ if (e.type !== 'mousedown') {
260
+ L.DomEvent.stopPropagation(e);
261
+ } else {
262
+ L.DomEvent.preventDefault(e);
263
+ }
264
+ }
265
+ });
266
+
267
+
268
+ // This object is a mixin for L.Marker and L.CircleMarker. We declare it here as both need to include the contents.
269
+ L.BaseMarkerMethods = {
270
+ showLabel: function () {
271
+ if (this.label && this._map) {
272
+ this.label.setLatLng(this._latlng);
273
+ this._map.showLabel(this.label);
274
+ }
275
+
276
+ return this;
277
+ },
278
+
279
+ hideLabel: function () {
280
+ if (this.label) {
281
+ this.label.close();
282
+ }
283
+ return this;
284
+ },
285
+
286
+ setLabelNoHide: function (noHide) {
287
+ if (this._labelNoHide === noHide) {
288
+ return;
289
+ }
290
+
291
+ this._labelNoHide = noHide;
292
+
293
+ if (noHide) {
294
+ this._removeLabelRevealHandlers();
295
+ this.showLabel();
296
+ } else {
297
+ this._addLabelRevealHandlers();
298
+ this.hideLabel();
299
+ }
300
+ },
301
+
302
+ bindLabel: function (content, options) {
303
+ var labelAnchor = this.options.icon ? this.options.icon.options.labelAnchor : this.options.labelAnchor,
304
+ anchor = L.point(labelAnchor) || L.point(0, 0);
305
+
306
+ anchor = anchor.add(L.Label.prototype.options.offset);
307
+
308
+ if (options && options.offset) {
309
+ anchor = anchor.add(options.offset);
310
+ }
311
+
312
+ options = L.Util.extend({offset: anchor}, options);
313
+
314
+ this._labelNoHide = options.noHide;
315
+
316
+ if (!this.label) {
317
+ if (!this._labelNoHide) {
318
+ this._addLabelRevealHandlers();
319
+ }
320
+
321
+ this
322
+ .on('remove', this.hideLabel, this)
323
+ .on('move', this._moveLabel, this)
324
+ .on('add', this._onMarkerAdd, this);
325
+
326
+ this._hasLabelHandlers = true;
327
+ }
328
+
329
+ this.label = new L.Label(options, this)
330
+ .setContent(content);
331
+
332
+ return this;
333
+ },
334
+
335
+ unbindLabel: function () {
336
+ if (this.label) {
337
+ this.hideLabel();
338
+
339
+ this.label = null;
340
+
341
+ if (this._hasLabelHandlers) {
342
+ if (!this._labelNoHide) {
343
+ this._removeLabelRevealHandlers();
344
+ }
345
+
346
+ this
347
+ .off('remove', this.hideLabel, this)
348
+ .off('move', this._moveLabel, this)
349
+ .off('add', this._onMarkerAdd, this);
350
+ }
351
+
352
+ this._hasLabelHandlers = false;
353
+ }
354
+ return this;
355
+ },
356
+
357
+ updateLabelContent: function (content) {
358
+ if (this.label) {
359
+ this.label.setContent(content);
360
+ }
361
+ },
362
+
363
+ getLabel: function () {
364
+ return this.label;
365
+ },
366
+
367
+ _onMarkerAdd: function () {
368
+ if (this._labelNoHide) {
369
+ this.showLabel();
370
+ }
371
+ },
372
+
373
+ _addLabelRevealHandlers: function () {
374
+ this
375
+ .on('mouseover', this.showLabel, this)
376
+ .on('mouseout', this.hideLabel, this);
377
+
378
+ if (L.Browser.touch) {
379
+ this.on('click', this.showLabel, this);
380
+ }
381
+ },
382
+
383
+ _removeLabelRevealHandlers: function () {
384
+ this
385
+ .off('mouseover', this.showLabel, this)
386
+ .off('mouseout', this.hideLabel, this);
387
+
388
+ if (L.Browser.touch) {
389
+ this.off('click', this.showLabel, this);
390
+ }
391
+ },
392
+
393
+ _moveLabel: function (e) {
394
+ this.label.setLatLng(e.latlng);
395
+ }
396
+ };
397
+
398
+ // Add in an option to icon that is used to set where the label anchor is
399
+ L.Icon.Default.mergeOptions({
400
+ labelAnchor: new L.Point(9, -20)
401
+ });
402
+
403
+ // Have to do this since Leaflet is loaded before this plugin and initializes
404
+ // L.Marker.options.icon therefore missing our mixin above.
405
+ L.Marker.mergeOptions({
406
+ icon: new L.Icon.Default()
407
+ });
408
+
409
+ L.Marker.include(L.BaseMarkerMethods);
410
+ L.Marker.include({
411
+ _originalUpdateZIndex: L.Marker.prototype._updateZIndex,
412
+
413
+ _updateZIndex: function (offset) {
414
+ var zIndex = this._zIndex + offset;
415
+
416
+ this._originalUpdateZIndex(offset);
417
+
418
+ if (this.label) {
419
+ this.label.updateZIndex(zIndex);
420
+ }
421
+ },
422
+
423
+ _originalSetOpacity: L.Marker.prototype.setOpacity,
424
+
425
+ setOpacity: function (opacity, labelHasSemiTransparency) {
426
+ this.options.labelHasSemiTransparency = labelHasSemiTransparency;
427
+
428
+ this._originalSetOpacity(opacity);
429
+ },
430
+
431
+ _originalUpdateOpacity: L.Marker.prototype._updateOpacity,
432
+
433
+ _updateOpacity: function () {
434
+ var absoluteOpacity = this.options.opacity === 0 ? 0 : 1;
435
+
436
+ this._originalUpdateOpacity();
437
+
438
+ if (this.label) {
439
+ this.label.setOpacity(this.options.labelHasSemiTransparency ? this.options.opacity : absoluteOpacity);
440
+ }
441
+ },
442
+
443
+ _originalSetLatLng: L.Marker.prototype.setLatLng,
444
+
445
+ setLatLng: function (latlng) {
446
+ if (this.label && !this._labelNoHide) {
447
+ this.hideLabel();
448
+ }
449
+
450
+ return this._originalSetLatLng(latlng);
451
+ }
452
+ });
453
+
454
+ // Add in an option to icon that is used to set where the label anchor is
455
+ L.CircleMarker.mergeOptions({
456
+ labelAnchor: new L.Point(0, 0)
457
+ });
458
+
459
+
460
+ L.CircleMarker.include(L.BaseMarkerMethods);
461
+
462
+ L.Path.include({
463
+ bindLabel: function (content, options) {
464
+ if (!this.label || this.label.options !== options) {
465
+ this.label = new L.Label(options, this);
466
+ }
467
+
468
+ this.label.setContent(content);
469
+
470
+ if (!this._showLabelAdded) {
471
+ this
472
+ .on('mouseover', this._showLabel, this)
473
+ .on('mousemove', this._moveLabel, this)
474
+ .on('mouseout remove', this._hideLabel, this);
475
+
476
+ if (L.Browser.touch) {
477
+ this.on('click', this._showLabel, this);
478
+ }
479
+ this._showLabelAdded = true;
480
+ }
481
+
482
+ return this;
483
+ },
484
+
485
+ unbindLabel: function () {
486
+ if (this.label) {
487
+ this._hideLabel();
488
+ this.label = null;
489
+ this._showLabelAdded = false;
490
+ this
491
+ .off('mouseover', this._showLabel, this)
492
+ .off('mousemove', this._moveLabel, this)
493
+ .off('mouseout remove', this._hideLabel, this);
494
+ }
495
+ return this;
496
+ },
497
+
498
+ updateLabelContent: function (content) {
499
+ if (this.label) {
500
+ this.label.setContent(content);
501
+ }
502
+ },
503
+
504
+ _showLabel: function (e) {
505
+ this.label.setLatLng(e.latlng);
506
+ this._map.showLabel(this.label);
507
+ },
508
+
509
+ _moveLabel: function (e) {
510
+ this.label.setLatLng(e.latlng);
511
+ },
512
+
513
+ _hideLabel: function () {
514
+ this.label.close();
515
+ }
516
+ });
517
+
518
+ L.Map.include({
519
+ showLabel: function (label) {
520
+ return this.addLayer(label);
521
+ }
522
+ });
523
+
524
+ L.FeatureGroup.include({
525
+ // TODO: remove this when AOP is supported in Leaflet, need this as we cannot put code in removeLayer()
526
+ clearLayers: function () {
527
+ this.unbindLabel();
528
+ this.eachLayer(this.removeLayer, this);
529
+ return this;
530
+ },
531
+
532
+ bindLabel: function (content, options) {
533
+ return this.invoke('bindLabel', content, options);
534
+ },
535
+
536
+ unbindLabel: function () {
537
+ return this.invoke('unbindLabel');
538
+ },
539
+
540
+ updateLabelContent: function (content) {
541
+ this.invoke('updateLabelContent', content);
542
+ }
543
+ });
544
+
545
+ }(window, document));