commonroutesApp/www/lib/ui-leaflet/dist/ui-leaflet.js
www/lib/ui-leaflet/dist/ui-leaflet.jsRaw
1/*!
2* ui-leaflet 2.0.0 2016-10-04
3* ui-leaflet - An AngularJS directive to easily interact with Leaflet maps
4* git: https://github.com/angular-ui/ui-leaflet
5*/
6(function(angular){
7'use strict';
8'use strict';
9
10angular.module('ui-leaflet', ['nemLogging']).directive('leaflet', ["$q", "leafletData", "leafletMapDefaults", "leafletHelpers", "leafletMapEvents", function ($q, leafletData, leafletMapDefaults, leafletHelpers, leafletMapEvents) {
11 return {
12 restrict: "EA",
13 replace: true,
14 scope: {
15 center: '=',
16 lfCenter: '=',
17 defaults: '=',
18 maxbounds: '=',
19 bounds: '=',
20 markers: '=',
21 legend: '=',
22 geojson: '=',
23 paths: '=',
24 tiles: '=',
25 layers: '=',
26 controls: '=',
27 decorations: '=',
28 eventBroadcast: '=',
29 watchOptions: '=',
30 id: '@'
31 },
32 transclude: true,
33 template: '<div class="angular-leaflet-map"><div ng-transclude></div></div>',
34 controller: ["$scope", function controller($scope) {
35 this._leafletMap = $q.defer();
36 this.getMap = function () {
37 return this._leafletMap.promise;
38 };
39
40 this.getLeafletScope = function () {
41 return $scope;
42 };
43 }],
44
45 link: function link(scope, element, attrs, ctrl) {
46 var isDefined = leafletHelpers.isDefined,
47 defaults = leafletMapDefaults.setDefaults(scope.defaults, attrs.id),
48 mapEvents = leafletMapEvents.getAvailableMapEvents(),
49 addEvents = leafletMapEvents.addEvents;
50
51 scope.mapId = attrs.id;
52 leafletData.setDirectiveControls({}, attrs.id);
53
54 // Set width and height utility functions
55 function updateWidth() {
56 if (isNaN(attrs.width)) {
57 element.css('width', attrs.width);
58 } else {
59 element.css('width', attrs.width + 'px');
60 }
61 }
62
63 function updateHeight() {
64 if (isNaN(attrs.height)) {
65 element.css('height', attrs.height);
66 } else {
67 element.css('height', attrs.height + 'px');
68 }
69 }
70
71 // Create the Leaflet Map Object with the options
72 var map = new L.Map(element[0], leafletMapDefaults.getMapCreationDefaults(attrs.id));
73 ctrl._leafletMap.resolve(map);
74
75 // If the width attribute defined update css
76 // Then watch if bound property changes and update css
77 if (isDefined(attrs.width)) {
78 updateWidth();
79
80 scope.$watch(function () {
81 return element[0].getAttribute('width');
82 }, function () {
83 updateWidth();
84 map.invalidateSize();
85 });
86 }
87
88 // If the height attribute defined update css
89 // Then watch if bound property changes and update css
90 if (isDefined(attrs.height)) {
91 updateHeight();
92
93 scope.$watch(function () {
94 return element[0].getAttribute('height');
95 }, function () {
96 updateHeight();
97 map.invalidateSize();
98 });
99 }
100
101 if (!isDefined(attrs.center) && !isDefined(attrs.lfCenter)) {
102 map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
103 }
104
105 // If no layers nor tiles defined, set the default tileLayer
106 if (!isDefined(attrs.tiles) && !isDefined(attrs.layers)) {
107 var tileLayerObj = L.tileLayer(defaults.tileLayer, defaults.tileLayerOptions);
108 tileLayerObj.addTo(map);
109 leafletData.setTiles(tileLayerObj, attrs.id);
110 }
111
112 // Set zoom control configuration
113 if (isDefined(map.zoomControl) && isDefined(defaults.zoomControlPosition)) {
114 map.zoomControl.setPosition(defaults.zoomControlPosition);
115 }
116
117 if (isDefined(map.zoomControl) && defaults.zoomControl === false) {
118 map.zoomControl.removeFrom(map);
119 }
120
121 if (isDefined(map.zoomsliderControl) && isDefined(defaults.zoomsliderControl) && defaults.zoomsliderControl === false) {
122 map.zoomsliderControl.removeFrom(map);
123 }
124
125 // if no event-broadcast attribute, all events are broadcasted
126 if (!isDefined(attrs.eventBroadcast)) {
127 var logic = "broadcast";
128 addEvents(map, attrs.id, mapEvents, "eventName", scope, logic);
129 }
130
131 // Resolve the map object to the promises
132 map.whenReady(function () {
133 leafletData.setMap(map, attrs.id);
134 });
135
136 scope.$on('$destroy', function () {
137 leafletMapDefaults.reset();
138 map.remove();
139 leafletData.unresolveMap(attrs.id);
140 });
141
142 //Handle request to invalidate the map size
143 //Up scope using $scope.$emit('invalidateSize')
144 //Down scope using $scope.$broadcast('invalidateSize')
145 scope.$on('invalidateSize', function () {
146 map.invalidateSize();
147 });
148 }
149 };
150}]);
151
152'use strict';
153
154(function () {
155 angular.module('ui-leaflet').factory('eventManager', [function () {
156 var EventManager = function EventManager() {
157 this.listeners = {};
158 };
159
160 EventManager.prototype = {
161 addEventListener: function addEventListener(type, callback, scope) {
162 var args = [];
163 var numOfArgs = arguments.length;
164 for (var i = 0; i < numOfArgs; i++) {
165 args.push(arguments[i]);
166 }
167 args = args.length > 3 ? args.splice(3, args.length - 1) : [];
168 if (typeof this.listeners[type] !== "undefined") {
169 this.listeners[type].push({ scope: scope, callback: callback, args: args });
170 } else {
171 this.listeners[type] = [{ scope: scope, callback: callback, args: args }];
172 }
173 },
174 removeEventListener: function removeEventListener(type, callback, scope) {
175 if (typeof this.listeners[type] !== "undefined") {
176 var numOfCallbacks = this.listeners[type].length;
177 var newArray = [];
178 for (var i = 0; i < numOfCallbacks; i++) {
179 var listener = this.listeners[type][i];
180 if (listener.scope === scope && listener.callback === callback) {} else {
181 newArray.push(listener);
182 }
183 }
184 this.listeners[type] = newArray;
185 }
186 },
187 hasEventListener: function hasEventListener(type, callback, scope) {
188 if (typeof this.listeners[type] !== "undefined") {
189 var numOfCallbacks = this.listeners[type].length;
190 if (callback === undefined && scope === undefined) {
191 return numOfCallbacks > 0;
192 }
193 for (var i = 0; i < numOfCallbacks; i++) {
194 var listener = this.listeners[type][i];
195 if ((scope ? listener.scope === scope : true) && listener.callback === callback) {
196 return true;
197 }
198 }
199 }
200 return false;
201 },
202 dispatch: function dispatch(type, target) {
203 var numOfListeners = 0;
204 var event = {
205 type: type,
206 target: target
207 };
208 var args = [];
209 var numOfArgs = arguments.length;
210 for (var i = 0; i < numOfArgs; i++) {
211 args.push(arguments[i]);
212 }
213 args = args.length > 2 ? args.splice(2, args.length - 1) : [];
214 args = [event].concat(args);
215 if (typeof this.listeners[type] !== "undefined") {
216 var numOfCallbacks = this.listeners[type].length;
217 for (var x = 0; x < numOfCallbacks; x++) {
218 var listener = this.listeners[type][x];
219 if (listener && listener.callback) {
220 var concatArgs = args.concat(listener.args);
221 listener.callback.apply(listener.scope, concatArgs);
222 numOfListeners += 1;
223 }
224 }
225 }
226 },
227 getEvents: function getEvents() {
228 var str = "";
229 for (var type in this.listeners) {
230 var numOfCallbacks = this.listeners[type].length;
231 for (var i = 0; i < numOfCallbacks; i++) {
232 var listener = this.listeners[type][i];
233 str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous";
234 str += " listen for '" + type + "'\n";
235 }
236 }
237 return str;
238 }
239 };
240 return EventManager;
241 }]).service('eventManager', ["EventManager", function (EventManager) {
242 return new EventManager();
243 }]);
244})();
245
246'use strict';
247
248angular.module('ui-leaflet').factory('leafletBoundsHelpers', ["leafletLogger", "leafletHelpers", function (leafletLogger, leafletHelpers) {
249
250 var isArray = leafletHelpers.isArray,
251 isNumber = leafletHelpers.isNumber,
252 isFunction = leafletHelpers.isFunction,
253 isDefined = leafletHelpers.isDefined,
254 $log = leafletLogger;
255
256 function _isValidBounds(bounds) {
257 return angular.isDefined(bounds) && angular.isDefined(bounds.southWest) && angular.isDefined(bounds.northEast) && angular.isNumber(bounds.southWest.lat) && angular.isNumber(bounds.southWest.lng) && angular.isNumber(bounds.northEast.lat) && angular.isNumber(bounds.northEast.lng);
258 }
259
260 return {
261 createLeafletBounds: function createLeafletBounds(bounds) {
262 if (_isValidBounds(bounds)) {
263 return L.latLngBounds([bounds.southWest.lat, bounds.southWest.lng], [bounds.northEast.lat, bounds.northEast.lng]);
264 }
265 },
266
267 isValidBounds: _isValidBounds,
268
269 createBoundsFromArray: function createBoundsFromArray(boundsArray) {
270 if (!(isArray(boundsArray) && boundsArray.length === 2 && isArray(boundsArray[0]) && isArray(boundsArray[1]) && boundsArray[0].length === 2 && boundsArray[1].length === 2 && isNumber(boundsArray[0][0]) && isNumber(boundsArray[0][1]) && isNumber(boundsArray[1][0]) && isNumber(boundsArray[1][1]))) {
271 $log.error("[AngularJS - Leaflet] The bounds array is not valid.");
272 return;
273 }
274
275 return {
276 northEast: {
277 lat: boundsArray[0][0],
278 lng: boundsArray[0][1]
279 },
280 southWest: {
281 lat: boundsArray[1][0],
282 lng: boundsArray[1][1]
283 }
284 };
285 },
286
287 createBoundsFromLeaflet: function createBoundsFromLeaflet(lfBounds) {
288 if (!(isDefined(lfBounds) && isFunction(lfBounds.getNorthEast) && isFunction(lfBounds.getSouthWest))) {
289 $log.error("[AngularJS - Leaflet] The leaflet bounds is not valid object.");
290 return;
291 }
292
293 var northEast = lfBounds.getNorthEast(),
294 southWest = lfBounds.getSouthWest();
295
296 return {
297 northEast: {
298 lat: northEast.lat,
299 lng: northEast.lng
300 },
301 southWest: {
302 lat: southWest.lat,
303 lng: southWest.lng
304 }
305 };
306 }
307 };
308}]);
309
310'use strict';
311
312angular.module('ui-leaflet').factory('leafletControlHelpers', ["$rootScope", "leafletLogger", "leafletHelpers", "leafletLayerHelpers", "leafletMapDefaults", function ($rootScope, leafletLogger, leafletHelpers, leafletLayerHelpers, leafletMapDefaults) {
313 var isDefined = leafletHelpers.isDefined,
314 isObject = leafletHelpers.isObject,
315 createLayer = leafletLayerHelpers.createLayer,
316 _controls = {},
317 errorHeader = leafletHelpers.errorHeader + ' [Controls] ',
318 $log = leafletLogger;
319
320 var _controlLayersMustBeVisible = function _controlLayersMustBeVisible(baselayers, overlays, mapId) {
321 var defaults = leafletMapDefaults.getDefaults(mapId);
322 if (!defaults.controls.layers.visible) {
323 return false;
324 }
325
326 var atLeastOneControlItemMustBeShown = false;
327
328 if (isObject(baselayers)) {
329 Object.keys(baselayers).forEach(function (key) {
330 var layer = baselayers[key];
331 if (!isDefined(layer.layerOptions) || layer.layerOptions.showOnSelector !== false) {
332 atLeastOneControlItemMustBeShown = true;
333 }
334 });
335 }
336
337 if (isObject(overlays)) {
338 Object.keys(overlays).forEach(function (key) {
339 var layer = overlays[key];
340 if (!isDefined(layer.layerParams) || layer.layerParams.showOnSelector !== false) {
341 atLeastOneControlItemMustBeShown = true;
342 }
343 });
344 }
345
346 return atLeastOneControlItemMustBeShown;
347 };
348
349 var _createLayersControl = function _createLayersControl(mapId) {
350 var defaults = leafletMapDefaults.getDefaults(mapId);
351 var controlOptions = {
352 collapsed: defaults.controls.layers.collapsed,
353 position: defaults.controls.layers.position,
354 autoZIndex: false
355 };
356
357 angular.extend(controlOptions, defaults.controls.layers.options);
358
359 var control;
360 if (defaults.controls.layers && isDefined(defaults.controls.layers.control)) {
361 control = defaults.controls.layers.control.apply(this, [[], [], controlOptions]);
362 } else {
363 control = new L.control.layers([], [], controlOptions);
364 }
365
366 return control;
367 };
368
369 var controlTypes = {
370 draw: {
371 isPluginLoaded: function isPluginLoaded() {
372 if (!angular.isDefined(L.Control.Draw)) {
373 $log.error(errorHeader + ' Draw plugin is not loaded.');
374 return false;
375 }
376 return true;
377 },
378 checkValidParams: function checkValidParams() /* params */{
379 return true;
380 },
381 createControl: function createControl(params) {
382 return new L.Control.Draw(params);
383 }
384 },
385 scale: {
386 isPluginLoaded: function isPluginLoaded() {
387 return true;
388 },
389 checkValidParams: function checkValidParams() /* params */{
390 return true;
391 },
392 createControl: function createControl(params) {
393 return new L.control.scale(params);
394 }
395 },
396 fullscreen: {
397 isPluginLoaded: function isPluginLoaded() {
398 if (!angular.isDefined(L.Control.Fullscreen)) {
399 $log.error(errorHeader + ' Fullscreen plugin is not loaded.');
400 return false;
401 }
402 return true;
403 },
404 checkValidParams: function checkValidParams() /* params */{
405 return true;
406 },
407 createControl: function createControl(params) {
408 return new L.Control.Fullscreen(params);
409 }
410 },
411 search: {
412 isPluginLoaded: function isPluginLoaded() {
413 if (!angular.isDefined(L.Control.Search)) {
414 $log.error(errorHeader + ' Search plugin is not loaded.');
415 return false;
416 }
417 return true;
418 },
419 checkValidParams: function checkValidParams() /* params */{
420 return true;
421 },
422 createControl: function createControl(params) {
423 return new L.Control.Search(params);
424 }
425 },
426 custom: {},
427 minimap: {
428 isPluginLoaded: function isPluginLoaded() {
429 if (!angular.isDefined(L.Control.MiniMap)) {
430 $log.error(errorHeader + ' Minimap plugin is not loaded.');
431 return false;
432 }
433
434 return true;
435 },
436 checkValidParams: function checkValidParams(params) {
437 if (!isDefined(params.layer)) {
438 $log.warn(errorHeader + ' minimap "layer" option should be defined.');
439 return false;
440 }
441 return true;
442 },
443 createControl: function createControl(params) {
444 var layer = createLayer(params.layer);
445
446 if (!isDefined(layer)) {
447 $log.warn(errorHeader + ' minimap control "layer" could not be created.');
448 return;
449 }
450
451 return new L.Control.MiniMap(layer, params);
452 }
453 }
454 };
455
456 return {
457 layersControlMustBeVisible: _controlLayersMustBeVisible,
458
459 isValidControlType: function isValidControlType(type) {
460 return Object.keys(controlTypes).indexOf(type) !== -1;
461 },
462
463 createControl: function createControl(type, params) {
464 if (!controlTypes[type].checkValidParams(params)) {
465 return;
466 }
467
468 return controlTypes[type].createControl(params);
469 },
470
471 updateLayersControl: function updateLayersControl(map, mapId, loaded, baselayers, overlays, leafletLayers) {
472 var i;
473 var _layersControl = _controls[mapId];
474 var mustBeLoaded = _controlLayersMustBeVisible(baselayers, overlays, mapId);
475
476 if (isDefined(_layersControl) && loaded) {
477 for (i in leafletLayers.baselayers) {
478 _layersControl.removeLayer(leafletLayers.baselayers[i]);
479 }
480 for (i in leafletLayers.overlays) {
481 _layersControl.removeLayer(leafletLayers.overlays[i]);
482 }
483 map.removeControl(_layersControl);
484 delete _controls[mapId];
485 }
486
487 if (mustBeLoaded) {
488 _layersControl = _createLayersControl(mapId);
489 _controls[mapId] = _layersControl;
490 for (i in baselayers) {
491 var hideOnSelector = isDefined(baselayers[i].layerOptions) && baselayers[i].layerOptions.showOnSelector === false;
492 if (!hideOnSelector && isDefined(leafletLayers.baselayers[i])) {
493 _layersControl.addBaseLayer(leafletLayers.baselayers[i], baselayers[i].name);
494 }
495 }
496 for (i in overlays) {
497 var hideOverlayOnSelector = isDefined(overlays[i].layerParams) && overlays[i].layerParams.showOnSelector === false;
498 if (!hideOverlayOnSelector && isDefined(leafletLayers.overlays[i])) {
499 _layersControl.addOverlay(leafletLayers.overlays[i], overlays[i].name);
500 }
501 }
502
503 map.addControl(_layersControl);
504 }
505 return mustBeLoaded;
506 },
507
508 destroyMapLayersControl: function destroyMapLayersControl(mapId) {
509 delete _controls[mapId];
510 }
511 };
512}]);
513
514'use strict';
515
516angular.module('ui-leaflet').service('leafletData', ["leafletLogger", "$q", "leafletHelpers", function (leafletLogger, $q, leafletHelpers) {
517 var getDefer = leafletHelpers.getDefer,
518 getUnresolvedDefer = leafletHelpers.getUnresolvedDefer,
519 setResolvedDefer = leafletHelpers.setResolvedDefer;
520 // $log = leafletLogger;
521
522 var _private = {};
523 var self = this;
524
525 var upperFirst = function upperFirst(string) {
526 return string.charAt(0).toUpperCase() + string.slice(1);
527 };
528
529 var _privateItems = ['map', 'tiles', 'layers', 'paths', 'markers', 'geoJSON', 'UTFGrid', //odd ball on naming convention keeping to not break
530 'decorations', 'directiveControls'];
531
532 //init
533 _privateItems.forEach(function (itemName) {
534 _private[itemName] = {};
535 });
536
537 this.unresolveMap = function (scopeId) {
538 var id = leafletHelpers.obtainEffectiveMapId(_private.map, scopeId);
539 _privateItems.forEach(function (itemName) {
540 _private[itemName][id] = undefined;
541 });
542 };
543
544 //int repetitive stuff (get and sets)
545 _privateItems.forEach(function (itemName) {
546 var name = upperFirst(itemName);
547 self['set' + name] = function (lObject, scopeId) {
548 var defer = getUnresolvedDefer(_private[itemName], scopeId);
549 defer.resolve(lObject);
550 setResolvedDefer(_private[itemName], scopeId);
551 };
552
553 self['get' + name] = function (scopeId) {
554 var defer = getDefer(_private[itemName], scopeId);
555 return defer.promise;
556 };
557 });
558}]);
559
560'use strict';
561
562angular.module('ui-leaflet').service('leafletDirectiveControlsHelpers', ["leafletLogger", "leafletData", "leafletHelpers", function (leafletLogger, leafletData, leafletHelpers) {
563 var _isDefined = leafletHelpers.isDefined,
564 _isString = leafletHelpers.isString,
565 _isObject = leafletHelpers.isObject,
566 _mainErrorHeader = leafletHelpers.errorHeader,
567 $log = leafletLogger;
568
569 var _errorHeader = _mainErrorHeader + '[leafletDirectiveControlsHelpers';
570
571 var _extend = function _extend(id, thingToAddName, createFn, cleanFn) {
572 var _fnHeader = _errorHeader + '.extend] ';
573 var extender = {};
574 if (!_isDefined(thingToAddName)) {
575 $log.error(_fnHeader + 'thingToAddName cannot be undefined');
576 return;
577 }
578
579 if (_isString(thingToAddName) && _isDefined(createFn) && _isDefined(cleanFn)) {
580 extender[thingToAddName] = {
581 create: createFn,
582 clean: cleanFn
583 };
584 } else if (_isObject(thingToAddName) && !_isDefined(createFn) && !_isDefined(cleanFn)) {
585 extender = thingToAddName;
586 } else {
587 $log.error(_fnHeader + 'incorrect arguments');
588 return;
589 }
590
591 //add external control to create / destroy markers without a watch
592 leafletData.getDirectiveControls().then(function (controls) {
593 angular.extend(controls, extender);
594 leafletData.setDirectiveControls(controls, id);
595 });
596 };
597
598 return {
599 extend: _extend
600 };
601}]);
602
603'use strict';
604
605angular.module('ui-leaflet').service('leafletGeoJsonHelpers', ["leafletHelpers", "leafletIterators", function (leafletHelpers, leafletIterators) {
606 var lHlp = leafletHelpers,
607 lIt = leafletIterators;
608 var Point = function Point(lat, lng) {
609 this.lat = lat;
610 this.lng = lng;
611 return this;
612 };
613
614 var _getLat = function _getLat(value) {
615 if (Array.isArray(value) && value.length === 2) {
616 return value[1];
617 } else if (lHlp.isDefined(value.type) && value.type === 'Point') {
618 return +value.coordinates[1];
619 } else {
620 return +value.lat;
621 }
622 };
623
624 var _getLng = function _getLng(value) {
625 if (Array.isArray(value) && value.length === 2) {
626 return value[0];
627 } else if (lHlp.isDefined(value.type) && value.type === 'Point') {
628 return +value.coordinates[0];
629 } else {
630 return +value.lng;
631 }
632 };
633
634 var _validateCoords = function _validateCoords(coords) {
635 if (lHlp.isUndefined(coords)) {
636 return false;
637 }
638 if (lHlp.isArray(coords)) {
639 if (coords.length === 2 && lHlp.isNumber(coords[0]) && lHlp.isNumber(coords[1])) {
640 return true;
641 }
642 } else if (lHlp.isDefined(coords.type)) {
643 if (coords.type === 'Point' && lHlp.isArray(coords.coordinates) && coords.coordinates.length === 2 && lHlp.isNumber(coords.coordinates[0]) && lHlp.isNumber(coords.coordinates[1])) {
644 return true;
645 }
646 }
647
648 var ret = lIt.all(['lat', 'lng'], function (pos) {
649 return lHlp.isDefined(coords[pos]) && lHlp.isNumber(coords[pos]);
650 });
651 return ret;
652 };
653
654 var _getCoords = function _getCoords(value) {
655 if (!value || !_validateCoords(value)) {
656 return;
657 }
658 var p = null;
659 if (Array.isArray(value) && value.length === 2) {
660 p = new Point(value[1], value[0]);
661 } else if (lHlp.isDefined(value.type) && value.type === 'Point') {
662 p = new Point(value.coordinates[1], value.coordinates[0]);
663 } else {
664 return value;
665 }
666 //note angular.merge is avail in angular 1.4.X we might want to fill it here
667 return angular.extend(value, p); //tap on lat, lng if it doesnt exist
668 };
669
670 return {
671 getLat: _getLat,
672 getLng: _getLng,
673 validateCoords: _validateCoords,
674 getCoords: _getCoords
675 };
676}]);
677
678'use strict';
679
680angular.module('ui-leaflet').service('leafletHelpers', ["$q", "$log", "$timeout", function ($q, $log, $timeout) {
681 var _errorHeader = '[ui-leaflet] ';
682 var _copy = angular.copy;
683 var _clone = _copy;
684 /*
685 For parsing paths to a field in an object
686 Example:
687 var obj = {
688 bike:{
689 1: 'hi'
690 2: 'foo'
691 }
692 };
693 _getObjectValue(obj,"bike.1") returns 'hi'
694 this is getPath in ui-gmap
695 */
696 var _getObjectValue = function _getObjectValue(object, pathStr) {
697 var obj;
698 if (!object || !angular.isObject(object)) return;
699 //if the key is not a sting then we already have the value
700 if (pathStr === null || !angular.isString(pathStr)) {
701 return pathStr;
702 }
703 obj = object;
704 pathStr.split('.').forEach(function (value) {
705 if (obj) {
706 obj = obj[value];
707 }
708 });
709 return obj;
710 };
711
712 /*
713 Object Array Notation
714 _getObjectArrayPath("bike.one.two")
715 returns:
716 'bike["one"]["two"]'
717 */
718 var _getObjectArrayPath = function _getObjectArrayPath(pathStr) {
719 return pathStr.split('.').reduce(function (previous, current) {
720 return previous + '["' + current + '"]';
721 });
722 };
723
724 /* Object Dot Notation
725 _getObjectPath(["bike","one","two"])
726 returns:
727 "bike.one.two"
728 */
729 var _getObjectDotPath = function _getObjectDotPath(arrayOfStrings) {
730 return arrayOfStrings.reduce(function (previous, current) {
731 return previous + '.' + current;
732 });
733 };
734
735 function _obtainEffectiveMapId(d, mapId) {
736 var id, i;
737 if (!angular.isDefined(mapId)) {
738 if (Object.keys(d).length === 0) {
739 id = "main";
740 } else if (Object.keys(d).length >= 1) {
741 for (i in d) {
742 if (d.hasOwnProperty(i)) {
743 id = i;
744 }
745 }
746 } else {
747 $log.error(_errorHeader + "- You have more than 1 map on the DOM, you must provide the map ID to the leafletData.getXXX call");
748 }
749 } else {
750 id = mapId;
751 }
752
753 return id;
754 }
755
756 function _getUnresolvedDefer(d, mapId) {
757 var id = _obtainEffectiveMapId(d, mapId),
758 defer;
759
760 if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) {
761 defer = $q.defer();
762 d[id] = {
763 defer: defer,
764 resolvedDefer: false
765 };
766 } else {
767 defer = d[id].defer;
768 }
769
770 return defer;
771 }
772
773 var _isDefined = function _isDefined(value) {
774 return angular.isDefined(value) && value !== null;
775 };
776 var _isUndefined = function _isUndefined(value) {
777 return !_isDefined(value);
778 };
779
780 // BEGIN DIRECT PORT FROM AngularJS code base
781
782 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
783
784 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
785
786 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
787
788 /**
789 Converts snake_case to camelCase.
790 Also there is special case for Moz prefix starting with upper case letter.
791 @param name Name to normalize
792 */
793
794 var camelCase = function camelCase(name) {
795 return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
796 if (offset) {
797 return letter.toUpperCase();
798 } else {
799 return letter;
800 }
801 }).replace(MOZ_HACK_REGEXP, "Moz$1");
802 };
803
804 /**
805 Converts all accepted directives format into proper directive name.
806 @param name Name to normalize
807 */
808
809 var directiveNormalize = function directiveNormalize(name) {
810 return camelCase(name.replace(PREFIX_REGEXP, ""));
811 };
812 // END AngularJS port
813
814 var _watchTrapDelayMilliSec = 10;
815
816 var _modelChangeInDirective = function _modelChangeInDirective(trapObj, trapField, cbToExec) {
817 if (!trapObj) throw new Error(_errorHeader + 'trapObj is undefined');
818 if (!trapField) throw new Error(_errorHeader + 'trapField is undefined');
819
820 trapObj[trapField] = true;
821 var ret = cbToExec();
822 $timeout(function () {
823 trapObj[trapField] = false;
824 }, _watchTrapDelayMilliSec);
825 return ret;
826 };
827
828 return {
829 watchTrapDelayMilliSec: _watchTrapDelayMilliSec,
830 modelChangeInDirective: _modelChangeInDirective,
831 camelCase: camelCase,
832 directiveNormalize: directiveNormalize,
833 copy: _copy,
834 clone: _clone,
835 errorHeader: _errorHeader,
836 getObjectValue: _getObjectValue,
837 getObjectArrayPath: _getObjectArrayPath,
838 getObjectDotPath: _getObjectDotPath,
839 defaultTo: function defaultTo(val, _default) {
840 return _isDefined(val) ? val : _default;
841 },
842 //mainly for checking attributes of directives lets keep this minimal (on what we accept)
843 isTruthy: function isTruthy(val) {
844 return val === 'true' || val === true;
845 },
846 //Determine if a reference is {}
847 isEmpty: function isEmpty(value) {
848 return Object.keys(value).length === 0;
849 },
850
851 //Determine if a reference is undefined or {}
852 isUndefinedOrEmpty: function isUndefinedOrEmpty(value) {
853 return angular.isUndefined(value) || value === null || Object.keys(value).length === 0;
854 },
855
856 // Determine if a reference is defined
857 isDefined: _isDefined,
858 isUndefined: _isUndefined,
859 isNumber: angular.isNumber,
860 isString: angular.isString,
861 isArray: angular.isArray,
862 isObject: angular.isObject,
863 isFunction: angular.isFunction,
864 equals: angular.equals,
865
866 isValidCenter: function isValidCenter(center) {
867 return angular.isDefined(center) && angular.isNumber(center.lat) && angular.isNumber(center.lng) && angular.isNumber(center.zoom);
868 },
869
870 isValidPoint: function isValidPoint(point) {
871 if (!angular.isDefined(point)) {
872 return false;
873 }
874 if (angular.isArray(point)) {
875 return point.length === 2 && angular.isNumber(point[0]) && angular.isNumber(point[1]);
876 }
877 return angular.isNumber(point.lat) && angular.isNumber(point.lng);
878 },
879
880 isSameCenterOnMap: function isSameCenterOnMap(centerModel, map) {
881 var mapCenter = map.getCenter();
882 var zoom = map.getZoom();
883 if (centerModel.lat && centerModel.lng && mapCenter.lat.toFixed(4) === centerModel.lat.toFixed(4) && mapCenter.lng.toFixed(4) === centerModel.lng.toFixed(4) && zoom === centerModel.zoom) {
884 return true;
885 }
886 return false;
887 },
888
889 safeApply: function safeApply($scope, fn) {
890 var phase = $scope.$root.$$phase;
891 if (phase === '$apply' || phase === '$digest') {
892 $scope.$eval(fn);
893 } else {
894 $scope.$evalAsync(fn);
895 }
896 },
897
898 obtainEffectiveMapId: _obtainEffectiveMapId,
899
900 getDefer: function getDefer(d, mapId) {
901 var id = _obtainEffectiveMapId(d, mapId),
902 defer;
903 if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) {
904 defer = _getUnresolvedDefer(d, mapId);
905 } else {
906 defer = d[id].defer;
907 }
908 return defer;
909 },
910
911 getUnresolvedDefer: _getUnresolvedDefer,
912
913 setResolvedDefer: function setResolvedDefer(d, mapId) {
914 var id = _obtainEffectiveMapId(d, mapId);
915 d[id].resolvedDefer = true;
916 },
917
918 rangeIsSupported: function rangeIsSupported() {
919 var testrange = document.createElement('input');
920 testrange.setAttribute('type', 'range');
921 return testrange.type === 'range';
922 },
923
924 FullScreenControlPlugin: {
925 isLoaded: function isLoaded() {
926 return angular.isDefined(L.Control.Fullscreen);
927 }
928 },
929
930 MiniMapControlPlugin: {
931 isLoaded: function isLoaded() {
932 return angular.isDefined(L.Control.MiniMap);
933 }
934 },
935
936 AwesomeMarkersPlugin: {
937 isLoaded: function isLoaded() {
938 return angular.isDefined(L.AwesomeMarkers) && angular.isDefined(L.AwesomeMarkers.Icon);
939 },
940 is: function is(icon) {
941 if (this.isLoaded()) {
942 return icon instanceof L.AwesomeMarkers.Icon;
943 } else {
944 return false;
945 }
946 },
947 equal: function equal(iconA, iconB) {
948 if (!this.isLoaded()) {
949 return false;
950 }
951 if (this.is(iconA)) {
952 return angular.equals(iconA, iconB);
953 } else {
954 return false;
955 }
956 }
957 },
958
959 VectorMarkersPlugin: {
960 isLoaded: function isLoaded() {
961 return angular.isDefined(L.VectorMarkers) && angular.isDefined(L.VectorMarkers.Icon);
962 },
963 is: function is(icon) {
964 if (this.isLoaded()) {
965 return icon instanceof L.VectorMarkers.Icon;
966 } else {
967 return false;
968 }
969 },
970 equal: function equal(iconA, iconB) {
971 if (!this.isLoaded()) {
972 return false;
973 }
974 if (this.is(iconA)) {
975 return angular.equals(iconA, iconB);
976 } else {
977 return false;
978 }
979 }
980 },
981
982 DomMarkersPlugin: {
983 isLoaded: function isLoaded() {
984 if (angular.isDefined(L.DomMarkers) && angular.isDefined(L.DomMarkers.Icon)) {
985 return true;
986 } else {
987 return false;
988 }
989 },
990 is: function is(icon) {
991 if (this.isLoaded()) {
992 return icon instanceof L.DomMarkers.Icon;
993 } else {
994 return false;
995 }
996 },
997 equal: function equal(iconA, iconB) {
998 if (!this.isLoaded()) {
999 return false;
1000 }
1001 if (this.is(iconA)) {
1002 return angular.equals(iconA, iconB);
1003 } else {
1004 return false;
1005 }
1006 }
1007 },
1008
1009 PolylineDecoratorPlugin: {
1010 isLoaded: function isLoaded() {
1011 if (angular.isDefined(L.PolylineDecorator)) {
1012 return true;
1013 } else {
1014 return false;
1015 }
1016 },
1017 is: function is(decoration) {
1018 if (this.isLoaded()) {
1019 return decoration instanceof L.PolylineDecorator;
1020 } else {
1021 return false;
1022 }
1023 },
1024 equal: function equal(decorationA, decorationB) {
1025 if (!this.isLoaded()) {
1026 return false;
1027 }
1028 if (this.is(decorationA)) {
1029 return angular.equals(decorationA, decorationB);
1030 } else {
1031 return false;
1032 }
1033 }
1034 },
1035
1036 MakiMarkersPlugin: {
1037 isLoaded: function isLoaded() {
1038 if (angular.isDefined(L.MakiMarkers) && angular.isDefined(L.MakiMarkers.Icon)) {
1039 return true;
1040 } else {
1041 return false;
1042 }
1043 },
1044 is: function is(icon) {
1045 if (this.isLoaded()) {
1046 return icon instanceof L.MakiMarkers.Icon;
1047 } else {
1048 return false;
1049 }
1050 },
1051 equal: function equal(iconA, iconB) {
1052 if (!this.isLoaded()) {
1053 return false;
1054 }
1055 if (this.is(iconA)) {
1056 return angular.equals(iconA, iconB);
1057 } else {
1058 return false;
1059 }
1060 }
1061 },
1062 ExtraMarkersPlugin: {
1063 isLoaded: function isLoaded() {
1064 if (angular.isDefined(L.ExtraMarkers) && angular.isDefined(L.ExtraMarkers.Icon)) {
1065 return true;
1066 } else {
1067 return false;
1068 }
1069 },
1070 is: function is(icon) {
1071 if (this.isLoaded()) {
1072 return icon instanceof L.ExtraMarkers.Icon;
1073 } else {
1074 return false;
1075 }
1076 },
1077 equal: function equal(iconA, iconB) {
1078 if (!this.isLoaded()) {
1079 return false;
1080 }
1081 if (this.is(iconA)) {
1082 return angular.equals(iconA, iconB);
1083 } else {
1084 return false;
1085 }
1086 }
1087 },
1088 LabelPlugin: {
1089 isLoaded: function isLoaded() {
1090 return angular.isDefined(L.Label);
1091 },
1092 is: function is(layer) {
1093 if (this.isLoaded()) {
1094 return layer instanceof L.MarkerClusterGroup;
1095 } else {
1096 return false;
1097 }
1098 }
1099 },
1100 MarkerClusterPlugin: {
1101 isLoaded: function isLoaded() {
1102 return angular.isDefined(L.MarkerClusterGroup);
1103 },
1104 is: function is(layer) {
1105 if (this.isLoaded()) {
1106 return layer instanceof L.MarkerClusterGroup;
1107 } else {
1108 return false;
1109 }
1110 }
1111 },
1112 GeoJSONPlugin: {
1113 isLoaded: function isLoaded() {
1114 return angular.isDefined(L.TileLayer.GeoJSON);
1115 },
1116 is: function is(layer) {
1117 if (this.isLoaded()) {
1118 return layer instanceof L.TileLayer.GeoJSON;
1119 } else {
1120 return false;
1121 }
1122 }
1123 },
1124 CartoDB: {
1125 isLoaded: function isLoaded() {
1126 return cartodb;
1127 },
1128 is: function is() /*layer*/{
1129 return true;
1130 /*
1131 if (this.isLoaded()) {
1132 return layer instanceof L.TileLayer.GeoJSON;
1133 } else {
1134 return false;
1135 }*/
1136 }
1137 },
1138 Leaflet: {
1139 DivIcon: {
1140 is: function is(icon) {
1141 return icon instanceof L.DivIcon;
1142 },
1143 equal: function equal(iconA, iconB) {
1144 if (this.is(iconA)) {
1145 return angular.equals(iconA, iconB);
1146 } else {
1147 return false;
1148 }
1149 }
1150 },
1151 Icon: {
1152 is: function is(icon) {
1153 return icon instanceof L.Icon;
1154 },
1155 equal: function equal(iconA, iconB) {
1156 if (this.is(iconA)) {
1157 return angular.equals(iconA, iconB);
1158 } else {
1159 return false;
1160 }
1161 }
1162 }
1163 },
1164 /*
1165 watchOptions - object to set deep nested watches and turn off watches all together
1166 (rely on control / functional updates)
1167 watchOptions - Object
1168 type: string. //One of ['watch', 'watchCollection', 'watchDeep', null]
1169 individual
1170 type: string
1171 */
1172 //legacy defaults
1173 watchOptions: {
1174 type: 'watchDeep',
1175 individual: {
1176 type: 'watchDeep'
1177 }
1178 }
1179 };
1180}]);
1181
1182'use strict';
1183
1184angular.module('ui-leaflet').service('leafletIterators', ["leafletLogger", "leafletHelpers", function (leafletLogger, leafletHelpers) {
1185
1186 var lHlp = leafletHelpers,
1187 errorHeader = leafletHelpers.errorHeader + 'leafletIterators: ';
1188
1189 //BEGIN COPY from underscore
1190 var _keys = Object.keys;
1191 var _isFunction = lHlp.isFunction;
1192 var _isObject = lHlp.isObject;
1193 var $log = leafletLogger;
1194
1195 // Helper for collection methods to determine whether a collection
1196 // should be iterated as an array or as an object
1197 // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
1198 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
1199
1200 var _isArrayLike = function _isArrayLike(collection) {
1201 var length = collection !== null && collection.length;
1202 return lHlp.isNumber(length) && length >= 0 && length <= MAX_ARRAY_INDEX;
1203 };
1204
1205 // Keep the identity function around for default iteratees.
1206 var _identity = function _identity(value) {
1207 return value;
1208 };
1209
1210 var _property = function _property(key) {
1211 return function (obj) {
1212 return obj === null ? void 0 : obj[key];
1213 };
1214 };
1215
1216 // Internal function that returns an efficient (for current engines) version
1217 // of the passed-in callback, to be repeatedly applied in other Underscore
1218 // functions.
1219 var optimizeCb = function optimizeCb(func, context, argCount) {
1220 if (context === void 0) return func;
1221 switch (argCount === null ? 3 : argCount) {
1222 case 1:
1223 return function (value) {
1224 return func.call(context, value);
1225 };
1226 case 2:
1227 return function (value, other) {
1228 return func.call(context, value, other);
1229 };
1230 case 3:
1231 return function (value, index, collection) {
1232 return func.call(context, value, index, collection);
1233 };
1234 case 4:
1235 return function (accumulator, value, index, collection) {
1236 return func.call(context, accumulator, value, index, collection);
1237 };
1238 }
1239 return function () {
1240 return func.apply(context, arguments);
1241 };
1242 };
1243
1244 // An internal function for creating assigner functions.
1245 var createAssigner = function createAssigner(keysFunc, undefinedOnly) {
1246 return function (obj) {
1247 var length = arguments.length;
1248 if (length < 2 || obj === null) return obj;
1249 for (var index = 1; index < length; index++) {
1250 var source = arguments[index],
1251 keys = keysFunc(source),
1252 l = keys.length;
1253 for (var i = 0; i < l; i++) {
1254 var key = keys[i];
1255 if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
1256 }
1257 }
1258 return obj;
1259 };
1260 };
1261
1262 // Assigns a given object with all the own properties in the passed-in object(s)
1263 // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
1264 var _extendOwn,
1265 _assign = null;
1266 _extendOwn = _assign = createAssigner(_keys);
1267
1268 // Returns whether an object has a given set of `key:value` pairs.
1269 var _isMatch = function _isMatch(object, attrs) {
1270 var keys = _keys(attrs),
1271 length = keys.length;
1272 if (object === null) return !length;
1273 var obj = Object(object);
1274 for (var i = 0; i < length; i++) {
1275 var key = keys[i];
1276 if (attrs[key] !== obj[key] || !(key in obj)) return false;
1277 }
1278 return true;
1279 };
1280
1281 // Returns a predicate for checking whether an object has a given set of
1282 // `key:value` pairs.
1283 var _matcher,
1284 _matches = null;
1285 _matcher = _matches = function _matches(attrs) {
1286 attrs = _extendOwn({}, attrs);
1287 return function (obj) {
1288 return _isMatch(obj, attrs);
1289 };
1290 };
1291
1292 // A mostly-internal function to generate callbacks that can be applied
1293 // to each element in a collection, returning the desired result — either
1294 // identity, an arbitrary callback, a property matcher, or a property accessor.
1295 var cb = function cb(value, context, argCount) {
1296 if (value === null) return _identity;
1297 if (_isFunction(value)) return optimizeCb(value, context, argCount);
1298 if (_isObject(value)) return _matcher(value);
1299 return _property(value);
1300 };
1301
1302 var _every,
1303 _all = null;
1304 _every = _all = function _all(obj, predicate, context) {
1305 predicate = cb(predicate, context);
1306 var keys = !_isArrayLike(obj) && _keys(obj),
1307 length = (keys || obj).length;
1308 for (var index = 0; index < length; index++) {
1309 var currentKey = keys ? keys[index] : index;
1310 if (!predicate(obj[currentKey], currentKey, obj)) return false;
1311 }
1312 return true;
1313 };
1314
1315 //END COPY fron underscore
1316
1317 var _hasErrors = function _hasErrors(collection, cb, ignoreCollection, cbName) {
1318 if (!ignoreCollection) {
1319 if (!lHlp.isDefined(collection) || !lHlp.isDefined(cb)) {
1320 return true;
1321 }
1322 }
1323 if (!lHlp.isFunction(cb)) {
1324 cbName = lHlp.defaultTo(cb, 'cb');
1325 $log.error(errorHeader + cbName + ' is not a function');
1326 return true;
1327 }
1328 return false;
1329 };
1330
1331 var _iterate = function _iterate(collection, externalCb, internalCb) {
1332 if (_hasErrors(undefined, internalCb, true, 'internalCb')) {
1333 return;
1334 }
1335 if (!_hasErrors(collection, externalCb)) {
1336 for (var key in collection) {
1337 if (collection.hasOwnProperty(key)) {
1338 internalCb(collection[key], key);
1339 }
1340 }
1341 }
1342 };
1343
1344 //see http://jsperf.com/iterators/3
1345 //utilizing for in is way faster
1346 var _each = function _each(collection, cb) {
1347 _iterate(collection, cb, function (val, key) {
1348 cb(val, key);
1349 });
1350 };
1351
1352 return {
1353 each: _each,
1354 forEach: _each,
1355 every: _every,
1356 all: _all
1357 };
1358}]);
1359
1360'use strict';
1361
1362angular.module('ui-leaflet').factory('leafletLayerHelpers', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", "leafletIterators", function ($rootScope, $q, leafletLogger, leafletHelpers, leafletIterators) {
1363 var Helpers = leafletHelpers;
1364 var isString = leafletHelpers.isString;
1365 var isObject = leafletHelpers.isObject;
1366 var isArray = leafletHelpers.isArray;
1367 var isDefined = leafletHelpers.isDefined;
1368 var errorHeader = leafletHelpers.errorHeader;
1369 var $it = leafletIterators;
1370 var $log = leafletLogger;
1371
1372 var utfGridCreateLayer = function utfGridCreateLayer(params) {
1373 if (!Helpers.UTFGridPlugin.isLoaded()) {
1374 $log.error('[AngularJS - Leaflet] The UTFGrid plugin is not loaded.');
1375 return;
1376 }
1377 var utfgrid = new L.UtfGrid(params.url, params.pluginOptions);
1378
1379 var toSend = {
1380 model: params.$parent
1381 };
1382
1383 // TODO Use event manager
1384 utfgrid.on('mouseover', function (e) {
1385 angular.extend(toSend, {
1386 leafletEvent: e,
1387 leafletObject: e.target
1388 });
1389 $rootScope.$broadcast('leafletDirectiveMap.utfgridMouseover', toSend);
1390 });
1391
1392 utfgrid.on('mouseout', function (e) {
1393 angular.extend(toSend, {
1394 leafletEvent: e,
1395 leafletObject: e.target
1396 });
1397 $rootScope.$broadcast('leafletDirectiveMap.utfgridMouseout', toSend);
1398 });
1399
1400 utfgrid.on('click', function (e) {
1401 angular.extend(toSend, {
1402 leafletEvent: e,
1403 leafletObject: e.target
1404 });
1405 $rootScope.$broadcast('leafletDirectiveMap.utfgridClick', toSend);
1406 });
1407
1408 utfgrid.on('mousemove', function (e) {
1409 angular.extend(toSend, {
1410 leafletEvent: e,
1411 leafletObject: e.target
1412 });
1413 $rootScope.$broadcast('leafletDirectiveMap.utfgridMousemove', toSend);
1414 });
1415
1416 return utfgrid;
1417 };
1418
1419 var layerTypes = {
1420 xyz: {
1421 mustHaveUrl: true,
1422 createLayer: function createLayer(params) {
1423 return L.tileLayer(params.url, params.options);
1424 }
1425 },
1426 geoJSON: {
1427 mustHaveUrl: true,
1428 createLayer: function createLayer(params) {
1429 if (!Helpers.GeoJSONPlugin.isLoaded()) {
1430 return;
1431 }
1432 return new L.TileLayer.GeoJSON(params.url, params.pluginOptions, params.options);
1433 }
1434 },
1435 geoJSONShape: {
1436 mustHaveUrl: false,
1437 createLayer: function createLayer(params) {
1438 return new L.GeoJSON(params.data, params.options);
1439 }
1440 },
1441 geoJSONAwesomeMarker: {
1442 mustHaveUrl: false,
1443 createLayer: function createLayer(params) {
1444 return new L.geoJson(params.data, {
1445 pointToLayer: function pointToLayer(feature, latlng) {
1446 return L.marker(latlng, { icon: L.AwesomeMarkers.icon(params.icon) });
1447 }
1448 });
1449 }
1450 },
1451 geoJSONVectorMarker: {
1452 mustHaveUrl: false,
1453 createLayer: function createLayer(params) {
1454 return new L.geoJson(params.data, {
1455 pointToLayer: function pointToLayer(feature, latlng) {
1456 return L.marker(latlng, { icon: L.VectorMarkers.icon(params.icon) });
1457 }
1458 });
1459 }
1460 },
1461 cartodbTiles: {
1462 mustHaveKey: true,
1463 createLayer: function createLayer(params) {
1464 var url = isDefined(params.url) ? params.url + '/' + params.user : '//' + params.user + '.cartodb.com';
1465 url += '/api/v1/map/' + params.key + '/{z}/{x}/{y}.png';
1466 return L.tileLayer(url, params.options);
1467 }
1468 },
1469 cartodbUTFGrid: {
1470 mustHaveKey: true,
1471 mustHaveLayer: true,
1472 createLayer: function createLayer(params) {
1473 var url = isDefined(params.url) ? params.url + '/' + params.user : '//' + params.user + '.cartodb.com';
1474 params.url = url + '/api/v1/map/' + params.key + '/' + params.layer + '/{z}/{x}/{y}.grid.json';
1475 return utfGridCreateLayer(params);
1476 }
1477 },
1478 cartodbInteractive: {
1479 mustHaveKey: true,
1480 mustHaveLayer: true,
1481 createLayer: function createLayer(params) {
1482 var url = isDefined(params.url) ? params.url + '/' + params.user : '//' + params.user + '.cartodb.com';
1483 var tilesURL = url + '/api/v1/map/' + params.key + '/{z}/{x}/{y}.png';
1484 var tileLayer = L.tileLayer(tilesURL, params.options);
1485 var layers = [tileLayer];
1486
1487 var addUtfLayer = function addUtfLayer(parent, params, layer) {
1488 var paramsCopy = angular.copy(params);
1489 paramsCopy.url = url + '/api/v1/map/' + paramsCopy.key + '/' + layer + '/{z}/{x}/{y}.grid.json';
1490 parent.push(utfGridCreateLayer(paramsCopy));
1491 };
1492
1493 if (isArray(params.layer)) {
1494 for (var i = 0; i < params.layer.length; i++) {
1495 addUtfLayer(layers, params, params.layer[i]);
1496 }
1497 } else {
1498 addUtfLayer(layers, params, params.layer);
1499 }
1500 return L.layerGroup(layers);
1501 }
1502 },
1503 wms: {
1504 mustHaveUrl: true,
1505 createLayer: function createLayer(params) {
1506 return L.tileLayer.wms(params.url, params.options);
1507 }
1508 },
1509 wmts: {
1510 mustHaveUrl: true,
1511 createLayer: function createLayer(params) {
1512 return L.tileLayer.wmts(params.url, params.options);
1513 }
1514 },
1515 group: {
1516 mustHaveUrl: false,
1517 createLayer: function createLayer(params) {
1518 var lyrs = [];
1519 $it.each(params.options.layers, function (l) {
1520 lyrs.push(_createLayer(l));
1521 });
1522 params.options.loadedDefer = function () {
1523 var defers = [];
1524 if (isDefined(params.options.layers)) {
1525 for (var i = 0; i < params.options.layers.length; i++) {
1526 var d = params.options.layers[i].layerOptions.loadedDefer;
1527 if (isDefined(d)) {
1528 defers.push(d);
1529 }
1530 }
1531 }
1532 return defers;
1533 };
1534 return L.layerGroup(lyrs);
1535 }
1536 },
1537 featureGroup: {
1538 mustHaveUrl: false,
1539 createLayer: function createLayer() {
1540 return L.featureGroup();
1541 }
1542 },
1543 markercluster: {
1544 mustHaveUrl: false,
1545 createLayer: function createLayer(params) {
1546 if (!Helpers.MarkerClusterPlugin.isLoaded()) {
1547 $log.warn(errorHeader + ' The markercluster plugin is not loaded.');
1548 return;
1549 }
1550 return new L.MarkerClusterGroup(params.options);
1551 }
1552 },
1553 imageOverlay: {
1554 mustHaveUrl: true,
1555 mustHaveBounds: true,
1556 createLayer: function createLayer(params) {
1557 return L.imageOverlay(params.url, params.bounds, params.options);
1558 }
1559 },
1560 iip: {
1561 mustHaveUrl: true,
1562 createLayer: function createLayer(params) {
1563 return L.tileLayer.iip(params.url, params.options);
1564 }
1565 },
1566
1567 // This "custom" type is used to accept every layer that user want to define himself.
1568 // We can wrap these custom layers like heatmap or yandex, but it means a lot of work/code to wrap the world,
1569 // so we let user to define their own layer outside the directive,
1570 // and pass it on "createLayer" result for next processes
1571 custom: {
1572 createLayer: function createLayer(params) {
1573 if (params.layer instanceof L.Class) {
1574 return angular.copy(params.layer);
1575 } else {
1576 $log.error('[AngularJS - Leaflet] A custom layer must be a leaflet Class');
1577 }
1578 }
1579 },
1580 cartodb: {
1581 mustHaveUrl: true,
1582 createLayer: function createLayer(params) {
1583 return cartodb.createLayer(params.map, params.url);
1584 }
1585 }
1586 };
1587
1588 function isValidLayerType(layerDefinition) {
1589 // Check if the baselayer has a valid type
1590 if (!isString(layerDefinition.type)) {
1591 $log.error('[AngularJS - Leaflet] A layer must have a valid type defined.');
1592 return false;
1593 }
1594
1595 if (Object.keys(layerTypes).indexOf(layerDefinition.type) === -1) {
1596 $log.error('[AngularJS - Leaflet] A layer must have a valid type: ' + Object.keys(layerTypes));
1597 return false;
1598 }
1599
1600 // Check if the layer must have an URL
1601 if (layerTypes[layerDefinition.type].mustHaveUrl && !isString(layerDefinition.url)) {
1602 $log.error('[AngularJS - Leaflet] A base layer must have an url');
1603 return false;
1604 }
1605
1606 if (layerTypes[layerDefinition.type].mustHaveData && !isDefined(layerDefinition.data)) {
1607 $log.error('[AngularJS - Leaflet] The base layer must have a "data" array attribute');
1608 return false;
1609 }
1610
1611 if (layerTypes[layerDefinition.type].mustHaveLayer && !isDefined(layerDefinition.layer)) {
1612 $log.error('[AngularJS - Leaflet] The type of layer ' + layerDefinition.type + ' must have an layer defined');
1613 return false;
1614 }
1615
1616 if (layerTypes[layerDefinition.type].mustHaveBounds && !isDefined(layerDefinition.bounds)) {
1617 $log.error('[AngularJS - Leaflet] The type of layer ' + layerDefinition.type + ' must have bounds defined');
1618 return false;
1619 }
1620
1621 if (layerTypes[layerDefinition.type].mustHaveKey && !isDefined(layerDefinition.key)) {
1622 $log.error('[AngularJS - Leaflet] The type of layer ' + layerDefinition.type + ' must have key defined');
1623 return false;
1624 }
1625 return true;
1626 }
1627
1628 function _createLayer(layerDefinition) {
1629 if (!isValidLayerType(layerDefinition)) {
1630 return;
1631 }
1632
1633 if (!isString(layerDefinition.name)) {
1634 $log.error('[AngularJS - Leaflet] A base layer must have a name');
1635 return;
1636 }
1637 if (!isObject(layerDefinition.layerParams)) {
1638 layerDefinition.layerParams = {};
1639 }
1640 if (!isObject(layerDefinition.layerOptions)) {
1641 layerDefinition.layerOptions = {};
1642 }
1643
1644 // Mix the layer specific parameters with the general Leaflet options. Although this is an overhead
1645 // the definition of a base layers is more 'clean' if the two types of parameters are differentiated
1646 for (var attrname in layerDefinition.layerParams) {
1647 layerDefinition.layerOptions[attrname] = layerDefinition.layerParams[attrname];
1648 }
1649
1650 var params = {
1651 url: layerDefinition.url,
1652 data: layerDefinition.data,
1653 options: layerDefinition.layerOptions,
1654 layer: layerDefinition.layer,
1655 icon: layerDefinition.icon,
1656 type: layerDefinition.layerType,
1657 bounds: layerDefinition.bounds,
1658 key: layerDefinition.key,
1659 apiKey: layerDefinition.apiKey,
1660 pluginOptions: layerDefinition.pluginOptions,
1661 user: layerDefinition.user,
1662 $parent: layerDefinition
1663 };
1664
1665 //TODO Add $watch to the layer properties
1666 return layerTypes[layerDefinition.type].createLayer(params);
1667 }
1668
1669 function safeAddLayer(map, layer) {
1670 if (layer && typeof layer.addTo === 'function') {
1671 layer.addTo(map);
1672 } else {
1673 map.addLayer(layer);
1674 }
1675 }
1676
1677 function safeRemoveLayer(map, layer, layerOptions) {
1678 if (isDefined(layerOptions) && isDefined(layerOptions.loadedDefer)) {
1679 if (angular.isFunction(layerOptions.loadedDefer)) {
1680 var defers = layerOptions.loadedDefer();
1681 $log.debug('Loaded Deferred', defers);
1682 var count = defers.length;
1683 if (count > 0) {
1684 var resolve = function resolve() {
1685 count--;
1686 if (count === 0) {
1687 map.removeLayer(layer);
1688 }
1689 };
1690
1691 for (var i = 0; i < defers.length; i++) {
1692 defers[i].promise.then(resolve);
1693 }
1694 } else {
1695 map.removeLayer(layer);
1696 }
1697 } else {
1698 layerOptions.loadedDefer.promise.then(function () {
1699 map.removeLayer(layer);
1700 });
1701 }
1702 } else {
1703 map.removeLayer(layer);
1704 }
1705 }
1706
1707 var changeOpacityListener = function changeOpacityListener(op) {
1708 return function (ly) {
1709 if (isDefined(ly.setOpacity)) {
1710 ly.setOpacity(op);
1711 }
1712 };
1713 };
1714
1715 return {
1716 createLayer: _createLayer,
1717 layerTypes: layerTypes,
1718 safeAddLayer: safeAddLayer,
1719 safeRemoveLayer: safeRemoveLayer,
1720 changeOpacityListener: changeOpacityListener
1721 };
1722}]);
1723
1724'use strict';
1725
1726angular.module("ui-leaflet").factory('leafletLegendHelpers', ["$http", "$q", "$log", "leafletHelpers", function ($http, $q, $log, leafletHelpers) {
1727 var requestQueue = {},
1728 isDefined = leafletHelpers.isDefined;
1729
1730 var _execNext = function _execNext(mapId) {
1731 var queue = requestQueue[mapId];
1732 var task = queue[0];
1733 $http(task.c).then(function (data) {
1734 queue.shift();
1735 task.d.resolve(data);
1736 if (queue.length > 0) {
1737 _execNext(mapId);
1738 }
1739 }, function (err) {
1740 queue.shift();
1741 task.d.reject(err);
1742 if (queue.length > 0) {
1743 _execNext(mapId);
1744 }
1745 });
1746 };
1747
1748 var _updateLegend = function _updateLegend(div, legendData, type, url) {
1749 div.innerHTML = '';
1750 if (legendData.error) {
1751 div.innerHTML += '<div class="info-title alert alert-danger">' + legendData.error.message + '</div>';
1752 } else {
1753 if (type === 'arcgis') {
1754 for (var i = 0; i < legendData.layers.length; i++) {
1755 var layer = legendData.layers[i];
1756 div.innerHTML += '<div class="info-title" data-layerid="' + layer.layerId + '">' + layer.layerName + '</div>';
1757 for (var j = 0; j < layer.legend.length; j++) {
1758 var leg = layer.legend[j];
1759 div.innerHTML += '<div class="inline" data-layerid="' + layer.layerId + '"><img src="data:' + leg.contentType + ';base64,' + leg.imageData + '" /></div>' + '<div class="info-label" data-layerid="' + layer.layerId + '">' + leg.label + '</div>';
1760 }
1761 }
1762 } else if (type === 'image') {
1763 div.innerHTML = '<img src="' + url + '"/>';
1764 }
1765 }
1766 };
1767
1768 var _getOnAddLegend = function _getOnAddLegend(legendData, legendClass, type, url) {
1769 return function () /*map*/{
1770 var div = L.DomUtil.create('div', legendClass);
1771
1772 if (!L.Browser.touch) {
1773 L.DomEvent.disableClickPropagation(div);
1774 L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
1775 } else {
1776 L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
1777 }
1778 _updateLegend(div, legendData, type, url);
1779 return div;
1780 };
1781 };
1782
1783 var _getOnAddArrayLegend = function _getOnAddArrayLegend(legend, legendClass) {
1784 return function () /*map*/{
1785 var div = L.DomUtil.create('div', legendClass);
1786 for (var i = 0; i < legend.colors.length; i++) {
1787 div.innerHTML += '<div class="outline"><i style="background:' + legend.colors[i] + '"></i></div>' + '<div class="info-label">' + legend.labels[i] + '</div>';
1788 }
1789 if (!L.Browser.touch) {
1790 L.DomEvent.disableClickPropagation(div);
1791 L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
1792 } else {
1793 L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
1794 }
1795 return div;
1796 };
1797 };
1798
1799 return {
1800 getOnAddLegend: _getOnAddLegend,
1801 getOnAddArrayLegend: _getOnAddArrayLegend,
1802 updateLegend: _updateLegend,
1803 addLegendURL: function addLegendURL(mapId, config) {
1804 var d = $q.defer();
1805 if (!isDefined(requestQueue[mapId])) {
1806 requestQueue[mapId] = [];
1807 }
1808 requestQueue[mapId].push({ c: config, d: d });
1809 if (requestQueue[mapId].length === 1) {
1810 _execNext(mapId);
1811 }
1812 return d.promise;
1813 }
1814 };
1815}]);
1816
1817'use strict';
1818
1819angular.module('ui-leaflet').factory('leafletMapDefaults', ["$q", "leafletHelpers", function ($q, leafletHelpers) {
1820 function _getDefaults() {
1821 return {
1822 keyboard: true,
1823 dragging: true,
1824 worldCopyJump: false,
1825 doubleClickZoom: true,
1826 scrollWheelZoom: true,
1827 tap: true,
1828 touchZoom: true,
1829 zoomControl: true,
1830 zoomsliderControl: false,
1831 zoomControlPosition: 'topleft',
1832 attributionControl: true,
1833 controls: {
1834 layers: {
1835 visible: true,
1836 position: 'topright',
1837 collapsed: true
1838 }
1839 },
1840 nominatim: {
1841 server: ' http://nominatim.openstreetmap.org/search'
1842 },
1843 crs: L.CRS.EPSG3857,
1844 tileLayer: '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
1845 tileLayerOptions: {
1846 attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
1847 },
1848 path: {
1849 weight: 10,
1850 opacity: 1,
1851 color: '#0000ff'
1852 },
1853 center: {
1854 lat: 0,
1855 lng: 0,
1856 zoom: 1
1857 },
1858 trackResize: true
1859 };
1860 }
1861
1862 var isDefined = leafletHelpers.isDefined,
1863 isObject = leafletHelpers.isObject,
1864 obtainEffectiveMapId = leafletHelpers.obtainEffectiveMapId,
1865 defaults = {};
1866
1867 // Get the _defaults dictionary, and override the properties defined by the user
1868 return {
1869 reset: function reset() {
1870 defaults = {};
1871 },
1872 getDefaults: function getDefaults(scopeId) {
1873 var mapId = obtainEffectiveMapId(defaults, scopeId);
1874 return defaults[mapId];
1875 },
1876
1877 getMapCreationDefaults: function getMapCreationDefaults(scopeId) {
1878 var mapId = obtainEffectiveMapId(defaults, scopeId);
1879 var d = defaults[mapId];
1880
1881 var mapDefaults = {
1882 maxZoom: d.maxZoom,
1883 keyboard: d.keyboard,
1884 dragging: d.dragging,
1885 zoomControl: d.zoomControl,
1886 doubleClickZoom: d.doubleClickZoom,
1887 scrollWheelZoom: d.scrollWheelZoom,
1888 tap: d.tap,
1889 touchZoom: d.touchZoom,
1890 attributionControl: d.attributionControl,
1891 worldCopyJump: d.worldCopyJump,
1892 crs: d.crs,
1893 trackResize: d.trackResize
1894 };
1895
1896 if (isDefined(d.minZoom)) {
1897 mapDefaults.minZoom = d.minZoom;
1898 }
1899
1900 if (isDefined(d.zoomAnimation)) {
1901 mapDefaults.zoomAnimation = d.zoomAnimation;
1902 }
1903
1904 if (isDefined(d.fadeAnimation)) {
1905 mapDefaults.fadeAnimation = d.fadeAnimation;
1906 }
1907
1908 if (isDefined(d.markerZoomAnimation)) {
1909 mapDefaults.markerZoomAnimation = d.markerZoomAnimation;
1910 }
1911
1912 if (d.map) {
1913 for (var option in d.map) {
1914 mapDefaults[option] = d.map[option];
1915 }
1916 }
1917
1918 return mapDefaults;
1919 },
1920
1921 setDefaults: function setDefaults(userDefaults, scopeId) {
1922 var newDefaults = _getDefaults();
1923
1924 if (isDefined(userDefaults)) {
1925 newDefaults.doubleClickZoom = isDefined(userDefaults.doubleClickZoom) ? userDefaults.doubleClickZoom : newDefaults.doubleClickZoom;
1926 newDefaults.scrollWheelZoom = isDefined(userDefaults.scrollWheelZoom) ? userDefaults.scrollWheelZoom : newDefaults.doubleClickZoom;
1927 newDefaults.tap = isDefined(userDefaults.tap) ? userDefaults.tap : newDefaults.tap;
1928 newDefaults.touchZoom = isDefined(userDefaults.touchZoom) ? userDefaults.touchZoom : newDefaults.doubleClickZoom;
1929 newDefaults.zoomControl = isDefined(userDefaults.zoomControl) ? userDefaults.zoomControl : newDefaults.zoomControl;
1930 newDefaults.zoomsliderControl = isDefined(userDefaults.zoomsliderControl) ? userDefaults.zoomsliderControl : newDefaults.zoomsliderControl;
1931 newDefaults.attributionControl = isDefined(userDefaults.attributionControl) ? userDefaults.attributionControl : newDefaults.attributionControl;
1932 newDefaults.tileLayer = isDefined(userDefaults.tileLayer) ? userDefaults.tileLayer : newDefaults.tileLayer;
1933 newDefaults.zoomControlPosition = isDefined(userDefaults.zoomControlPosition) ? userDefaults.zoomControlPosition : newDefaults.zoomControlPosition;
1934 newDefaults.keyboard = isDefined(userDefaults.keyboard) ? userDefaults.keyboard : newDefaults.keyboard;
1935 newDefaults.dragging = isDefined(userDefaults.dragging) ? userDefaults.dragging : newDefaults.dragging;
1936 newDefaults.trackResize = isDefined(userDefaults.trackResize) ? userDefaults.trackResize : newDefaults.trackResize;
1937
1938 if (isDefined(userDefaults.controls)) {
1939 angular.extend(newDefaults.controls, userDefaults.controls);
1940 }
1941
1942 if (isObject(userDefaults.crs)) {
1943 newDefaults.crs = userDefaults.crs;
1944 } else if (isDefined(L.CRS[userDefaults.crs])) {
1945 newDefaults.crs = L.CRS[userDefaults.crs];
1946 }
1947
1948 if (isDefined(userDefaults.center)) {
1949 angular.copy(userDefaults.center, newDefaults.center);
1950 }
1951
1952 if (isDefined(userDefaults.tileLayerOptions)) {
1953 angular.copy(userDefaults.tileLayerOptions, newDefaults.tileLayerOptions);
1954 }
1955
1956 if (isDefined(userDefaults.maxZoom)) {
1957 newDefaults.maxZoom = userDefaults.maxZoom;
1958 }
1959
1960 if (isDefined(userDefaults.minZoom)) {
1961 newDefaults.minZoom = userDefaults.minZoom;
1962 }
1963
1964 if (isDefined(userDefaults.zoomAnimation)) {
1965 newDefaults.zoomAnimation = userDefaults.zoomAnimation;
1966 }
1967
1968 if (isDefined(userDefaults.fadeAnimation)) {
1969 newDefaults.fadeAnimation = userDefaults.fadeAnimation;
1970 }
1971
1972 if (isDefined(userDefaults.markerZoomAnimation)) {
1973 newDefaults.markerZoomAnimation = userDefaults.markerZoomAnimation;
1974 }
1975
1976 if (isDefined(userDefaults.worldCopyJump)) {
1977 newDefaults.worldCopyJump = userDefaults.worldCopyJump;
1978 }
1979
1980 if (isDefined(userDefaults.map)) {
1981 newDefaults.map = userDefaults.map;
1982 }
1983
1984 if (isDefined(userDefaults.path)) {
1985 newDefaults.path = userDefaults.path;
1986 }
1987 }
1988
1989 var mapId = obtainEffectiveMapId(defaults, scopeId);
1990 defaults[mapId] = newDefaults;
1991 return newDefaults;
1992 }
1993 };
1994}]);
1995
1996'use strict';
1997
1998angular.module('ui-leaflet').service('leafletMarkersHelpers', ["$rootScope", "$timeout", "leafletHelpers", "leafletLogger", "$compile", "leafletGeoJsonHelpers", "leafletWatchHelpers", function ($rootScope, $timeout, leafletHelpers, leafletLogger, $compile, leafletGeoJsonHelpers, leafletWatchHelpers) {
1999 var isDefined = leafletHelpers.isDefined,
2000 defaultTo = leafletHelpers.defaultTo,
2001 MarkerClusterPlugin = leafletHelpers.MarkerClusterPlugin,
2002 AwesomeMarkersPlugin = leafletHelpers.AwesomeMarkersPlugin,
2003 VectorMarkersPlugin = leafletHelpers.VectorMarkersPlugin,
2004 MakiMarkersPlugin = leafletHelpers.MakiMarkersPlugin,
2005 ExtraMarkersPlugin = leafletHelpers.ExtraMarkersPlugin,
2006 DomMarkersPlugin = leafletHelpers.DomMarkersPlugin,
2007 safeApply = leafletHelpers.safeApply,
2008 Helpers = leafletHelpers,
2009 isString = leafletHelpers.isString,
2010 isNumber = leafletHelpers.isNumber,
2011 isObject = leafletHelpers.isObject,
2012 groups = {},
2013 geoHlp = leafletGeoJsonHelpers,
2014 errorHeader = leafletHelpers.errorHeader,
2015 maybeWatch = leafletWatchHelpers.maybeWatch,
2016 $log = leafletLogger;
2017
2018 var _string = function _string(marker) {
2019 //this exists since JSON.stringify barfs on cyclic
2020 var retStr = '';
2021 ['_icon', '_latlng', '_leaflet_id', '_map', '_shadow'].forEach(function (prop) {
2022 retStr += prop + ': ' + defaultTo(marker[prop], 'undefined') + ' \n';
2023 });
2024 return '[leafletMarker] : \n' + retStr;
2025 };
2026 var _log = function _log(marker, useConsole) {
2027 var logger = useConsole ? console : $log;
2028 logger.debug(_string(marker));
2029 };
2030
2031 var existDomContainer = function existDomContainer(groupName) {
2032 return angular.element(groups[groupName]._map._container).parent().length > 0;
2033 };
2034
2035 var createLeafletIcon = function createLeafletIcon(iconData) {
2036 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'awesomeMarker') {
2037 if (!AwesomeMarkersPlugin.isLoaded()) {
2038 $log.error(errorHeader + ' The AwesomeMarkers Plugin is not loaded.');
2039 }
2040
2041 return new L.AwesomeMarkers.icon(iconData);
2042 }
2043
2044 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'vectorMarker') {
2045 if (!VectorMarkersPlugin.isLoaded()) {
2046 $log.error(errorHeader + ' The VectorMarkers Plugin is not loaded.');
2047 }
2048
2049 return new L.VectorMarkers.icon(iconData);
2050 }
2051
2052 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'makiMarker') {
2053 if (!MakiMarkersPlugin.isLoaded()) {
2054 $log.error(errorHeader + 'The MakiMarkers Plugin is not loaded.');
2055 }
2056
2057 return new L.MakiMarkers.icon(iconData);
2058 }
2059
2060 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'extraMarker') {
2061 if (!ExtraMarkersPlugin.isLoaded()) {
2062 $log.error(errorHeader + 'The ExtraMarkers Plugin is not loaded.');
2063 }
2064 return new L.ExtraMarkers.icon(iconData);
2065 }
2066
2067 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'div') {
2068 return new L.divIcon(iconData);
2069 }
2070
2071 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'dom') {
2072 if (!DomMarkersPlugin.isLoaded()) {
2073 $log.error(errorHeader + 'The DomMarkers Plugin is not loaded.');
2074 }
2075 var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope().$new() : $rootScope,
2076 template = $compile(iconData.template)(markerScope),
2077 iconDataCopy = angular.copy(iconData);
2078 iconDataCopy.ngElement = template;
2079 iconDataCopy.element = template[0];
2080 if (angular.isFunction(iconData.getMarkerScope)) iconDataCopy.scope = markerScope;
2081 return new L.DomMarkers.icon(iconDataCopy);
2082 }
2083
2084 // allow for any custom icon to be used... assumes the icon has already been initialized
2085 if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'icon') {
2086 return iconData.icon;
2087 }
2088
2089 var base64icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGqKII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWVMqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzqBk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0gpBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAwAhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5WYnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRchah8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1EIlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdWr7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIPhP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmqlyvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsYJ7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIavznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDllwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQSCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GCLVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjNcNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg==";
2090 var base64shadow = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAApCAYAAACoYAD2AAAC5ElEQVRYw+2YW4/TMBCF45S0S1luXZCABy5CgLQgwf//S4BYBLTdJLax0fFqmB07nnQfEGqkIydpVH85M+NLjPe++dcPc4Q8Qh4hj5D/AaQJx6H/4TMwB0PeBNwU7EGQAmAtsNfAzoZkgIa0ZgLMa4Aj6CxIAsjhjOCoL5z7Glg1JAOkaicgvQBXuncwJAWjksLtBTWZe04CnYRktUGdilALppZBOgHGZcBzL6OClABvMSVIzyBjazOgrvACf1ydC5mguqAVg6RhdkSWQFj2uxfaq/BrIZOLEWgZdALIDvcMcZLD8ZbLC9de4yR1sYMi4G20S4Q/PWeJYxTOZn5zJXANZHIxAd4JWhPIloTJZhzMQduM89WQ3MUVAE/RnhAXpTycqys3NZALOBbB7kFrgLesQl2h45Fcj8L1tTSohUwuxhy8H/Qg6K7gIs+3kkaigQCOcyEXCHN07wyQazhrmIulvKMQAwMcmLNqyCVyMAI+BuxSMeTk3OPikLY2J1uE+VHQk6ANrhds+tNARqBeaGc72cK550FP4WhXmFmcMGhTwAR1ifOe3EvPqIegFmF+C8gVy0OfAaWQPMR7gF1OQKqGoBjq90HPMP01BUjPOqGFksC4emE48tWQAH0YmvOgF3DST6xieJgHAWxPAHMuNhrImIdvoNOKNWIOcE+UXE0pYAnkX6uhWsgVXDxHdTfCmrEEmMB2zMFimLVOtiiajxiGWrbU52EeCdyOwPEQD8LqyPH9Ti2kgYMf4OhSKB7qYILbBv3CuVTJ11Y80oaseiMWOONc/Y7kJYe0xL2f0BaiFTxknHO5HaMGMublKwxFGzYdWsBF174H/QDknhTHmHHN39iWFnkZx8lPyM8WHfYELmlLKtgWNmFNzQcC1b47gJ4hL19i7o65dhH0Negbca8vONZoP7doIeOC9zXm8RjuL0Gf4d4OYaU5ljo3GYiqzrWQHfJxA6ALhDpVKv9qYeZA8eM3EhfPSCmpuD0AAAAASUVORK5CYII=";
2091
2092 if (!isDefined(iconData) || !isDefined(iconData.iconUrl)) {
2093 return new L.Icon.Default({
2094 iconUrl: base64icon,
2095 shadowUrl: base64shadow,
2096 iconSize: [25, 41],
2097 iconAnchor: [12, 41],
2098 popupAnchor: [1, -34],
2099 shadowSize: [41, 41]
2100 });
2101 }
2102
2103 return new L.Icon(iconData);
2104 };
2105
2106 var _resetMarkerGroup = function _resetMarkerGroup(groupName) {
2107 if (isDefined(groups[groupName])) {
2108 delete groups[groupName];
2109 }
2110 };
2111
2112 var _resetMarkerGroups = function _resetMarkerGroups() {
2113 groups = {};
2114 };
2115
2116 var _resetUnusedMarkerGroups = function _resetUnusedMarkerGroups() {
2117 for (var groupName in groups) {
2118 if (!existDomContainer(groupName)) {
2119 _resetMarkerGroup(groupName);
2120 }
2121 }
2122 };
2123
2124 var _cleanDomIcon = function _cleanDomIcon(marker) {
2125 if (marker.options.icon.options.ngElement) {
2126 marker.options.icon.options.ngElement.remove();
2127 }
2128 if (marker.options.icon.options.scope) {
2129 marker.options.icon.options.scope.$destroy();
2130 }
2131 };
2132
2133 var _deleteMarker = function _deleteMarker(marker, map, layers) {
2134 marker.closePopup();
2135
2136 // if it's a dom icon, clean it
2137 if (marker.options.icon && marker.options.icon.options && marker.options.icon.options.type === 'dom') {
2138 _cleanDomIcon(marker);
2139 }
2140
2141 // There is no easy way to know if a marker is added to a layer, so we search for it
2142 // if there are overlays
2143 if (isDefined(layers) && isDefined(layers.overlays)) {
2144 for (var key in layers.overlays) {
2145 if (layers.overlays[key] instanceof L.LayerGroup || layers.overlays[key] instanceof L.FeatureGroup) {
2146 if (layers.overlays[key].hasLayer(marker)) {
2147 layers.overlays[key].removeLayer(marker);
2148 return;
2149 }
2150 }
2151 }
2152 }
2153
2154 if (isDefined(groups)) {
2155 for (var groupKey in groups) {
2156 if (groups[groupKey].hasLayer(marker)) {
2157 groups[groupKey].removeLayer(marker);
2158 }
2159 }
2160 }
2161
2162 if (map.hasLayer(marker)) {
2163 map.removeLayer(marker);
2164 }
2165 };
2166
2167 var adjustPopupPan = function adjustPopupPan(marker, map) {
2168 var containerHeight = marker._popup._container.offsetHeight,
2169 layerPos = new L.Point(marker._popup._containerLeft, -containerHeight - marker._popup._containerBottom),
2170 containerPos = map.layerPointToContainerPoint(layerPos);
2171 if (containerPos !== null) {
2172 marker._popup._adjustPan();
2173 }
2174 };
2175
2176 var compilePopup = function compilePopup(marker, markerScope) {
2177 $compile(marker._popup._contentNode)(markerScope);
2178 };
2179
2180 var updatePopup = function updatePopup(marker, markerScope, map) {
2181 //The innerText should be more than 1 once angular has compiled.
2182 //We need to keep trying until angular has compiled before we _updateLayout and _updatePosition
2183 //This should take care of any scenario , eg ngincludes, whatever.
2184 //Is there a better way to check for this?
2185 var innerText = marker._popup._contentNode.innerText || marker._popup._contentNode.textContent;
2186 if (innerText.length < 1) {
2187 $timeout(function () {
2188 updatePopup(marker, markerScope, map);
2189 });
2190 }
2191
2192 //cause a reflow - this is also very important - if we don't do this then the widths are from before $compile
2193 var reflow = marker._popup._contentNode.offsetWidth;
2194
2195 marker._popup._updateLayout();
2196 marker._popup._updatePosition();
2197
2198 if (marker._popup.options.autoPan) {
2199 adjustPopupPan(marker, map);
2200 }
2201
2202 //using / returning reflow so jshint doesn't moan
2203 return reflow;
2204 };
2205
2206 var _manageOpenPopup = function _manageOpenPopup(marker, markerData, map) {
2207 // The marker may provide a scope returning function used to compile the message
2208 // default to $rootScope otherwise
2209 var markerScope = angular.isFunction(markerData.getMessageScope) ? markerData.getMessageScope() : $rootScope,
2210 compileMessage = isDefined(markerData.compileMessage) ? markerData.compileMessage : true;
2211
2212 if (compileMessage) {
2213 if (!isDefined(marker._popup) || !isDefined(marker._popup._contentNode)) {
2214 $log.error(errorHeader + 'Popup is invalid or does not have any content.');
2215 return false;
2216 }
2217
2218 compilePopup(marker, markerScope);
2219 updatePopup(marker, markerData, map);
2220 }
2221 };
2222
2223 var _manageOpenLabel = function _manageOpenLabel(marker, markerData) {
2224 var markerScope = angular.isFunction(markerData.getMessageScope) ? markerData.getMessageScope() : $rootScope,
2225 labelScope = angular.isFunction(markerData.getLabelScope) ? markerData.getLabelScope() : markerScope,
2226 compileMessage = isDefined(markerData.compileMessage) ? markerData.compileMessage : true;
2227
2228 if (Helpers.LabelPlugin.isLoaded() && isDefined(markerData.label)) {
2229 if (isDefined(markerData.label.options) && markerData.label.options.noHide === true) {
2230 marker.showLabel();
2231 }
2232 if (compileMessage && isDefined(marker.label)) {
2233 $compile(marker.label._container)(labelScope);
2234 }
2235 }
2236 };
2237
2238 var _updateMarker = function _updateMarker(markerData, oldMarkerData, marker, name, leafletScope, layers, map) {
2239 if (!isDefined(oldMarkerData)) {
2240 return;
2241 }
2242
2243 // Update the lat-lng property (always present in marker properties)
2244 if (!geoHlp.validateCoords(markerData)) {
2245 $log.warn('There are problems with lat-lng data, please verify your marker model');
2246 _deleteMarker(marker, map, layers);
2247 return;
2248 }
2249
2250 // watch is being initialized if old and new object is the same
2251 var isInitializing = markerData === oldMarkerData;
2252
2253 // Update marker rotation
2254 if (isDefined(markerData.iconAngle) && oldMarkerData.iconAngle !== markerData.iconAngle) {
2255 marker.setIconAngle(markerData.iconAngle);
2256 }
2257
2258 // It is possible that the layer has been removed or the layer marker does not exist
2259 // Update the layer group if present or move it to the map if not
2260 if (!isString(markerData.layer)) {
2261 // There is no layer information, we move the marker to the map if it was in a layer group
2262 if (isString(oldMarkerData.layer)) {
2263 // Remove from the layer group that is supposed to be
2264 if (isDefined(layers.overlays[oldMarkerData.layer]) && layers.overlays[oldMarkerData.layer].hasLayer(marker)) {
2265 layers.overlays[oldMarkerData.layer].removeLayer(marker);
2266 marker.closePopup();
2267 }
2268 // Test if it is not on the map and add it
2269 if (!map.hasLayer(marker)) {
2270 map.addLayer(marker);
2271 }
2272 }
2273 }
2274
2275 if ((isNumber(markerData.opacity) || isNumber(parseFloat(markerData.opacity))) && markerData.opacity !== oldMarkerData.opacity) {
2276 // There was a different opacity so we update it
2277 marker.setOpacity(markerData.opacity);
2278 }
2279
2280 if (isString(markerData.layer) && oldMarkerData.layer !== markerData.layer) {
2281 // If it was on a layer group we have to remove it
2282 if (isString(oldMarkerData.layer) && isDefined(layers.overlays[oldMarkerData.layer]) && layers.overlays[oldMarkerData.layer].hasLayer(marker)) {
2283 layers.overlays[oldMarkerData.layer].removeLayer(marker);
2284 }
2285 marker.closePopup();
2286
2287 // Remove it from the map in case the new layer is hidden or there is an error in the new layer
2288 if (map.hasLayer(marker)) {
2289 map.removeLayer(marker);
2290 }
2291
2292 // The markerData.layer is defined so we add the marker to the layer if it is different from the old data
2293 if (!isDefined(layers.overlays[markerData.layer])) {
2294 $log.error(errorHeader + 'You must use a name of an existing layer');
2295 return;
2296 }
2297 // Is a group layer?
2298 var layerGroup = layers.overlays[markerData.layer];
2299 if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) {
2300 $log.error(errorHeader + 'A marker can only be added to a layer of type "group" or "featureGroup"');
2301 return;
2302 }
2303 // The marker goes to a correct layer group, so first of all we add it
2304 layerGroup.addLayer(marker);
2305 // The marker is automatically added to the map depending on the visibility
2306 // of the layer, so we only have to open the popup if the marker is in the map
2307 if (map.hasLayer(marker) && markerData.focus === true) {
2308 marker.openPopup();
2309 }
2310 }
2311
2312 // Update the draggable property
2313 if (markerData.draggable !== true && oldMarkerData.draggable === true && isDefined(marker.dragging)) {
2314 marker.dragging.disable();
2315 }
2316
2317 if (markerData.draggable === true && oldMarkerData.draggable !== true) {
2318 // The markerData.draggable property must be true so we update if there wasn't a previous value or it wasn't true
2319 if (marker.dragging) {
2320 marker.dragging.enable();
2321 } else {
2322 if (L.Handler.MarkerDrag) {
2323 marker.dragging = new L.Handler.MarkerDrag(marker);
2324 marker.options.draggable = true;
2325 marker.dragging.enable();
2326 }
2327 }
2328 }
2329
2330 // Update the icon property
2331 if (!isObject(markerData.icon)) {
2332 // If there is no icon property or it's not an object
2333 if (isObject(oldMarkerData.icon)) {
2334 if (oldMarkerData.icon.type === 'dom') {
2335 // clean previous icon if it's a dom one
2336 _cleanDomIcon(marker);
2337 }
2338 // If there was an icon before restore to the default
2339 marker.setIcon(createLeafletIcon());
2340 marker.closePopup();
2341 marker.unbindPopup();
2342 if (isString(markerData.message)) {
2343 marker.bindPopup(markerData.message, markerData.popupOptions);
2344 }
2345 }
2346 }
2347
2348 if (isObject(markerData.icon) && isObject(oldMarkerData.icon) && !angular.equals(markerData.icon, oldMarkerData.icon)) {
2349 var dragG = false;
2350 if (marker.dragging) {
2351 dragG = marker.dragging.enabled();
2352 }
2353 if (oldMarkerData.icon.type === 'dom') {
2354 // clean previous icon if it's a dom one
2355 _cleanDomIcon(marker);
2356 }
2357 marker.setIcon(createLeafletIcon(markerData.icon));
2358 if (dragG) {
2359 marker.dragging.enable();
2360 }
2361 marker.closePopup();
2362 marker.unbindPopup();
2363 if (isString(markerData.message)) {
2364 marker.bindPopup(markerData.message, markerData.popupOptions);
2365 // if marker has been already focused, reopen popup
2366 if (map.hasLayer(marker) && markerData.focus === true) {
2367 marker.openPopup();
2368 }
2369 }
2370 }
2371
2372 // Update the Popup message property
2373 if (!isString(markerData.message) && isString(oldMarkerData.message)) {
2374 marker.closePopup();
2375 marker.unbindPopup();
2376 }
2377
2378 // Update the label content or bind a new label if the old one has been removed.
2379 if (Helpers.LabelPlugin.isLoaded()) {
2380 if (isDefined(markerData.label) && isDefined(markerData.label.message)) {
2381 if ('label' in oldMarkerData && 'message' in oldMarkerData.label && !angular.equals(markerData.label.message, oldMarkerData.label.message)) {
2382 marker.updateLabelContent(markerData.label.message);
2383 } else if (!angular.isFunction(marker.getLabel) || angular.isFunction(marker.getLabel) && !isDefined(marker.getLabel())) {
2384 marker.bindLabel(markerData.label.message, markerData.label.options);
2385 _manageOpenLabel(marker, markerData);
2386 } else {
2387 _manageOpenLabel(marker, markerData);
2388 }
2389 } else if (!('label' in markerData && !('message' in markerData.label))) {
2390 if (angular.isFunction(marker.unbindLabel)) {
2391 marker.unbindLabel();
2392 }
2393 }
2394 }
2395
2396 // There is some text in the popup, so we must show the text or update existing
2397 if (isString(markerData.message) && !isString(oldMarkerData.message)) {
2398 // There was no message before so we create it
2399 marker.bindPopup(markerData.message, markerData.popupOptions);
2400 }
2401
2402 if (isString(markerData.message) && isString(oldMarkerData.message) && markerData.message !== oldMarkerData.message) {
2403 // There was a different previous message so we update it
2404 marker.setPopupContent(markerData.message);
2405 }
2406
2407 // Update the focus property
2408 var updatedFocus = false;
2409 if (markerData.focus !== true && oldMarkerData.focus === true) {
2410 // If there was a focus property and was true we turn it off
2411 marker.closePopup();
2412 updatedFocus = true;
2413 }
2414
2415 // The markerData.focus property must be true so we update if there wasn't a previous value or it wasn't true
2416 if (markerData.focus === true && (!isDefined(oldMarkerData.focus) || oldMarkerData.focus === false) || isInitializing && markerData.focus === true) {
2417 // Reopen the popup when focus is still true
2418 marker.openPopup();
2419 updatedFocus = true;
2420 }
2421
2422 // zIndexOffset adjustment
2423 if (oldMarkerData.zIndexOffset !== markerData.zIndexOffset) {
2424 marker.setZIndexOffset(markerData.zIndexOffset);
2425 }
2426
2427 var markerLatLng = marker.getLatLng();
2428 var isCluster = isString(markerData.layer) && Helpers.MarkerClusterPlugin.is(layers.overlays[markerData.layer]);
2429 // If the marker is in a cluster it has to be removed and added to the layer when the location is changed
2430 if (isCluster) {
2431 // The focus has changed even by a user click or programatically
2432 if (updatedFocus) {
2433 // We only have to update the location if it was changed programatically, because it was
2434 // changed by a user drag the marker data has already been updated by the internal event
2435 // listened by the directive
2436 if (markerData.lat !== oldMarkerData.lat || markerData.lng !== oldMarkerData.lng) {
2437 layers.overlays[markerData.layer].removeLayer(marker);
2438 marker.setLatLng([markerData.lat, markerData.lng]);
2439 layers.overlays[markerData.layer].addLayer(marker);
2440 }
2441 } else {
2442 // The marker has possibly moved. It can be moved by a user drag (marker location and data are equal but old
2443 // data is diferent) or programatically (marker location and data are diferent)
2444 if (markerLatLng.lat !== markerData.lat || markerLatLng.lng !== markerData.lng) {
2445 // The marker was moved by a user drag
2446 layers.overlays[markerData.layer].removeLayer(marker);
2447 marker.setLatLng([markerData.lat, markerData.lng]);
2448 layers.overlays[markerData.layer].addLayer(marker);
2449 } else if (markerData.lat !== oldMarkerData.lat || markerData.lng !== oldMarkerData.lng) {
2450 // The marker was moved programatically
2451 layers.overlays[markerData.layer].removeLayer(marker);
2452 marker.setLatLng([markerData.lat, markerData.lng]);
2453 layers.overlays[markerData.layer].addLayer(marker);
2454 } else if (isObject(markerData.icon) && isObject(oldMarkerData.icon) && !angular.equals(markerData.icon, oldMarkerData.icon)) {
2455 layers.overlays[markerData.layer].removeLayer(marker);
2456 layers.overlays[markerData.layer].addLayer(marker);
2457 }
2458 }
2459 } else if (markerLatLng.lat !== markerData.lat || markerLatLng.lng !== markerData.lng) {
2460 marker.setLatLng([markerData.lat, markerData.lng]);
2461 }
2462 };
2463
2464 var _getLayerModels = function _getLayerModels(models, layerName) {
2465 if (!isDefined(models)) return;
2466 if (layerName) return models[layerName];
2467 return models;
2468 };
2469
2470 var _getModelFromModels = function _getModelFromModels(models, id, layerName) {
2471 if (!isDefined(models)) return;
2472 if (!id) {
2473 $log.error(errorHeader + 'marker id missing in getMarker');
2474 return;
2475 }
2476 if (layerName) return models[layerName][id];
2477
2478 return models[id];
2479 };
2480 return {
2481 resetMarkerGroup: _resetMarkerGroup,
2482
2483 resetMarkerGroups: _resetMarkerGroups,
2484
2485 resetUnusedMarkerGroups: _resetUnusedMarkerGroups,
2486
2487 deleteMarker: _deleteMarker,
2488
2489 manageOpenPopup: _manageOpenPopup,
2490
2491 manageOpenLabel: _manageOpenLabel,
2492
2493 createMarker: function createMarker(markerData) {
2494 if (!isDefined(markerData) || !geoHlp.validateCoords(markerData)) {
2495 $log.error(errorHeader + 'The marker definition is not valid.');
2496 return;
2497 }
2498 var coords = geoHlp.getCoords(markerData);
2499
2500 if (!isDefined(coords)) {
2501 $log.error(errorHeader + 'Unable to get coordinates from markerData.');
2502 return;
2503 }
2504
2505 var markerOptions = {
2506 icon: createLeafletIcon(markerData.icon),
2507 title: isDefined(markerData.title) ? markerData.title : '',
2508 draggable: isDefined(markerData.draggable) ? markerData.draggable : false,
2509 clickable: isDefined(markerData.clickable) ? markerData.clickable : true,
2510 riseOnHover: isDefined(markerData.riseOnHover) ? markerData.riseOnHover : false,
2511 zIndexOffset: isDefined(markerData.zIndexOffset) ? markerData.zIndexOffset : 0,
2512 iconAngle: isDefined(markerData.iconAngle) ? markerData.iconAngle : 0
2513 };
2514 // Add any other options not added above to markerOptions
2515 for (var markerDatum in markerData) {
2516 if (markerData.hasOwnProperty(markerDatum) && !markerOptions.hasOwnProperty(markerDatum)) {
2517 markerOptions[markerDatum] = markerData[markerDatum];
2518 }
2519 }
2520
2521 var marker = new L.marker(coords, markerOptions);
2522
2523 if (!isString(markerData.message)) {
2524 marker.unbindPopup();
2525 }
2526
2527 return marker;
2528 },
2529
2530 addMarkerToGroup: function addMarkerToGroup(marker, groupName, groupOptions, map) {
2531 if (!isString(groupName)) {
2532 $log.error(errorHeader + 'The marker group you have specified is invalid.');
2533 return;
2534 }
2535
2536 if (!MarkerClusterPlugin.isLoaded()) {
2537 $log.error(errorHeader + "The MarkerCluster plugin is not loaded.");
2538 return;
2539 }
2540 if (!isDefined(groups[groupName])) {
2541 groups[groupName] = new L.MarkerClusterGroup(groupOptions);
2542 map.addLayer(groups[groupName]);
2543 }
2544 groups[groupName].addLayer(marker);
2545 },
2546
2547 listenMarkerEvents: function listenMarkerEvents(marker, markerData, leafletScope, watchType, map) {
2548 marker.on("popupopen", function () /* event */{
2549 safeApply(leafletScope, function () {
2550 if (isDefined(marker._popup) || isDefined(marker._popup._contentNode)) {
2551 markerData.focus = true;
2552 _manageOpenPopup(marker, markerData, map); //needed since markerData is now a copy
2553 }
2554 });
2555 });
2556 marker.on("popupclose", function () /* event */{
2557 safeApply(leafletScope, function () {
2558 markerData.focus = false;
2559 });
2560 });
2561 marker.on("add", function () /* event */{
2562 safeApply(leafletScope, function () {
2563 if ('label' in markerData) _manageOpenLabel(marker, markerData);
2564 });
2565 });
2566 },
2567
2568 updateMarker: _updateMarker,
2569
2570 addMarkerWatcher: function addMarkerWatcher(marker, name, leafletScope, layers, map, watchOptions) {
2571 var markerWatchPath = Helpers.getObjectArrayPath("markers." + name);
2572
2573 maybeWatch(leafletScope, markerWatchPath, watchOptions, function (markerData, oldMarkerData, clearWatch) {
2574 if (!isDefined(markerData)) {
2575 _deleteMarker(marker, map, layers);
2576 clearWatch();
2577 return;
2578 }
2579 _updateMarker(markerData, oldMarkerData, marker, name, leafletScope, layers, map);
2580 });
2581 },
2582 string: _string,
2583 log: _log,
2584 getModelFromModels: _getModelFromModels,
2585 getLayerModels: _getLayerModels
2586 };
2587}]);
2588
2589'use strict';
2590
2591angular.module('ui-leaflet').factory('leafletPathsHelpers', ["$rootScope", "leafletLogger", "leafletHelpers", function ($rootScope, leafletLogger, leafletHelpers) {
2592 var isDefined = leafletHelpers.isDefined,
2593 isArray = leafletHelpers.isArray,
2594 isNumber = leafletHelpers.isNumber,
2595 isValidPoint = leafletHelpers.isValidPoint,
2596 $log = leafletLogger;
2597
2598 var availableOptions = [
2599 // Path options
2600 'stroke', 'weight', 'color', 'opacity', 'fill', 'fillColor', 'fillOpacity', 'dashArray', 'lineCap', 'lineJoin', 'clickable', 'pointerEvents', 'className',
2601
2602 // Polyline options
2603 'smoothFactor', 'noClip'];
2604 function _convertToLeafletLatLngs(latlngs) {
2605 return latlngs.filter(function (latlng) {
2606 return isValidPoint(latlng);
2607 }).map(function (latlng) {
2608 return _convertToLeafletLatLng(latlng);
2609 });
2610 }
2611
2612 function _convertToLeafletLatLng(latlng) {
2613 if (isArray(latlng)) {
2614 return new L.LatLng(latlng[0], latlng[1]);
2615 } else {
2616 return new L.LatLng(latlng.lat, latlng.lng);
2617 }
2618 }
2619
2620 function _convertToLeafletMultiLatLngs(paths) {
2621 return paths.map(function (latlngs) {
2622 return _convertToLeafletLatLngs(latlngs);
2623 });
2624 }
2625
2626 function _getOptions(path, defaults) {
2627 var options = {};
2628 for (var i = 0; i < availableOptions.length; i++) {
2629 var optionName = availableOptions[i];
2630
2631 if (isDefined(path[optionName])) {
2632 options[optionName] = path[optionName];
2633 } else if (isDefined(defaults.path[optionName])) {
2634 options[optionName] = defaults.path[optionName];
2635 }
2636 }
2637
2638 return options;
2639 }
2640
2641 var _updatePathOptions = function _updatePathOptions(path, data) {
2642 var updatedStyle = {};
2643 for (var i = 0; i < availableOptions.length; i++) {
2644 var optionName = availableOptions[i];
2645 if (isDefined(data[optionName])) {
2646 updatedStyle[optionName] = data[optionName];
2647 }
2648 }
2649 path.setStyle(data);
2650 };
2651
2652 var _isValidPolyline = function _isValidPolyline(latlngs) {
2653 if (!isArray(latlngs)) {
2654 return false;
2655 }
2656 for (var i = 0; i < latlngs.length; i++) {
2657 var point = latlngs[i];
2658 if (!isValidPoint(point)) {
2659 return false;
2660 }
2661 }
2662 return true;
2663 };
2664
2665 var pathTypes = {
2666 polyline: {
2667 isValid: function isValid(pathData) {
2668 var latlngs = pathData.latlngs;
2669 return _isValidPolyline(latlngs);
2670 },
2671 createPath: function createPath(options) {
2672 return new L.Polyline([], options);
2673 },
2674 setPath: function setPath(path, data) {
2675 path.setLatLngs(_convertToLeafletLatLngs(data.latlngs));
2676 _updatePathOptions(path, data);
2677 return;
2678 }
2679 },
2680 multiPolyline: {
2681 isValid: function isValid(pathData) {
2682 var latlngs = pathData.latlngs;
2683 if (!isArray(latlngs)) {
2684 return false;
2685 }
2686
2687 for (var i in latlngs) {
2688 var polyline = latlngs[i];
2689 if (!_isValidPolyline(polyline)) {
2690 return false;
2691 }
2692 }
2693
2694 return true;
2695 },
2696 createPath: function createPath(options) {
2697 return new L.multiPolyline([[[0, 0], [1, 1]]], options);
2698 },
2699 setPath: function setPath(path, data) {
2700 path.setLatLngs(_convertToLeafletMultiLatLngs(data.latlngs));
2701 _updatePathOptions(path, data);
2702 return;
2703 }
2704 },
2705 polygon: {
2706 isValid: function isValid(pathData) {
2707 var latlngs = pathData.latlngs;
2708 return _isValidPolyline(latlngs);
2709 },
2710 createPath: function createPath(options) {
2711 return new L.Polygon([], options);
2712 },
2713 setPath: function setPath(path, data) {
2714 path.setLatLngs(_convertToLeafletLatLngs(data.latlngs));
2715 _updatePathOptions(path, data);
2716 return;
2717 }
2718 },
2719 multiPolygon: {
2720 isValid: function isValid(pathData) {
2721 var latlngs = pathData.latlngs;
2722
2723 if (!isArray(latlngs)) {
2724 return false;
2725 }
2726
2727 for (var i in latlngs) {
2728 var polyline = latlngs[i];
2729 if (!_isValidPolyline(polyline)) {
2730 return false;
2731 }
2732 }
2733
2734 return true;
2735 },
2736 createPath: function createPath(options) {
2737 return new L.MultiPolygon([[[0, 0], [1, 1], [0, 1]]], options);
2738 },
2739 setPath: function setPath(path, data) {
2740 path.setLatLngs(_convertToLeafletMultiLatLngs(data.latlngs));
2741 _updatePathOptions(path, data);
2742 return;
2743 }
2744 },
2745 rectangle: {
2746 isValid: function isValid(pathData) {
2747 var latlngs = pathData.latlngs;
2748
2749 if (!isArray(latlngs) || latlngs.length !== 2) {
2750 return false;
2751 }
2752
2753 for (var i in latlngs) {
2754 var point = latlngs[i];
2755 if (!isValidPoint(point)) {
2756 return false;
2757 }
2758 }
2759
2760 return true;
2761 },
2762 createPath: function createPath(options) {
2763 return new L.Rectangle([[0, 0], [1, 1]], options);
2764 },
2765 setPath: function setPath(path, data) {
2766 path.setBounds(new L.LatLngBounds(_convertToLeafletLatLngs(data.latlngs)));
2767 _updatePathOptions(path, data);
2768 }
2769 },
2770 circle: {
2771 isValid: function isValid(pathData) {
2772 var point = pathData.latlngs;
2773 return isValidPoint(point) && isNumber(pathData.radius);
2774 },
2775 createPath: function createPath(options) {
2776 return new L.Circle([0, 0], 1, options);
2777 },
2778 setPath: function setPath(path, data) {
2779 path.setLatLng(_convertToLeafletLatLng(data.latlngs));
2780 if (isDefined(data.radius)) {
2781 path.setRadius(data.radius);
2782 }
2783 _updatePathOptions(path, data);
2784 }
2785 },
2786 circleMarker: {
2787 isValid: function isValid(pathData) {
2788 var point = pathData.latlngs;
2789 return isValidPoint(point) && isNumber(pathData.radius);
2790 },
2791 createPath: function createPath(options) {
2792 return new L.CircleMarker([0, 0], options);
2793 },
2794 setPath: function setPath(path, data) {
2795 path.setLatLng(_convertToLeafletLatLng(data.latlngs));
2796 if (isDefined(data.radius)) {
2797 path.setRadius(data.radius);
2798 }
2799 _updatePathOptions(path, data);
2800 }
2801 }
2802 };
2803
2804 var _getPathData = function _getPathData(path) {
2805 var pathData = {};
2806 if (path.latlngs) {
2807 pathData.latlngs = path.latlngs;
2808 }
2809
2810 if (path.radius) {
2811 pathData.radius = path.radius;
2812 }
2813
2814 return pathData;
2815 };
2816
2817 return {
2818 setPathOptions: function setPathOptions(leafletPath, pathType, data) {
2819 if (!isDefined(pathType)) {
2820 pathType = "polyline";
2821 }
2822 pathTypes[pathType].setPath(leafletPath, data);
2823 },
2824 createPath: function createPath(name, path, defaults) {
2825 if (!isDefined(path.type)) {
2826 path.type = "polyline";
2827 }
2828 var options = _getOptions(path, defaults);
2829 var pathData = _getPathData(path);
2830
2831 if (!pathTypes[path.type].isValid(pathData)) {
2832 $log.error("[AngularJS - Leaflet] Invalid data passed to the " + path.type + " path");
2833 return;
2834 }
2835
2836 return pathTypes[path.type].createPath(options);
2837 }
2838 };
2839}]);
2840
2841'use strict';
2842
2843angular.module('ui-leaflet').service('leafletWatchHelpers', function () {
2844
2845 var _maybe = function _maybe(scope, watchFunctionName, thingToWatchStr, watchOptions, initCb) {
2846 var unWatch = scope[watchFunctionName](thingToWatchStr, function (newValue, oldValue) {
2847 //make the unWatch function available to the callback as well.
2848 initCb(newValue, oldValue, unWatch);
2849 if (watchOptions.type === null) unWatch();
2850 }, watchOptions.type === 'watchDeep');
2851
2852 return unWatch;
2853 };
2854
2855 /*
2856 @name: maybeWatch
2857 @description: Utility to watch something once or forever.
2858 @returns unWatch function
2859 @param watchOptions - This object is used to determine the type of
2860 watch used.
2861 */
2862 var _maybeWatch = function _maybeWatch(scope, thingToWatchStr, watchOptions, initCb) {
2863 var watchMethod;
2864
2865 if (watchOptions.type === 'watchCollection') {
2866 watchMethod = '$watchCollection';
2867 } else {
2868 watchMethod = '$watch';
2869 }
2870
2871 return _maybe(scope, watchMethod, thingToWatchStr, watchOptions, initCb);
2872 };
2873
2874 return {
2875 maybeWatch: _maybeWatch
2876 };
2877});
2878
2879'use strict';
2880
2881angular.module('ui-leaflet').service('leafletLogger', ["nemSimpleLogger", function (nemSimpleLogger) {
2882 return nemSimpleLogger.spawn();
2883}]);
2884
2885'use strict';
2886
2887angular.module('ui-leaflet').factory('nominatimService', ["$q", "$http", "leafletHelpers", "leafletMapDefaults", function ($q, $http, leafletHelpers, leafletMapDefaults) {
2888 var isDefined = leafletHelpers.isDefined;
2889
2890 return {
2891 query: function query(address, mapId) {
2892 var defaults = leafletMapDefaults.getDefaults(mapId);
2893 var url = defaults.nominatim.server;
2894 var df = $q.defer();
2895
2896 $http.get(url, { params: { format: 'json', limit: 1, q: address } }).success(function (data) {
2897 if (data.length > 0 && isDefined(data[0].boundingbox)) {
2898 df.resolve(data[0]);
2899 } else {
2900 df.reject('[Nominatim] Invalid address');
2901 }
2902 });
2903
2904 return df.promise;
2905 }
2906 };
2907}]);
2908
2909'use strict';
2910
2911angular.module('ui-leaflet').directive('bounds', ["leafletLogger", "$timeout", "$http", "leafletHelpers", "nominatimService", "leafletBoundsHelpers", function (leafletLogger, $timeout, $http, leafletHelpers, nominatimService, leafletBoundsHelpers) {
2912 var $log = leafletLogger;
2913 return {
2914 restrict: "A",
2915 scope: false,
2916 replace: false,
2917 require: ['leaflet'],
2918
2919 link: function link(scope, element, attrs, controller) {
2920 var isDefined = leafletHelpers.isDefined;
2921 var createLeafletBounds = leafletBoundsHelpers.createLeafletBounds;
2922 var leafletScope = controller[0].getLeafletScope();
2923 var mapController = controller[0];
2924 var errorHeader = leafletHelpers.errorHeader + ' [Bounds] ';
2925
2926 var emptyBounds = function emptyBounds(bounds) {
2927 return bounds._southWest.lat === 0 && bounds._southWest.lng === 0 && bounds._northEast.lat === 0 && bounds._northEast.lng === 0;
2928 };
2929
2930 mapController.getMap().then(function (map) {
2931 leafletScope.$on('boundsChanged', function (event) {
2932 var scope = event.currentScope;
2933 var bounds = map.getBounds();
2934
2935 if (emptyBounds(bounds) || scope.settingBoundsFromScope) {
2936 return;
2937 }
2938 scope.settingBoundsFromLeaflet = true;
2939 var newScopeBounds = {
2940 northEast: {
2941 lat: bounds._northEast.lat,
2942 lng: bounds._northEast.lng
2943 },
2944 southWest: {
2945 lat: bounds._southWest.lat,
2946 lng: bounds._southWest.lng
2947 },
2948 options: bounds.options
2949 };
2950 if (!angular.equals(scope.bounds, newScopeBounds)) {
2951 scope.bounds = newScopeBounds;
2952 }
2953 $timeout(function () {
2954 scope.settingBoundsFromLeaflet = false;
2955 });
2956 });
2957
2958 var lastNominatimQuery;
2959 leafletScope.$watch('bounds', function (bounds) {
2960 if (scope.settingBoundsFromLeaflet) return;
2961 if (isDefined(bounds.address) && bounds.address !== lastNominatimQuery) {
2962 scope.settingBoundsFromScope = true;
2963 nominatimService.query(bounds.address, attrs.id).then(function (data) {
2964 var b = data.boundingbox;
2965 var newBounds = [[b[0], b[2]], [b[1], b[3]]];
2966 map.fitBounds(newBounds);
2967 }, function (errMsg) {
2968 $log.error(errorHeader + ' ' + errMsg + '.');
2969 });
2970 lastNominatimQuery = bounds.address;
2971 $timeout(function () {
2972 scope.settingBoundsFromScope = false;
2973 });
2974 return;
2975 }
2976
2977 var leafletBounds = createLeafletBounds(bounds);
2978 if (leafletBounds && !map.getBounds().equals(leafletBounds)) {
2979 scope.settingBoundsFromScope = true;
2980 map.fitBounds(leafletBounds, bounds.options);
2981 $timeout(function () {
2982 scope.settingBoundsFromScope = false;
2983 });
2984 }
2985 }, true);
2986 });
2987 }
2988 };
2989}]);
2990
2991'use strict';
2992
2993var centerDirectiveTypes = ['center', 'lfCenter'],
2994 centerDirectives = {};
2995
2996centerDirectiveTypes.forEach(function (directiveName) {
2997 centerDirectives[directiveName] = ['leafletLogger', '$q', '$location', '$timeout', 'leafletMapDefaults', 'leafletHelpers', 'leafletBoundsHelpers', 'leafletMapEvents', function (leafletLogger, $q, $location, $timeout, leafletMapDefaults, leafletHelpers, leafletBoundsHelpers, leafletMapEvents) {
2998
2999 var isDefined = leafletHelpers.isDefined,
3000 isNumber = leafletHelpers.isNumber,
3001 isSameCenterOnMap = leafletHelpers.isSameCenterOnMap,
3002 safeApply = leafletHelpers.safeApply,
3003 isValidCenter = leafletHelpers.isValidCenter,
3004 isValidBounds = leafletBoundsHelpers.isValidBounds,
3005 isUndefinedOrEmpty = leafletHelpers.isUndefinedOrEmpty,
3006 errorHeader = leafletHelpers.errorHeader,
3007 $log = leafletLogger;
3008
3009 var shouldInitializeMapWithBounds = function shouldInitializeMapWithBounds(bounds, center) {
3010 return isDefined(bounds) && isValidBounds(bounds) && isUndefinedOrEmpty(center);
3011 };
3012
3013 var _leafletCenter;
3014 return {
3015 restrict: "A",
3016 scope: false,
3017 replace: false,
3018 require: 'leaflet',
3019 controller: function controller() {
3020 _leafletCenter = $q.defer();
3021 this.getCenter = function () {
3022 return _leafletCenter.promise;
3023 };
3024 },
3025 link: function link(scope, element, attrs, controller) {
3026 var leafletScope = controller.getLeafletScope(),
3027 centerModel = leafletScope[directiveName];
3028
3029 controller.getMap().then(function (map) {
3030 var defaults = leafletMapDefaults.getDefaults(attrs.id);
3031
3032 if (attrs[directiveName].search("-") !== -1) {
3033 $log.error(errorHeader + ' The "center" variable can\'t use a "-" on its key name: "' + attrs[directiveName] + '".');
3034 map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3035 return;
3036 } else if (shouldInitializeMapWithBounds(leafletScope.bounds, centerModel)) {
3037 map.fitBounds(leafletBoundsHelpers.createLeafletBounds(leafletScope.bounds), leafletScope.bounds.options);
3038 centerModel = map.getCenter();
3039 safeApply(leafletScope, function (scope) {
3040 angular.extend(scope[directiveName], {
3041 lat: map.getCenter().lat,
3042 lng: map.getCenter().lng,
3043 zoom: map.getZoom(),
3044 autoDiscover: false
3045 });
3046 });
3047 safeApply(leafletScope, function (scope) {
3048 var mapBounds = map.getBounds();
3049 scope.bounds = {
3050 northEast: {
3051 lat: mapBounds._northEast.lat,
3052 lng: mapBounds._northEast.lng
3053 },
3054 southWest: {
3055 lat: mapBounds._southWest.lat,
3056 lng: mapBounds._southWest.lng
3057 }
3058 };
3059 });
3060 } else if (!isDefined(centerModel)) {
3061 $log.error(errorHeader + ' The "center" property is not defined in the main scope');
3062 map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3063 return;
3064 } else if (!(isDefined(centerModel.lat) && isDefined(centerModel.lng)) && !isDefined(centerModel.autoDiscover)) {
3065 angular.copy(defaults.center, centerModel);
3066 }
3067
3068 var urlCenterHash, mapReady;
3069 if (attrs.urlHashCenter === "yes") {
3070 var extractCenterFromUrl = function extractCenterFromUrl() {
3071 var search = $location.search();
3072 var centerParam;
3073 var centerKey = attrs.urlHashParam ? attrs.urlHashParam : 'c';
3074 if (isDefined(search[centerKey])) {
3075 var cParam = search[centerKey].split(":");
3076 if (cParam.length === 3) {
3077 centerParam = {
3078 lat: parseFloat(cParam[0]),
3079 lng: parseFloat(cParam[1]),
3080 zoom: parseInt(cParam[2], 10)
3081 };
3082 }
3083 }
3084 return centerParam;
3085 };
3086 urlCenterHash = extractCenterFromUrl();
3087
3088 leafletScope.$on('$locationChangeSuccess', function (event) {
3089 var scope = event.currentScope;
3090 //$log.debug("updated location...");
3091 var urlCenter = extractCenterFromUrl();
3092 if (isDefined(urlCenter) && !isSameCenterOnMap(urlCenter, map)) {
3093 //$log.debug("updating center model...", urlCenter);
3094 angular.extend(scope[directiveName], {
3095 lat: urlCenter.lat,
3096 lng: urlCenter.lng,
3097 zoom: urlCenter.zoom
3098 });
3099 }
3100 });
3101 }
3102
3103 leafletScope.$watch(directiveName, function (center) {
3104 if (leafletScope.settingCenterFromLeaflet) return;
3105 //$log.debug("updated center model...");
3106 // The center from the URL has priority
3107 if (isDefined(urlCenterHash)) {
3108 angular.copy(urlCenterHash, center);
3109 urlCenterHash = undefined;
3110 }
3111
3112 if (!isValidCenter(center) && center.autoDiscover !== true) {
3113 $log.warn(errorHeader + " invalid 'center'");
3114 //map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3115 return;
3116 }
3117
3118 if (center.autoDiscover === true) {
3119 if (!isNumber(center.zoom)) {
3120 map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3121 }
3122 if (isNumber(center.zoom) && center.zoom > defaults.center.zoom) {
3123 map.locate({
3124 setView: true,
3125 maxZoom: center.zoom
3126 });
3127 } else if (isDefined(defaults.maxZoom)) {
3128 map.locate({
3129 setView: true,
3130 maxZoom: defaults.maxZoom
3131 });
3132 } else {
3133 map.locate({
3134 setView: true
3135 });
3136 }
3137 return;
3138 }
3139
3140 if (mapReady && isSameCenterOnMap(center, map)) {
3141 //$log.debug("no need to update map again.");
3142 return;
3143 }
3144
3145 //$log.debug("updating map center...", center);
3146 leafletScope.settingCenterFromScope = true;
3147 map.setView([center.lat, center.lng], center.zoom);
3148 leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3149 $timeout(function () {
3150 leafletScope.settingCenterFromScope = false;
3151 //$log.debug("allow center scope updates");
3152 });
3153 }, true);
3154
3155 map.whenReady(function () {
3156 mapReady = true;
3157 });
3158
3159 map.on('moveend', function () /* event */{
3160 // Resolve the center after the first map position
3161 _leafletCenter.resolve();
3162 leafletMapEvents.notifyCenterUrlHashChanged(leafletScope, map, attrs, $location.search());
3163 //$log.debug("updated center on map...");
3164 if (isSameCenterOnMap(centerModel, map) || leafletScope.settingCenterFromScope) {
3165 //$log.debug("same center in model, no need to update again.");
3166 return;
3167 }
3168 leafletScope.settingCenterFromLeaflet = true;
3169 safeApply(leafletScope, function (scope) {
3170 if (!leafletScope.settingCenterFromScope) {
3171 //$log.debug("updating center model...", map.getCenter(), map.getZoom());
3172 angular.extend(scope[directiveName], {
3173 lat: map.getCenter().lat,
3174 lng: map.getCenter().lng,
3175 zoom: map.getZoom(),
3176 autoDiscover: false
3177 });
3178 }
3179 leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3180 $timeout(function () {
3181 leafletScope.settingCenterFromLeaflet = false;
3182 });
3183 });
3184 });
3185
3186 if (centerModel.autoDiscover === true) {
3187 map.on('locationerror', function () {
3188 $log.warn(errorHeader + " The Geolocation API is unauthorized on this page.");
3189 if (isValidCenter(centerModel)) {
3190 map.setView([centerModel.lat, centerModel.lng], centerModel.zoom);
3191 leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3192 } else {
3193 map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3194 leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3195 }
3196 });
3197 }
3198 });
3199 }
3200 };
3201 }];
3202});
3203
3204centerDirectiveTypes.forEach(function (dirType) {
3205 angular.module('ui-leaflet').directive(dirType, centerDirectives[dirType]);
3206});
3207
3208'use strict';
3209
3210angular.module('ui-leaflet').directive('controls', ["leafletLogger", "leafletHelpers", "leafletControlHelpers", function (leafletLogger, leafletHelpers, leafletControlHelpers) {
3211 var $log = leafletLogger;
3212 return {
3213 restrict: "A",
3214 scope: false,
3215 replace: false,
3216 require: '?^leaflet',
3217
3218 link: function link(scope, element, attrs, controller) {
3219 if (!controller) {
3220 return;
3221 }
3222
3223 var createControl = leafletControlHelpers.createControl;
3224 var isValidControlType = leafletControlHelpers.isValidControlType;
3225 var leafletScope = controller.getLeafletScope();
3226 var isDefined = leafletHelpers.isDefined;
3227 var isArray = leafletHelpers.isArray;
3228 var leafletControls = {};
3229 var errorHeader = leafletHelpers.errorHeader + ' [Controls] ';
3230
3231 scope.$on('$destroy', function () {
3232 leafletControlHelpers.destroyMapLayersControl(scope.mapId);
3233 });
3234
3235 controller.getMap().then(function (map) {
3236
3237 leafletScope.$watchCollection('controls', function (newControls) {
3238
3239 // Delete controls from the array
3240 for (var name in leafletControls) {
3241 if (!isDefined(newControls[name])) {
3242 if (map.hasControl(leafletControls[name])) {
3243 map.removeControl(leafletControls[name]);
3244 }
3245 delete leafletControls[name];
3246 }
3247 }
3248
3249 for (var newName in newControls) {
3250 var control;
3251
3252 var controlType = isDefined(newControls[newName].type) ? newControls[newName].type : newName;
3253
3254 if (!isValidControlType(controlType)) {
3255 $log.error(errorHeader + ' Invalid control type: ' + controlType + '.');
3256 return;
3257 }
3258
3259 if (controlType !== 'custom') {
3260 control = createControl(controlType, newControls[newName]);
3261 map.addControl(control);
3262 leafletControls[newName] = control;
3263 } else {
3264 var customControlValue = newControls[newName];
3265 if (isArray(customControlValue)) {
3266 for (var i = 0; i < customControlValue.length; i++) {
3267 var customControl = customControlValue[i];
3268 map.addControl(customControl);
3269 leafletControls[newName] = !isDefined(leafletControls[newName]) ? [customControl] : leafletControls[newName].concat([customControl]);
3270 }
3271 } else {
3272 map.addControl(customControlValue);
3273 leafletControls[newName] = customControlValue;
3274 }
3275 }
3276 }
3277 });
3278 });
3279 }
3280 };
3281}]);
3282
3283"use strict";
3284
3285angular.module('ui-leaflet').directive("decorations", ["leafletLogger", "leafletHelpers", function (leafletLogger, leafletHelpers) {
3286 var $log = leafletLogger;
3287 return {
3288 restrict: "A",
3289 scope: false,
3290 replace: false,
3291 require: 'leaflet',
3292
3293 link: function link(scope, element, attrs, controller) {
3294 var leafletScope = controller.getLeafletScope(),
3295 PolylineDecoratorPlugin = leafletHelpers.PolylineDecoratorPlugin,
3296 isDefined = leafletHelpers.isDefined,
3297 leafletDecorations = {};
3298
3299 /* Creates an "empty" decoration with a set of coordinates, but no pattern. */
3300 function createDecoration(options) {
3301 if (isDefined(options) && isDefined(options.coordinates)) {
3302 if (!PolylineDecoratorPlugin.isLoaded()) {
3303 $log.error('[AngularJS - Leaflet] The PolylineDecorator Plugin is not loaded.');
3304 }
3305 }
3306
3307 return L.polylineDecorator(options.coordinates);
3308 }
3309
3310 /* Updates the path and the patterns for the provided decoration, and returns the decoration. */
3311 function setDecorationOptions(decoration, options) {
3312 if (isDefined(decoration) && isDefined(options)) {
3313 if (isDefined(options.coordinates) && isDefined(options.patterns)) {
3314 decoration.setPaths(options.coordinates);
3315 decoration.setPatterns(options.patterns);
3316 return decoration;
3317 }
3318 }
3319 }
3320
3321 controller.getMap().then(function (map) {
3322 leafletScope.$watch("decorations", function (newDecorations) {
3323 for (var name in leafletDecorations) {
3324 if (!isDefined(newDecorations[name]) || !angular.equals(newDecorations[name], leafletDecorations)) {
3325 map.removeLayer(leafletDecorations[name]);
3326 delete leafletDecorations[name];
3327 }
3328 }
3329
3330 for (var newName in newDecorations) {
3331 var decorationData = newDecorations[newName],
3332 newDecoration = createDecoration(decorationData);
3333
3334 if (isDefined(newDecoration)) {
3335 leafletDecorations[newName] = newDecoration;
3336 map.addLayer(newDecoration);
3337 setDecorationOptions(newDecoration, decorationData);
3338 }
3339 }
3340 }, true);
3341 });
3342 }
3343 };
3344}]);
3345
3346'use strict';
3347
3348angular.module('ui-leaflet').directive('eventBroadcast', ["leafletLogger", "$rootScope", "leafletHelpers", "leafletMapEvents", "leafletIterators", function (leafletLogger, $rootScope, leafletHelpers, leafletMapEvents, leafletIterators) {
3349 var $log = leafletLogger;
3350 return {
3351 restrict: "A",
3352 scope: false,
3353 replace: false,
3354 require: 'leaflet',
3355
3356 link: function link(scope, element, attrs, controller) {
3357 var isObject = leafletHelpers.isObject,
3358 isDefined = leafletHelpers.isDefined,
3359 leafletScope = controller.getLeafletScope(),
3360 eventBroadcast = leafletScope.eventBroadcast,
3361 availableMapEvents = leafletMapEvents.getAvailableMapEvents(),
3362 addEvents = leafletMapEvents.addEvents;
3363
3364 controller.getMap().then(function (map) {
3365
3366 var mapEvents = [],
3367 logic = "broadcast";
3368
3369 // We have a possible valid object
3370 if (!isDefined(eventBroadcast.map)) {
3371 // We do not have events enable/disable do we do nothing (all enabled by default)
3372 mapEvents = availableMapEvents;
3373 } else if (!isObject(eventBroadcast.map)) {
3374 // Not a valid object
3375 $log.warn("[AngularJS - Leaflet] event-broadcast.map must be an object check your model.");
3376 } else {
3377 // We have a possible valid map object
3378 // Event propadation logic
3379 if (eventBroadcast.map.logic !== "emit" && eventBroadcast.map.logic !== "broadcast") {
3380 // This is an error
3381 $log.warn("[AngularJS - Leaflet] Available event propagation logic are: 'emit' or 'broadcast'.");
3382 } else {
3383 logic = eventBroadcast.map.logic;
3384 }
3385
3386 if (!(isObject(eventBroadcast.map.enable) && eventBroadcast.map.enable.length >= 0)) {
3387 $log.warn("[AngularJS - Leaflet] event-broadcast.map.enable must be an object check your model.");
3388 } else {
3389 // Enable events
3390 leafletIterators.each(eventBroadcast.map.enable, function (eventName) {
3391 // Do we have already the event enabled?
3392 if (mapEvents.indexOf(eventName) === -1 && availableMapEvents.indexOf(eventName) !== -1) {
3393 mapEvents.push(eventName);
3394 }
3395 });
3396 }
3397 }
3398 // as long as the map is removed in the root leaflet directive we
3399 // do not need ot clean up the events as leaflet does it itself
3400 addEvents(map, attrs.id, mapEvents, "eventName", leafletScope, logic);
3401 });
3402 }
3403 };
3404}]);
3405
3406'use strict';
3407
3408angular.module('ui-leaflet').directive('geojson', ["$timeout", "leafletLogger", "leafletData", "leafletHelpers", "leafletWatchHelpers", "leafletDirectiveControlsHelpers", "leafletIterators", "leafletGeoJsonEvents", function ($timeout, leafletLogger, leafletData, leafletHelpers, leafletWatchHelpers, leafletDirectiveControlsHelpers, leafletIterators, leafletGeoJsonEvents) {
3409 var _maybeWatch = leafletWatchHelpers.maybeWatch,
3410 _defaultWatchOptions = leafletHelpers.watchOptions,
3411 _extendDirectiveControls = leafletDirectiveControlsHelpers.extend,
3412 hlp = leafletHelpers,
3413 $it = leafletIterators,
3414 watchTrap = { changeFromDirective: false };
3415 // $log = leafletLogger;
3416
3417 return {
3418 restrict: "A",
3419 scope: false,
3420 replace: false,
3421 require: 'leaflet',
3422
3423 link: function link(scope, element, attrs, controller) {
3424 var isDefined = leafletHelpers.isDefined,
3425 leafletScope = controller.getLeafletScope(),
3426 leafletGeoJSON = {},
3427 _hasSetLeafletData = false;
3428
3429 controller.getMap().then(function (map) {
3430 var watchOptions;
3431 if (leafletScope.watchOptions && leafletScope.watchOptions.geojson) {
3432 watchOptions = leafletScope.watchOptions.geojson;
3433 } else {
3434 watchOptions = _defaultWatchOptions;
3435 }
3436
3437 var _hookUpEvents = function _hookUpEvents(geojson, maybeName) {
3438 var onEachFeature;
3439
3440 if (angular.isFunction(geojson.onEachFeature)) {
3441 onEachFeature = geojson.onEachFeature;
3442 } else {
3443 onEachFeature = function onEachFeature(feature, layer) {
3444 if (leafletHelpers.LabelPlugin.isLoaded() && isDefined(feature.properties.description)) {
3445 layer.bindLabel(feature.properties.description);
3446 }
3447
3448 leafletGeoJsonEvents.bindEvents(attrs.id, layer, null, feature, leafletScope, maybeName, { resetStyleOnMouseout: geojson.resetStyleOnMouseout,
3449 mapId: attrs.id });
3450 };
3451 }
3452 return onEachFeature;
3453 };
3454
3455 var isNested = hlp.isDefined(attrs.geojsonNested) && hlp.isTruthy(attrs.geojsonNested);
3456
3457 var _clean = function _clean() {
3458 if (!leafletGeoJSON) return;
3459 var _remove = function _remove(lObject) {
3460 if (isDefined(lObject) && map.hasLayer(lObject)) {
3461 map.removeLayer(lObject);
3462 }
3463 };
3464 if (isNested) {
3465 $it.each(leafletGeoJSON, function (lObject) {
3466 _remove(lObject);
3467 });
3468 return;
3469 }
3470 _remove(leafletGeoJSON);
3471 };
3472
3473 var _addGeojson = function _addGeojson(geojson, maybeName) {
3474
3475 if (!(isDefined(geojson) && isDefined(geojson.data))) {
3476 return;
3477 }
3478 var onEachFeature = _hookUpEvents(geojson, maybeName);
3479
3480 if (!isDefined(geojson.options)) {
3481 hlp.modelChangeInDirective(watchTrap, "changeFromDirective", function () {
3482 geojson.options = {
3483 style: geojson.style,
3484 filter: geojson.filter,
3485 onEachFeature: onEachFeature,
3486 pointToLayer: geojson.pointToLayer
3487 };
3488 });
3489 }
3490
3491 var lObject = L.geoJson(geojson.data, geojson.options);
3492
3493 if (maybeName && hlp.isString(maybeName)) {
3494 leafletGeoJSON[maybeName] = lObject;
3495 } else {
3496 leafletGeoJSON = lObject;
3497 }
3498
3499 lObject.addTo(map);
3500
3501 if (!_hasSetLeafletData) {
3502 //only do this once and play with the same ref forever
3503 _hasSetLeafletData = true;
3504 leafletData.setGeoJSON(leafletGeoJSON, attrs.id);
3505 }
3506 };
3507
3508 var _create = function _create(model) {
3509 _clean();
3510 if (isNested) {
3511 if (!model || !Object.keys(model).length) return;
3512 $it.each(model, function (m, name) {
3513 //name could be layerName and or groupName
3514 //for now it is not tied to a layer
3515 _addGeojson(m, name);
3516 });
3517 return;
3518 }
3519 _addGeojson(model);
3520 };
3521
3522 _extendDirectiveControls(attrs.id, 'geojson', _create, _clean);
3523
3524 _maybeWatch(leafletScope, 'geojson', watchOptions, function (geojson) {
3525 if (watchTrap.changeFromDirective) return;
3526 _create(geojson);
3527 });
3528 });
3529 }
3530 };
3531}]);
3532
3533'use strict';
3534
3535angular.module('ui-leaflet').directive('layercontrol', ["$filter", "leafletLogger", "leafletData", "leafletHelpers", function ($filter, leafletLogger, leafletData, leafletHelpers) {
3536 var $log = leafletLogger;
3537 return {
3538 restrict: "E",
3539 scope: {
3540 icons: '=?',
3541 autoHideOpacity: '=?', // Hide other opacity controls when one is activated.
3542 showGroups: '=?', // Hide other opacity controls when one is activated.
3543 title: '@',
3544 baseTitle: '@',
3545 overlaysTitle: '@'
3546 },
3547 replace: true,
3548 transclude: false,
3549 require: '^leaflet',
3550 controller: ["$scope", "$element", "$sce", function controller($scope, $element, $sce) {
3551 $log.debug('[Angular Directive - Layers] layers', $scope, $element);
3552 var safeApply = leafletHelpers.safeApply,
3553 isDefined = leafletHelpers.isDefined;
3554 angular.extend($scope, {
3555 baselayer: '',
3556 oldGroup: '',
3557 layerProperties: {},
3558 groupProperties: {},
3559 rangeIsSupported: leafletHelpers.rangeIsSupported(),
3560 changeBaseLayer: function changeBaseLayer(key, e) {
3561 leafletHelpers.safeApply($scope, function (scp) {
3562 scp.baselayer = key;
3563 leafletData.getMap().then(function (map) {
3564 leafletData.getLayers().then(function (leafletLayers) {
3565 if (map.hasLayer(leafletLayers.baselayers[key])) {
3566 return;
3567 }
3568 for (var i in scp.layers.baselayers) {
3569 scp.layers.baselayers[i].icon = scp.icons.unradio;
3570 if (map.hasLayer(leafletLayers.baselayers[i])) {
3571 map.removeLayer(leafletLayers.baselayers[i]);
3572 }
3573 }
3574 map.addLayer(leafletLayers.baselayers[key]);
3575 scp.layers.baselayers[key].icon = $scope.icons.radio;
3576 });
3577 });
3578 });
3579 e.preventDefault();
3580 },
3581 moveLayer: function moveLayer(ly, newIndex, e) {
3582 var delta = Object.keys($scope.layers.baselayers).length;
3583 if (newIndex >= 1 + delta && newIndex <= $scope.overlaysArray.length + delta) {
3584 var oldLy;
3585 for (var key in $scope.layers.overlays) {
3586 if ($scope.layers.overlays[key].index === newIndex) {
3587 oldLy = $scope.layers.overlays[key];
3588 break;
3589 }
3590 }
3591 if (oldLy) {
3592 safeApply($scope, function () {
3593 oldLy.index = ly.index;
3594 ly.index = newIndex;
3595 });
3596 }
3597 }
3598 e.stopPropagation();
3599 e.preventDefault();
3600 },
3601 initIndex: function initIndex(layer, idx) {
3602 var delta = Object.keys($scope.layers.baselayers).length;
3603 layer.index = isDefined(layer.index) ? layer.index : idx + delta + 1;
3604 },
3605 initGroup: function initGroup(groupName) {
3606 $scope.groupProperties[groupName] = $scope.groupProperties[groupName] ? $scope.groupProperties[groupName] : {};
3607 },
3608 toggleOpacity: function toggleOpacity(e, layer) {
3609 if (layer.visible) {
3610 if ($scope.autoHideOpacity && !$scope.layerProperties[layer.name].opacityControl) {
3611 for (var k in $scope.layerProperties) {
3612 $scope.layerProperties[k].opacityControl = false;
3613 }
3614 }
3615 $scope.layerProperties[layer.name].opacityControl = !$scope.layerProperties[layer.name].opacityControl;
3616 }
3617 e.stopPropagation();
3618 e.preventDefault();
3619 },
3620 toggleLegend: function toggleLegend(layer) {
3621 $scope.layerProperties[layer.name].showLegend = !$scope.layerProperties[layer.name].showLegend;
3622 },
3623 showLegend: function showLegend(layer) {
3624 return layer.legend && $scope.layerProperties[layer.name].showLegend;
3625 },
3626 unsafeHTML: function unsafeHTML(html) {
3627 return $sce.trustAsHtml(html);
3628 },
3629 getOpacityIcon: function getOpacityIcon(layer) {
3630 return layer.visible && $scope.layerProperties[layer.name].opacityControl ? $scope.icons.close : $scope.icons.open;
3631 },
3632 getGroupIcon: function getGroupIcon(group) {
3633 return group.visible ? $scope.icons.check : $scope.icons.uncheck;
3634 },
3635 changeGroupVisibility: function changeGroupVisibility(groupName) {
3636 if (!isDefined($scope.groupProperties[groupName])) {
3637 return;
3638 }
3639 var visible = $scope.groupProperties[groupName].visible;
3640 for (var k in $scope.layers.overlays) {
3641 var layer = $scope.layers.overlays[k];
3642 if (layer.group === groupName) {
3643 layer.visible = visible;
3644 }
3645 }
3646 }
3647 });
3648
3649 var div = $element.get(0);
3650 if (!L.Browser.touch) {
3651 L.DomEvent.disableClickPropagation(div);
3652 L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
3653 } else {
3654 L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
3655 }
3656 }],
3657 template: '<div class="angular-leaflet-control-layers" ng-show="overlaysArray.length">' + '<h4 ng-if="title">{{ title }}</h4>' + '<div class="lf-baselayers">' + '<h5 class="lf-title" ng-if="baseTitle">{{ baseTitle }}</h5>' + '<div class="lf-row" ng-repeat="(key, layer) in baselayersArray">' + '<label class="lf-icon-bl" ng-click="changeBaseLayer(key, $event)">' + '<input class="leaflet-control-layers-selector" type="radio" name="lf-radio" ' + 'ng-show="false" ng-checked="baselayer === key" ng-value="key" /> ' + '<i class="lf-icon lf-icon-radio" ng-class="layer.icon"></i>' + '<div class="lf-text">{{layer.name}}</div>' + '</label>' + '</div>' + '</div>' + '<div class="lf-overlays">' + '<h5 class="lf-title" ng-if="overlaysTitle">{{ overlaysTitle }}</h5>' + '<div class="lf-container">' + '<div class="lf-row" ng-repeat="layer in (o = (overlaysArray | orderBy:\'index\':order))" ng-init="initIndex(layer, $index)">' + '<label class="lf-icon-ol-group" ng-if="showGroups && layer.group && layer.group != o[$index-1].group">' + '<input class="lf-control-layers-selector" type="checkbox" ng-show="false" ' + 'ng-change="changeGroupVisibility(layer.group)" ng-model="groupProperties[layer.group].visible"/> ' + '<i class="lf-icon lf-icon-check" ng-class="getGroupIcon(groupProperties[layer.group])"></i>' + '<div class="lf-text">{{ layer.group }}</div>' + '</label>' + '<label class="lf-icon-ol">' + '<input class="lf-control-layers-selector" type="checkbox" ng-show="false" ng-model="layer.visible"/> ' + '<i class="lf-icon lf-icon-check" ng-class="layer.icon"></i>' + '<div class="lf-text">{{layer.name}}</div>' + '</label>' + '<div class="lf-icons">' + '<i class="lf-icon lf-up" ng-class="icons.up" ng-click="moveLayer(layer, layer.index - orderNumber, $event)"></i> ' + '<i class="lf-icon lf-down" ng-class="icons.down" ng-click="moveLayer(layer, layer.index + orderNumber, $event)"></i> ' + '<i class="lf-icon lf-toggle-legend" ng-class="icons.toggleLegend" ng-if="layer.legend" ng-click="toggleLegend(layer)"></i> ' + '<i class="lf-icon lf-open" ng-class="getOpacityIcon(layer)" ng-click="toggleOpacity($event, layer)"></i>' + '</div>' + '<div class="lf-legend" ng-if="showLegend(layer)" ng-bind-html="unsafeHTML(layer.legend)"></div>' + '<div class="lf-opacity clearfix" ng-if="layer.visible && layerProperties[layer.name].opacityControl">' + '<label ng-if="rangeIsSupported" class="pull-left" style="width: 50%">0</label>' + '<label ng-if="rangeIsSupported" class="pull-left text-right" style="width: 50%">100</label>' + '<input ng-if="rangeIsSupported" class="clearfix" type="range" min="0" max="1" step="0.05" ' + 'class="lf-opacity-control" ng-model="layerProperties[layer.name].layerOptions.opacity"/>' + '<h6 ng-if="!rangeIsSupported">Range is not supported in this browser</h6>' + '</div>' + '</div>' + '</div>' + '</div>' + '</div>',
3658 link: function link(scope, element, attrs, controller) {
3659 var isDefined = leafletHelpers.isDefined,
3660 leafletScope = controller.getLeafletScope(),
3661 layers = leafletScope.layers;
3662
3663 scope.$watch('icons', function () {
3664 var defaultIcons = {
3665 uncheck: 'fa fa-square-o',
3666 check: 'fa fa-check-square-o',
3667 radio: 'fa fa-dot-circle-o',
3668 unradio: 'fa fa-circle-o',
3669 up: 'fa fa-angle-up',
3670 down: 'fa fa-angle-down',
3671 open: 'fa fa-angle-double-down',
3672 close: 'fa fa-angle-double-up',
3673 toggleLegend: 'fa fa-pencil-square-o'
3674 };
3675 if (isDefined(scope.icons)) {
3676 angular.extend(defaultIcons, scope.icons);
3677 angular.extend(scope.icons, defaultIcons);
3678 } else {
3679 scope.icons = defaultIcons;
3680 }
3681 });
3682
3683 // Setting layer stack order.
3684 attrs.order = isDefined(attrs.order) && (attrs.order === 'normal' || attrs.order === 'reverse') ? attrs.order : 'normal';
3685 scope.order = attrs.order === 'normal';
3686 scope.orderNumber = attrs.order === 'normal' ? -1 : 1;
3687
3688 scope.layers = layers;
3689 controller.getMap().then(function (map) {
3690 leafletScope.$watch('layers.baselayers', function (newBaseLayers) {
3691 var baselayersArray = {};
3692 leafletData.getLayers().then(function (leafletLayers) {
3693 var key;
3694 for (key in newBaseLayers) {
3695 var layer = newBaseLayers[key];
3696 layer.icon = scope.icons[map.hasLayer(leafletLayers.baselayers[key]) ? 'radio' : 'unradio'];
3697 baselayersArray[key] = layer;
3698 }
3699 scope.baselayersArray = baselayersArray;
3700 });
3701 });
3702
3703 leafletScope.$watch('layers.overlays', function (newOverlayLayers) {
3704 var overlaysArray = [];
3705 var groupVisibleCount = {};
3706 leafletData.getLayers().then(function () {
3707 var key;
3708 for (key in newOverlayLayers) {
3709 var layer = newOverlayLayers[key];
3710 layer.icon = scope.icons[layer.visible ? 'check' : 'uncheck'];
3711 overlaysArray.push(layer);
3712
3713 if (!isDefined(scope.layerProperties[layer.name])) {
3714 if (isDefined(layer.layerOptions.opacity)) {
3715 layer.layerOptions.opacity = 1;
3716 }
3717 scope.layerProperties[layer.name] = {
3718 opacityControl: false,
3719 showLegend: true,
3720 layerOptions: layer.layerOptions
3721 };
3722 }
3723 if (isDefined(layer.group)) {
3724 if (!isDefined(scope.groupProperties[layer.group])) {
3725 scope.groupProperties[layer.group] = {
3726 visible: false
3727 };
3728 }
3729 groupVisibleCount[layer.group] = isDefined(groupVisibleCount[layer.group]) ? groupVisibleCount[layer.group] : {
3730 count: 0,
3731 visibles: 0
3732 };
3733 groupVisibleCount[layer.group].count++;
3734 if (layer.visible) {
3735 groupVisibleCount[layer.group].visibles++;
3736 }
3737 }
3738 /*
3739 if(isDefined(layer.index) && leafletLayers.overlays[key].setZIndex) {
3740 leafletLayers.overlays[key].setZIndex(newOverlayLayers[key].index);
3741 }
3742 */
3743 }
3744
3745 for (key in groupVisibleCount) {
3746 scope.groupProperties[key].visible = groupVisibleCount[key].visibles === groupVisibleCount[key].count;
3747 }
3748 scope.overlaysArray = overlaysArray;
3749 });
3750 }, true);
3751 });
3752 }
3753 };
3754}]);
3755
3756'use strict';
3757
3758angular.module('ui-leaflet').directive('layers', ["leafletLogger", "$q", "leafletData", "leafletHelpers", "leafletLayerHelpers", "leafletControlHelpers", function (leafletLogger, $q, leafletData, leafletHelpers, leafletLayerHelpers, leafletControlHelpers) {
3759 // var $log = leafletLogger;
3760 return {
3761 restrict: "A",
3762 scope: false,
3763 replace: false,
3764 require: 'leaflet',
3765 controller: ["$scope", function controller($scope) {
3766 $scope._leafletLayers = $q.defer();
3767 this.getLayers = function () {
3768 return $scope._leafletLayers.promise;
3769 };
3770 }],
3771 link: function link(scope, element, attrs, controller) {
3772 var isDefined = leafletHelpers.isDefined,
3773 leafletLayers = {},
3774 leafletScope = controller.getLeafletScope(),
3775 layers = leafletScope.layers,
3776 createLayer = leafletLayerHelpers.createLayer,
3777 safeAddLayer = leafletLayerHelpers.safeAddLayer,
3778 safeRemoveLayer = leafletLayerHelpers.safeRemoveLayer,
3779 changeOpacityListener = leafletLayerHelpers.changeOpacityListener,
3780 updateLayersControl = leafletControlHelpers.updateLayersControl,
3781 isLayersControlVisible = false;
3782
3783 scope.$on('$destroy', function () {
3784 leafletControlHelpers.destroyMapLayersControl(scope.mapId);
3785 });
3786
3787 controller.getMap().then(function (map) {
3788
3789 // We have baselayers to add to the map
3790 scope._leafletLayers.resolve(leafletLayers);
3791 leafletData.setLayers(leafletLayers, attrs.id);
3792
3793 leafletLayers.baselayers = {};
3794 leafletLayers.overlays = {};
3795
3796 var mapId = attrs.id;
3797
3798 // Setup all baselayers definitions
3799 var oneVisibleLayer = false;
3800 for (var layerName in layers.baselayers) {
3801 var newBaseLayer = createLayer(layers.baselayers[layerName]);
3802 if (!isDefined(newBaseLayer)) {
3803 delete layers.baselayers[layerName];
3804 continue;
3805 }
3806 leafletLayers.baselayers[layerName] = newBaseLayer;
3807 // Only add the visible layer to the map, layer control manages the addition to the map
3808 // of layers in its control
3809 if (layers.baselayers[layerName].top === true) {
3810 safeAddLayer(map, leafletLayers.baselayers[layerName]);
3811 oneVisibleLayer = true;
3812 }
3813 }
3814
3815 // If there is no visible layer add first to the map
3816 if (!oneVisibleLayer && Object.keys(leafletLayers.baselayers).length > 0) {
3817 safeAddLayer(map, leafletLayers.baselayers[Object.keys(layers.baselayers)[0]]);
3818 }
3819
3820 // Setup the Overlays
3821 for (layerName in layers.overlays) {
3822 if (layers.overlays[layerName].type === 'cartodb') {}
3823 var newOverlayLayer = createLayer(layers.overlays[layerName]);
3824 if (!isDefined(newOverlayLayer)) {
3825 delete layers.overlays[layerName];
3826 continue;
3827 }
3828 leafletLayers.overlays[layerName] = newOverlayLayer;
3829 // Only add the visible overlays to the map
3830 if (layers.overlays[layerName].visible === true) {
3831 safeAddLayer(map, leafletLayers.overlays[layerName]);
3832 }
3833 }
3834
3835 // Watch for the base layers
3836 leafletScope.$watch('layers.baselayers', function (newBaseLayers, oldBaseLayers) {
3837 if (angular.equals(newBaseLayers, oldBaseLayers)) {
3838 isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, newBaseLayers, layers.overlays, leafletLayers);
3839 return true;
3840 }
3841 // Delete layers from the array
3842 for (var name in leafletLayers.baselayers) {
3843 if (!isDefined(newBaseLayers[name]) || newBaseLayers[name].doRefresh) {
3844 // Remove from the map if it's on it
3845 if (map.hasLayer(leafletLayers.baselayers[name])) {
3846 map.removeLayer(leafletLayers.baselayers[name]);
3847 }
3848 delete leafletLayers.baselayers[name];
3849
3850 if (newBaseLayers[name] && newBaseLayers[name].doRefresh) {
3851 newBaseLayers[name].doRefresh = false;
3852 }
3853 }
3854 }
3855 // add new layers
3856 for (var newName in newBaseLayers) {
3857 if (!isDefined(leafletLayers.baselayers[newName])) {
3858 var testBaseLayer = createLayer(newBaseLayers[newName]);
3859 if (isDefined(testBaseLayer)) {
3860 leafletLayers.baselayers[newName] = testBaseLayer;
3861 // Only add the visible layer to the map
3862 if (newBaseLayers[newName].top === true) {
3863 safeAddLayer(map, leafletLayers.baselayers[newName]);
3864 }
3865 }
3866 } else {
3867 if (newBaseLayers[newName].top === true && !map.hasLayer(leafletLayers.baselayers[newName])) {
3868 safeAddLayer(map, leafletLayers.baselayers[newName]);
3869 } else if (newBaseLayers[newName].top === false && map.hasLayer(leafletLayers.baselayers[newName])) {
3870 map.removeLayer(leafletLayers.baselayers[newName]);
3871 }
3872 }
3873 }
3874
3875 //we have layers, so we need to make, at least, one active
3876 var found = false;
3877 // search for an active layer
3878 for (var key in leafletLayers.baselayers) {
3879 if (map.hasLayer(leafletLayers.baselayers[key])) {
3880 found = true;
3881 break;
3882 }
3883 }
3884 // If there is no active layer make one active
3885 if (!found && Object.keys(leafletLayers.baselayers).length > 0) {
3886 safeAddLayer(map, leafletLayers.baselayers[Object.keys(leafletLayers.baselayers)[0]]);
3887 }
3888
3889 // Only show the layers switch selector control if we have more than one baselayer + overlay
3890 isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, newBaseLayers, layers.overlays, leafletLayers);
3891 }, true);
3892
3893 // Watch for the overlay layers
3894 leafletScope.$watch('layers.overlays', function (newOverlayLayers, oldOverlayLayers) {
3895 if (angular.equals(newOverlayLayers, oldOverlayLayers)) {
3896 isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, layers.baselayers, newOverlayLayers, leafletLayers);
3897 return true;
3898 }
3899
3900 // Delete layers from the array
3901 for (var name in leafletLayers.overlays) {
3902 if (!isDefined(newOverlayLayers[name]) || newOverlayLayers[name].doRefresh) {
3903 // Remove from the map if it's on it
3904 if (map.hasLayer(leafletLayers.overlays[name])) {
3905 // Safe remove when ArcGIS layers is loading.
3906 var options = isDefined(newOverlayLayers[name]) ? newOverlayLayers[name].layerOptions : null;
3907 safeRemoveLayer(map, leafletLayers.overlays[name], options);
3908 }
3909 // TODO: Depending on the layer type we will have to delete what's included on it
3910 delete leafletLayers.overlays[name];
3911
3912 if (newOverlayLayers[name] && newOverlayLayers[name].doRefresh) {
3913 newOverlayLayers[name].doRefresh = false;
3914 }
3915 }
3916 }
3917
3918 // add new overlays
3919 for (var newName in newOverlayLayers) {
3920 if (!isDefined(leafletLayers.overlays[newName])) {
3921 var testOverlayLayer = createLayer(newOverlayLayers[newName]);
3922 if (!isDefined(testOverlayLayer)) {
3923 // If the layer creation fails, continue to the next overlay
3924 continue;
3925 }
3926 leafletLayers.overlays[newName] = testOverlayLayer;
3927 if (newOverlayLayers[newName].visible === true) {
3928 safeAddLayer(map, leafletLayers.overlays[newName]);
3929 }
3930
3931 if (isDefined(newOverlayLayers[newName].index) && leafletLayers.overlays[newName].setZIndex) {
3932 leafletLayers.overlays[newName].setZIndex(newOverlayLayers[newName].index);
3933 }
3934 } else {
3935 // check for the .visible property to hide/show overLayers
3936 if (newOverlayLayers[newName].visible && !map.hasLayer(leafletLayers.overlays[newName])) {
3937 safeAddLayer(map, leafletLayers.overlays[newName]);
3938 } else if (newOverlayLayers[newName].visible === false && map.hasLayer(leafletLayers.overlays[newName])) {
3939 // Safe remove when ArcGIS layers is loading.
3940 safeRemoveLayer(map, leafletLayers.overlays[newName], newOverlayLayers[newName].layerOptions);
3941 }
3942
3943 // check for the .layerOptions.opacity property has changed.
3944 var ly = leafletLayers.overlays[newName];
3945 if (map.hasLayer(leafletLayers.overlays[newName])) {
3946 if (newOverlayLayers[newName].layerOptions.opacity !== oldOverlayLayers[newName].layerOptions.opacity) {
3947
3948 if (isDefined(ly.setOpacity)) {
3949 ly.setOpacity(newOverlayLayers[newName].layerOptions.opacity);
3950 }
3951 if (isDefined(ly.getLayers) && isDefined(ly.eachLayer)) {
3952 ly.eachLayer(changeOpacityListener(newOverlayLayers[newName].layerOptions.opacity));
3953 }
3954 }
3955
3956 if (isDefined(newOverlayLayers[newName].index) && ly.setZIndex && newOverlayLayers[newName].index !== oldOverlayLayers[newName].index) {
3957 ly.setZIndex(newOverlayLayers[newName].index);
3958 }
3959 }
3960 }
3961
3962 //refresh heatmap data if present
3963 if (newOverlayLayers[newName].visible && map._loaded && newOverlayLayers[newName].data && newOverlayLayers[newName].type === "heatmap") {
3964 leafletLayers.overlays[newName].setData(newOverlayLayers[newName].data);
3965 leafletLayers.overlays[newName].update();
3966 }
3967 }
3968
3969 // Only add the layers switch selector control if we have more than one baselayer + overlay
3970 isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, layers.baselayers, newOverlayLayers, leafletLayers);
3971 }, true);
3972 });
3973 }
3974 };
3975}]);
3976
3977'use strict';
3978
3979angular.module("ui-leaflet").directive('legend', ["leafletLogger", "$http", "$timeout", "leafletHelpers", "leafletLegendHelpers", function (leafletLogger, $http, $timeout, leafletHelpers, leafletLegendHelpers) {
3980 var $log = leafletLogger,
3981 errorHeader = leafletHelpers.errorHeader + ' [Legend] ';
3982 return {
3983 restrict: "A",
3984 scope: false,
3985 replace: false,
3986 require: 'leaflet',
3987 transclude: false,
3988
3989 link: function link(scope, element, attrs, controller) {
3990
3991 var isArray = leafletHelpers.isArray,
3992 isString = leafletHelpers.isString,
3993 isDefined = leafletHelpers.isDefined,
3994 isFunction = leafletHelpers.isFunction,
3995 leafletScope = controller.getLeafletScope(),
3996 legend = leafletScope.legend;
3997
3998 var legendClass;
3999 var position;
4000 var leafletLegend;
4001 var type;
4002
4003 leafletScope.$watch('legend', function (newLegend) {
4004
4005 if (isDefined(newLegend)) {
4006 legendClass = newLegend.legendClass ? newLegend.legendClass : "legend";
4007 position = newLegend.position || 'bottomright';
4008 // default to arcgis
4009 type = newLegend.type || 'arcgis';
4010 }
4011 }, true);
4012
4013 var createLegend = function createLegend(map, legendData, newURL) {
4014 if (legendData && legendData.layers && legendData.layers.length > 0) {
4015 if (isDefined(leafletLegend)) {
4016 leafletLegendHelpers.updateLegend(leafletLegend.getContainer(), legendData, type, newURL);
4017 } else {
4018 leafletLegend = L.control({
4019 position: position
4020 });
4021 leafletLegend.onAdd = leafletLegendHelpers.getOnAddLegend(legendData, legendClass, type, newURL);
4022 leafletLegend.addTo(map);
4023 }
4024
4025 if (isDefined(legend.loadedData) && isFunction(legend.loadedData)) {
4026 legend.loadedData();
4027 }
4028 }
4029 };
4030
4031 controller.getMap().then(function (map) {
4032 leafletScope.$watch('legend', function (newLegend) {
4033 if (!isDefined(newLegend)) {
4034 if (isDefined(leafletLegend)) {
4035 leafletLegend.removeFrom(map);
4036 leafletLegend = null;
4037 }
4038
4039 return;
4040 }
4041
4042 if (!isDefined(newLegend.url) && type === 'arcgis' && (!isArray(newLegend.colors) || !isArray(newLegend.labels) || newLegend.colors.length !== newLegend.labels.length)) {
4043 $log.warn(errorHeader + " legend.colors and legend.labels must be set.");
4044 return;
4045 }
4046
4047 if (isDefined(newLegend.url)) {
4048 $log.info(errorHeader + " loading legend service.");
4049 return;
4050 }
4051
4052 if (isDefined(leafletLegend)) {
4053 leafletLegend.removeFrom(map);
4054 leafletLegend = null;
4055 }
4056
4057 leafletLegend = L.control({
4058 position: position
4059 });
4060
4061 if (type === 'arcgis') {
4062 leafletLegend.onAdd = leafletLegendHelpers.getOnAddArrayLegend(newLegend, legendClass);
4063 }
4064 leafletLegend.addTo(map);
4065 });
4066
4067 leafletScope.$watch('legend.url', function (newURL) {
4068 if (!isDefined(newURL)) {
4069 return;
4070 }
4071
4072 if (!isArray(newURL) && !isString(newURL)) {
4073 $log.warn(errorHeader + " legend.url must be an array or string.");
4074 return;
4075 }
4076
4077 var urls = isString(newURL) ? [newURL] : newURL;
4078
4079 var legendData;
4080 var onResult = function onResult(idx, url) {
4081 return function (ld) {
4082 if (isDefined(ld.data.error)) {
4083 $log.warn(errorHeader + 'Error loadin legend from: ' + url, ld.data.error.message);
4084 } else {
4085 if (legendData && legendData.layers && legendData.layers.length > 0) {
4086 legendData.layers = legendData.layers.concat(ld.data.layers);
4087 } else {
4088 legendData = ld.data;
4089 }
4090 }
4091
4092 if (idx === urls.length - 1) {
4093 createLegend(map, legendData, newURL);
4094 }
4095 };
4096 };
4097 var onError = function onError(err) {
4098 $log.warn(errorHeader + ' legend.url not loaded.', err);
4099 };
4100
4101 for (var i = 0; i < urls.length; i++) {
4102 leafletLegendHelpers.addLegendURL(attrs.id, {
4103 url: urls[i],
4104 method: 'GET'
4105 }).then(onResult(i)).catch(onError);
4106 }
4107 });
4108
4109 leafletScope.$watch('legend.legendData', function (legendData) {
4110 $log.debug('legendData', legendData);
4111 if (isDefined(leafletScope.legend.url) || !isDefined(legendData)) {
4112 return;
4113 }
4114
4115 createLegend(map, legendData);
4116 }, true);
4117 });
4118 }
4119 };
4120}]);
4121
4122'use strict';
4123
4124angular.module('ui-leaflet').directive('markers', ["leafletLogger", "$rootScope", "$q", "leafletData", "leafletHelpers", "leafletMapDefaults", "leafletMarkersHelpers", "leafletMarkerEvents", "leafletIterators", "leafletWatchHelpers", "leafletDirectiveControlsHelpers", function (leafletLogger, $rootScope, $q, leafletData, leafletHelpers, leafletMapDefaults, leafletMarkersHelpers, leafletMarkerEvents, leafletIterators, leafletWatchHelpers, leafletDirectiveControlsHelpers) {
4125 //less terse vars to helpers
4126 var isDefined = leafletHelpers.isDefined,
4127 errorHeader = leafletHelpers.errorHeader,
4128 Helpers = leafletHelpers,
4129 isString = leafletHelpers.isString,
4130 addMarkerWatcher = leafletMarkersHelpers.addMarkerWatcher,
4131 updateMarker = leafletMarkersHelpers.updateMarker,
4132 listenMarkerEvents = leafletMarkersHelpers.listenMarkerEvents,
4133 addMarkerToGroup = leafletMarkersHelpers.addMarkerToGroup,
4134 createMarker = leafletMarkersHelpers.createMarker,
4135 deleteMarker = leafletMarkersHelpers.deleteMarker,
4136 getModelFromModels = leafletMarkersHelpers.getModelFromModels,
4137 getLayerModels = leafletMarkersHelpers.getLayerModels,
4138 resetUnusedMarkerGroups = leafletMarkersHelpers.resetUnusedMarkerGroups,
4139 $it = leafletIterators,
4140 _defaultWatchOptions = leafletHelpers.watchOptions,
4141 maybeWatch = leafletWatchHelpers.maybeWatch,
4142 extendDirectiveControls = leafletDirectiveControlsHelpers.extend,
4143 $log = leafletLogger,
4144 watchTrap = { changeFromDirective: false };
4145
4146 var _getLMarker = function _getLMarker(leafletMarkers, name, maybeLayerName) {
4147 if (!Object.keys(leafletMarkers).length) return;
4148 if (maybeLayerName && isString(maybeLayerName)) {
4149 if (!leafletMarkers[maybeLayerName] || !Object.keys(leafletMarkers[maybeLayerName]).length) return;
4150 return leafletMarkers[maybeLayerName][name];
4151 }
4152 return leafletMarkers[name];
4153 };
4154
4155 var _setLMarker = function _setLMarker(lObject, leafletMarkers, name, maybeLayerName) {
4156 if (maybeLayerName && isString(maybeLayerName)) {
4157 if (!isDefined(leafletMarkers[maybeLayerName])) leafletMarkers[maybeLayerName] = {};
4158 leafletMarkers[maybeLayerName][name] = lObject;
4159 } else leafletMarkers[name] = lObject;
4160 return lObject;
4161 };
4162
4163 var _maybeAddMarkerToLayer = function _maybeAddMarkerToLayer(layerName, layers, model, marker, watchType, map) {
4164
4165 if (!isString(layerName)) {
4166 $log.error(errorHeader + ' A layername must be a string');
4167 return false;
4168 }
4169
4170 if (!isDefined(layers)) {
4171 $log.error(errorHeader + ' You must add layers to the directive if the markers are going to use this functionality.');
4172 return false;
4173 }
4174
4175 if (!isDefined(layers.overlays) || !isDefined(layers.overlays[layerName])) {
4176 $log.error(errorHeader + ' A marker can only be added to a layer of type "group"');
4177 return false;
4178 }
4179 var layerGroup = layers.overlays[layerName];
4180 if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) {
4181 $log.error(errorHeader + ' Adding a marker to an overlay needs a overlay of the type "group" or "featureGroup"');
4182 return false;
4183 }
4184
4185 // The marker goes to a correct layer group, so first of all we add it
4186 layerGroup.addLayer(marker);
4187
4188 // The marker is automatically added to the map depending on the visibility
4189 // of the layer, so we only have to open the popup if the marker is in the map
4190 if (watchType === null && map.hasLayer(marker) && model.focus === true) {
4191 marker.openPopup();
4192 }
4193 return true;
4194 };
4195 //TODO: move to leafletMarkersHelpers??? or make a new class/function file (leafletMarkersHelpers is large already)
4196 var _addMarkers = function _addMarkers(mapId, markersToRender, oldModels, map, layers, leafletMarkers, leafletScope, watchOptions, maybeLayerName, skips) {
4197 $it.each(markersToRender, function (model, newName) {
4198 if (skips[newName]) return;
4199
4200 if (newName.search("-") !== -1) {
4201 $log.error('The marker can\'t use a "-" on his key name: "' + newName + '".');
4202 return;
4203 }
4204
4205 var pathToMarker = Helpers.getObjectDotPath(maybeLayerName ? [maybeLayerName, newName] : [newName]);
4206 var maybeLMarker = _getLMarker(leafletMarkers, newName, maybeLayerName);
4207 Helpers.modelChangeInDirective(watchTrap, "changeFromDirective", function () {
4208 if (!isDefined(maybeLMarker)) {
4209
4210 var marker = createMarker(model);
4211 var layerName = (model ? model.layer : undefined) || maybeLayerName; //original way takes pref
4212 if (!isDefined(marker)) {
4213 $log.error(errorHeader + ' Received invalid data on the marker ' + newName + '.');
4214 return;
4215 }
4216 _setLMarker(marker, leafletMarkers, newName, maybeLayerName);
4217
4218 // Bind message
4219 if (isDefined(model.message)) {
4220 marker.bindPopup(model.message, model.popupOptions);
4221 }
4222
4223 // Add the marker to a cluster group if needed
4224 if (isDefined(model.group)) {
4225 var groupOptions = isDefined(model.groupOption) ? model.groupOption : null;
4226 addMarkerToGroup(marker, model.group, groupOptions, map);
4227 }
4228
4229 // Show label if defined
4230 if (Helpers.LabelPlugin.isLoaded() && isDefined(model.label) && isDefined(model.label.message)) {
4231 marker.bindLabel(model.label.message, model.label.options);
4232 }
4233
4234 // Check if the marker should be added to a layer
4235 if (isDefined(model) && (isDefined(model.layer) || isDefined(maybeLayerName))) {
4236
4237 var pass = _maybeAddMarkerToLayer(layerName, layers, model, marker, watchOptions.individual.type, map);
4238 if (!pass) return; //something went wrong move on in the loop
4239 } else if (!isDefined(model.group)) {
4240 // We do not have a layer attr, so the marker goes to the map layer
4241 map.addLayer(marker);
4242 if (watchOptions.individual.type === null && model.focus === true) {
4243 marker.openPopup();
4244 }
4245 }
4246
4247 if (watchOptions.individual.type !== null) {
4248 addMarkerWatcher(marker, pathToMarker, leafletScope, layers, map, watchOptions.individual);
4249 }
4250
4251 listenMarkerEvents(marker, model, leafletScope, watchOptions.individual.type, map);
4252 leafletMarkerEvents.bindEvents(mapId, marker, pathToMarker, model, leafletScope, layerName);
4253 } else {
4254 var oldModel = getModelFromModels(oldModels, newName, maybeLayerName);
4255 updateMarker(model, oldModel, maybeLMarker, pathToMarker, leafletScope, layers, map);
4256 }
4257 });
4258 });
4259 };
4260 var _seeWhatWeAlreadyHave = function _seeWhatWeAlreadyHave(markerModels, oldMarkerModels, lMarkers, isEqual, cb) {
4261 var hasLogged = false,
4262 equals = false,
4263 oldMarker,
4264 newMarker;
4265
4266 var doCheckOldModel = isDefined(oldMarkerModels);
4267 for (var name in lMarkers) {
4268 if (!hasLogged) {
4269 $log.debug(errorHeader + "[markers] destroy: ");
4270 hasLogged = true;
4271 }
4272
4273 if (doCheckOldModel) {
4274 //might want to make the option (in watch options) to disable deep checking
4275 //ie the options to only check !== (reference check) instead of angular.equals (slow)
4276 newMarker = markerModels[name];
4277 oldMarker = oldMarkerModels[name];
4278 equals = isEqual && angular.equals(newMarker, oldMarker);
4279 }
4280 if (!isDefined(markerModels) || !Object.keys(markerModels).length || !isDefined(markerModels[name]) || !Object.keys(markerModels[name]).length || equals) {
4281 if (cb && Helpers.isFunction(cb)) cb(newMarker, oldMarker, name);
4282 }
4283 }
4284 };
4285 var _destroy = function _destroy(markerModels, oldMarkerModels, lMarkers, map, layers) {
4286 _seeWhatWeAlreadyHave(markerModels, oldMarkerModels, lMarkers, false, function (newMarker, oldMarker, lMarkerName) {
4287 $log.debug(errorHeader + '[marker] is deleting marker: ' + lMarkerName);
4288 deleteMarker(lMarkers[lMarkerName], map, layers);
4289 delete lMarkers[lMarkerName];
4290 });
4291 };
4292
4293 var _getNewModelsToSkipp = function _getNewModelsToSkipp(newModels, oldModels, lMarkers) {
4294 var skips = {};
4295 _seeWhatWeAlreadyHave(newModels, oldModels, lMarkers, true, function (newMarker, oldMarker, lMarkerName) {
4296 $log.debug(errorHeader + '[marker] is already rendered, marker: ' + lMarkerName);
4297 skips[lMarkerName] = newMarker;
4298 });
4299 return skips;
4300 };
4301
4302 return {
4303 restrict: "A",
4304 scope: false,
4305 replace: false,
4306 require: ['leaflet', '?layers'],
4307
4308 link: function link(scope, element, attrs, controller) {
4309 var mapController = controller[0],
4310 leafletScope = mapController.getLeafletScope();
4311
4312 mapController.getMap().then(function (map) {
4313 var leafletMarkers = {},
4314 getLayers;
4315
4316 // If the layers attribute is used, we must wait until the layers are created
4317 if (isDefined(controller[1])) {
4318 getLayers = controller[1].getLayers;
4319 } else {
4320 getLayers = function getLayers() {
4321 var deferred = $q.defer();
4322 deferred.resolve();
4323 return deferred.promise;
4324 };
4325 }
4326
4327 var watchOptions;
4328 if (leafletScope.watchOptions && leafletScope.watchOptions.markers) {
4329 watchOptions = leafletScope.watchOptions.markers;
4330 } else {
4331 watchOptions = _defaultWatchOptions;
4332 }
4333
4334 var isNested = isDefined(attrs.markersNested) && Helpers.isTruthy(attrs.markersNested);
4335
4336 getLayers().then(function (layers) {
4337 var _clean = function _clean(models, oldModels) {
4338 resetUnusedMarkerGroups();
4339 if (isNested) {
4340 $it.each(models, function (markerToMaybeDel, layerName) {
4341 var oldLayerModels = getLayerModels(oldModels, layerName);
4342 _destroy(markerToMaybeDel, oldLayerModels, leafletMarkers[layerName], map, layers);
4343 });
4344 return;
4345 }
4346 _destroy(models, oldModels, leafletMarkers, map, layers);
4347 };
4348
4349 var _create = function _create(models, oldModels) {
4350 _clean(models, oldModels);
4351 var skips = null;
4352 if (isNested) {
4353 $it.each(models, function (markersToAdd, layerName) {
4354 var oldLayerModels = getLayerModels(oldModels, layerName);
4355 var newlayerModels = getLayerModels(models, layerName);
4356 skips = _getNewModelsToSkipp(newlayerModels, oldLayerModels, leafletMarkers[layerName]);
4357 _addMarkers(attrs.id, markersToAdd, oldModels, map, layers, leafletMarkers, leafletScope, watchOptions, layerName, skips);
4358 });
4359 return;
4360 }
4361 skips = _getNewModelsToSkipp(models, oldModels, leafletMarkers);
4362 _addMarkers(attrs.id, models, oldModels, map, layers, leafletMarkers, leafletScope, watchOptions, undefined, skips);
4363 };
4364 extendDirectiveControls(attrs.id, 'markers', _create, _clean);
4365 leafletData.setMarkers(leafletMarkers, attrs.id);
4366
4367 maybeWatch(leafletScope, 'markers', watchOptions, function (newMarkers, oldMarkers) {
4368 if (watchTrap.changeFromDirective) return;
4369 _create(newMarkers, oldMarkers);
4370 });
4371 scope.$on('$destroy', function () {
4372 _destroy(leafletScope.markers, {}, leafletMarkers, map, layers);
4373 });
4374 });
4375 });
4376 }
4377 };
4378}]);
4379
4380'use strict';
4381
4382angular.module('ui-leaflet').directive('maxbounds', ["leafletLogger", "leafletMapDefaults", "leafletBoundsHelpers", "leafletHelpers", function (leafletLogger, leafletMapDefaults, leafletBoundsHelpers, leafletHelpers) {
4383 // var $log = leafletLogger;
4384 return {
4385 restrict: "A",
4386 scope: false,
4387 replace: false,
4388 require: 'leaflet',
4389
4390 link: function link(scope, element, attrs, controller) {
4391 var leafletScope = controller.getLeafletScope(),
4392 isValidBounds = leafletBoundsHelpers.isValidBounds,
4393 isNumber = leafletHelpers.isNumber;
4394
4395 controller.getMap().then(function (map) {
4396 leafletScope.$watch("maxbounds", function (maxbounds) {
4397 if (!isValidBounds(maxbounds)) {
4398 // Unset any previous maxbounds
4399 map.setMaxBounds();
4400 return;
4401 }
4402
4403 var leafletBounds = leafletBoundsHelpers.createLeafletBounds(maxbounds);
4404 if (isNumber(maxbounds.pad)) {
4405 leafletBounds = leafletBounds.pad(maxbounds.pad);
4406 }
4407
4408 map.setMaxBounds(leafletBounds);
4409 if (!attrs.center && !attrs.lfCenter) {
4410 map.fitBounds(leafletBounds);
4411 }
4412 });
4413 });
4414 }
4415 };
4416}]);
4417
4418'use strict';
4419
4420angular.module('ui-leaflet').directive('paths', ["leafletLogger", "$q", "leafletData", "leafletMapDefaults", "leafletHelpers", "leafletPathsHelpers", "leafletPathEvents", "leafletWatchHelpers", function (leafletLogger, $q, leafletData, leafletMapDefaults, leafletHelpers, leafletPathsHelpers, leafletPathEvents, leafletWatchHelpers) {
4421 var $log = leafletLogger;
4422 return {
4423 restrict: "A",
4424 scope: false,
4425 replace: false,
4426 require: ['leaflet', '?layers'],
4427
4428 link: function link(scope, element, attrs, controller) {
4429 var mapController = controller[0],
4430 isDefined = leafletHelpers.isDefined,
4431 isString = leafletHelpers.isString,
4432 leafletScope = mapController.getLeafletScope(),
4433 paths = leafletScope.paths,
4434 createPath = leafletPathsHelpers.createPath,
4435 bindPathEvents = leafletPathEvents.bindPathEvents,
4436 setPathOptions = leafletPathsHelpers.setPathOptions,
4437 maybeWatch = leafletWatchHelpers.maybeWatch;
4438
4439 mapController.getMap().then(function (map) {
4440 var defaults = leafletMapDefaults.getDefaults(attrs.id),
4441 getLayers;
4442
4443 // If the layers attribute is used, we must wait until the layers are created
4444 if (isDefined(controller[1])) {
4445 getLayers = controller[1].getLayers;
4446 } else {
4447 getLayers = function getLayers() {
4448 var deferred = $q.defer();
4449 deferred.resolve();
4450 return deferred.promise;
4451 };
4452 }
4453
4454 if (!isDefined(paths)) {
4455 return;
4456 }
4457
4458 //legacy behaviour does a watch collection on the paths
4459 var _legacyWatchOptions = {
4460 type: 'watchCollection',
4461 individual: {
4462 type: 'watchDeep'
4463 }
4464 };
4465
4466 var watchOptions;
4467 if (leafletScope.watchOptions && leafletScope.watchOptions.paths) {
4468 watchOptions = leafletScope.watchOptions.paths;
4469 } else {
4470 watchOptions = _legacyWatchOptions;
4471 }
4472
4473 getLayers().then(function (layers) {
4474
4475 var leafletPaths = {};
4476 leafletData.setPaths(leafletPaths, attrs.id);
4477
4478 // Function for listening every single path once created
4479 var watchPathFn = function watchPathFn(leafletPath, name, watchOptions) {
4480 var pathWatchPath = "paths[\"" + name + "\"]";
4481
4482 maybeWatch(leafletScope, pathWatchPath, watchOptions, function (pathData, old, clearWatch) {
4483 if (!isDefined(pathData)) {
4484 if (isDefined(old.layer)) {
4485 for (var i in layers.overlays) {
4486 var overlay = layers.overlays[i];
4487 overlay.removeLayer(leafletPath);
4488 }
4489 }
4490 map.removeLayer(leafletPath);
4491 clearWatch();
4492 return;
4493 }
4494 setPathOptions(leafletPath, pathData.type, pathData);
4495 });
4496 };
4497
4498 var _clean = function _clean(newPaths) {
4499 // Delete paths (by name) from the array
4500 for (var name in leafletPaths) {
4501 if (!isDefined(newPaths[name])) {
4502 map.removeLayer(leafletPaths[name]);
4503 delete leafletPaths[name];
4504 }
4505 }
4506 };
4507
4508 var _create = function _create(newPaths) {
4509 _clean(newPaths);
4510 // Create the new paths
4511 for (var newName in newPaths) {
4512 if (newName.search('\\$') === 0) {
4513 continue;
4514 }
4515 if (newName.search("-") !== -1) {
4516 $log.error('[AngularJS - Leaflet] The path name "' + newName + '" is not valid. It must not include "-" and a number.');
4517 continue;
4518 }
4519
4520 if (!isDefined(leafletPaths[newName])) {
4521 var pathData = newPaths[newName];
4522 var newPath = createPath(newName, newPaths[newName], defaults);
4523
4524 // bind popup if defined
4525 if (isDefined(newPath) && isDefined(pathData.message)) {
4526 newPath.bindPopup(pathData.message, pathData.popupOptions);
4527 }
4528
4529 // Show label if defined
4530 if (leafletHelpers.LabelPlugin.isLoaded() && isDefined(pathData.label) && isDefined(pathData.label.message)) {
4531 newPath.bindLabel(pathData.label.message, pathData.label.options);
4532 }
4533
4534 // Check if the marker should be added to a layer
4535 if (isDefined(pathData) && isDefined(pathData.layer)) {
4536
4537 if (!isString(pathData.layer)) {
4538 $log.error('[AngularJS - Leaflet] A layername must be a string');
4539 continue;
4540 }
4541 if (!isDefined(layers)) {
4542 $log.error('[AngularJS - Leaflet] You must add layers to the directive if the markers are going to use this functionality.');
4543 continue;
4544 }
4545
4546 if (!isDefined(layers.overlays) || !isDefined(layers.overlays[pathData.layer])) {
4547 $log.error('[AngularJS - Leaflet] A path can only be added to a layer of type "group"');
4548 continue;
4549 }
4550 var layerGroup = layers.overlays[pathData.layer];
4551 if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) {
4552 $log.error('[AngularJS - Leaflet] Adding a path to an overlay needs a overlay of the type "group" or "featureGroup"');
4553 continue;
4554 }
4555
4556 // Listen for changes on the new path
4557 leafletPaths[newName] = newPath;
4558 // The path goes to a correct layer group, so first of all we add it
4559 layerGroup.addLayer(newPath);
4560
4561 if (watchOptions.individual.type !== null) {
4562 watchPathFn(newPath, newName, watchOptions.individual);
4563 } else {
4564 setPathOptions(newPath, pathData.type, pathData);
4565 }
4566 } else if (isDefined(newPath)) {
4567 // Listen for changes on the new path
4568 leafletPaths[newName] = newPath;
4569 map.addLayer(newPath);
4570
4571 if (watchOptions.individual.type !== null) {
4572 watchPathFn(newPath, newName, watchOptions.individual);
4573 } else {
4574 setPathOptions(newPath, pathData.type, pathData);
4575 }
4576 }
4577
4578 bindPathEvents(attrs.id, newPath, newName, pathData, leafletScope);
4579 }
4580 }
4581 };
4582
4583 maybeWatch(leafletScope, 'paths', watchOptions, function (newPaths) {
4584 _create(newPaths);
4585 });
4586 });
4587 });
4588 }
4589 };
4590}]);
4591
4592'use strict';
4593
4594angular.module('ui-leaflet').directive('tiles', ["leafletLogger", "leafletData", "leafletMapDefaults", "leafletHelpers", function (leafletLogger, leafletData, leafletMapDefaults, leafletHelpers) {
4595 var $log = leafletLogger;
4596 return {
4597 restrict: "A",
4598 scope: false,
4599 replace: false,
4600 require: 'leaflet',
4601
4602 link: function link(scope, element, attrs, controller) {
4603 var isDefined = leafletHelpers.isDefined,
4604 leafletScope = controller.getLeafletScope(),
4605 tiles = leafletScope.tiles;
4606
4607 if (!isDefined(tiles) || !isDefined(tiles.url)) {
4608 $log.warn("[AngularJS - Leaflet] The 'tiles' definition doesn't have the 'url' property.");
4609 return;
4610 }
4611
4612 controller.getMap().then(function (map) {
4613 var defaults = leafletMapDefaults.getDefaults(attrs.id);
4614 var tileLayerObj;
4615 leafletScope.$watch("tiles", function (tiles) {
4616 var tileLayerOptions = defaults.tileLayerOptions;
4617 var tileLayerUrl = defaults.tileLayer;
4618
4619 // If no valid tiles are in the scope, remove the last layer
4620 if (!isDefined(tiles.url) && isDefined(tileLayerObj)) {
4621 map.removeLayer(tileLayerObj);
4622 return;
4623 }
4624
4625 // No leafletTiles object defined yet
4626 if (!isDefined(tileLayerObj)) {
4627 if (isDefined(tiles.options)) {
4628 angular.copy(tiles.options, tileLayerOptions);
4629 }
4630
4631 if (isDefined(tiles.url)) {
4632 tileLayerUrl = tiles.url;
4633 }
4634
4635 tileLayerObj = L.tileLayer(tileLayerUrl, tileLayerOptions);
4636 tileLayerObj.addTo(map);
4637 leafletData.setTiles(tileLayerObj, attrs.id);
4638 return;
4639 }
4640
4641 // If the options of the tilelayer is changed, we need to redraw the layer
4642 if (isDefined(tiles.url) && isDefined(tiles.options) && !angular.equals(tiles.options, tileLayerOptions)) {
4643 map.removeLayer(tileLayerObj);
4644 tileLayerOptions = defaults.tileLayerOptions;
4645 angular.copy(tiles.options, tileLayerOptions);
4646 tileLayerUrl = tiles.url;
4647 tileLayerObj = L.tileLayer(tileLayerUrl, tileLayerOptions);
4648 tileLayerObj.addTo(map);
4649 leafletData.setTiles(tileLayerObj, attrs.id);
4650 return;
4651 }
4652
4653 // Only the URL of the layer is changed, update the tiles object
4654 if (isDefined(tiles.url)) {
4655 tileLayerObj.setUrl(tiles.url);
4656 }
4657 }, true);
4658 });
4659 }
4660 };
4661}]);
4662
4663'use strict';
4664
4665angular.module('ui-leaflet').directive('watchOptions', ['$log', '$rootScope', '$q', 'leafletData', 'leafletHelpers', function (leafletLogger, $rootScope, $q, leafletData, leafletHelpers) {
4666
4667 var isDefined = leafletHelpers.isDefined,
4668 errorHeader = leafletHelpers.errorHeader,
4669 isObject = leafletHelpers.isObject,
4670 $log = leafletLogger;
4671
4672 return {
4673 restrict: "A",
4674 scope: false,
4675 replace: false,
4676 require: ['leaflet'],
4677
4678 link: function link(scope, element, attrs, controller) {
4679 var mapController = controller[0],
4680 leafletScope = mapController.getLeafletScope();
4681
4682 var _isValidWatchType = function _isValidWatchType(type) {
4683 return type === 'watch' || type === 'watchCollection' || type === 'watchDeep' || type === null;
4684 };
4685
4686 if (isDefined(leafletScope.watchOptions) && isObject(leafletScope.watchOptions)) {
4687 angular.forEach(['markers', 'geojson', 'paths'], function (name) {
4688 if (isDefined(leafletScope.watchOptions[name])) {
4689 if (!_isValidWatchType(leafletScope.watchOptions[name].type)) {
4690 $log.error(errorHeader + ' watchOptions.' + name + '.type is not a valid type.');
4691 }
4692 if (isDefined(leafletScope.watchOptions[name].individual)) {
4693 if (!_isValidWatchType(leafletScope.watchOptions[name].individual.type)) {
4694 $log.error(errorHeader + ' watchOptions.' + name + '.individual.type is not a valid type.');
4695 }
4696 } else {
4697 $log.error(errorHeader + ' watchOptions.' + name + '.type.individual must be defined.');
4698 }
4699 }
4700 });
4701 }
4702 }
4703 };
4704}]);
4705
4706'use strict';
4707
4708angular.module('ui-leaflet').factory('leafletEventsHelpersFactory', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", function ($rootScope, $q, leafletLogger, leafletHelpers) {
4709 var safeApply = leafletHelpers.safeApply,
4710 isDefined = leafletHelpers.isDefined,
4711 isObject = leafletHelpers.isObject,
4712 isArray = leafletHelpers.isArray,
4713 errorHeader = leafletHelpers.errorHeader,
4714 $log = leafletLogger;
4715
4716 var EventsHelper = function EventsHelper(rootBroadcastName, lObjectType) {
4717 this.rootBroadcastName = rootBroadcastName;
4718 $log.debug("leafletEventsHelpersFactory: lObjectType: " + lObjectType + "rootBroadcastName: " + rootBroadcastName);
4719 //used to path/key out certain properties based on the type , "markers", "geojson"
4720 this.lObjectType = lObjectType;
4721 };
4722
4723 EventsHelper.prototype.getAvailableEvents = function () {
4724 return [];
4725 };
4726
4727 /*
4728 argument: name: Note this can be a single string or dot notation
4729 Example:
4730 markerModel : {
4731 m1: { lat:_, lon: _}
4732 }
4733 //would yield name of
4734 name = "m1"
4735 If nested:
4736 markerModel : {
4737 cars: {
4738 m1: { lat:_, lon: _}
4739 }
4740 }
4741 //would yield name of
4742 name = "cars.m1"
4743 */
4744 EventsHelper.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName, extra) {
4745 var _this = this;
4746
4747 maybeMapId = maybeMapId || '';
4748 if (maybeMapId) maybeMapId = '.' + maybeMapId;
4749
4750 return function (e) {
4751 var broadcastName = _this.rootBroadcastName + maybeMapId + '.' + eventName;
4752 $log.debug(broadcastName);
4753 _this.fire(leafletScope, broadcastName, logic, e, e.target || lObject, model, name, layerName, extra);
4754 };
4755 };
4756
4757 EventsHelper.prototype.fire = function (scope, broadcastName, logic, event, lObject, model, modelName, layerName, extra) {
4758 // Safely broadcast the event
4759 safeApply(scope, function () {
4760 var toSend = {
4761 leafletEvent: event,
4762 leafletObject: lObject,
4763 modelName: modelName,
4764 model: model
4765 };
4766 if (isDefined(layerName)) angular.extend(toSend, { layerName: layerName });
4767
4768 if (logic === "emit") {
4769 scope.$emit(broadcastName, toSend);
4770 } else {
4771 $rootScope.$broadcast(broadcastName, toSend);
4772 }
4773 });
4774 };
4775
4776 EventsHelper.prototype.bindEvents = function (maybeMapId, lObject, name, model, leafletScope, layerName, extra) {
4777 var events = [];
4778 var logic = 'emit';
4779 var _this = this;
4780
4781 if (!isDefined(leafletScope.eventBroadcast)) {
4782 // Backward compatibility, if no event-broadcast attribute, all events are broadcasted
4783 events = this.getAvailableEvents();
4784 } else if (!isObject(leafletScope.eventBroadcast)) {
4785 // Not a valid object
4786 $log.error(errorHeader + "event-broadcast must be an object check your model.");
4787 } else {
4788 // We have a possible valid object
4789 if (!isDefined(leafletScope.eventBroadcast[_this.lObjectType])) {
4790 // We do not have events enable/disable do we do nothing (all enabled by default)
4791 events = this.getAvailableEvents();
4792 } else if (!isObject(leafletScope.eventBroadcast[_this.lObjectType])) {
4793 // Not a valid object
4794 $log.warn(errorHeader + 'event-broadcast.' + [_this.lObjectType] + ' must be an object check your model.');
4795 } else {
4796 // We have a possible valid map object
4797 // Event propadation logic
4798 if (isDefined(leafletScope.eventBroadcast[this.lObjectType].logic)) {
4799 // We take care of possible propagation logic
4800 if (leafletScope.eventBroadcast[_this.lObjectType].logic !== "emit" && leafletScope.eventBroadcast[_this.lObjectType].logic !== "broadcast") $log.warn(errorHeader + "Available event propagation logic are: 'emit' or 'broadcast'.");
4801 }
4802 // Enable / Disable
4803 var eventsEnable = false,
4804 eventsDisable = false;
4805 if (isDefined(leafletScope.eventBroadcast[_this.lObjectType].enable) && isArray(leafletScope.eventBroadcast[_this.lObjectType].enable)) eventsEnable = true;
4806 if (isDefined(leafletScope.eventBroadcast[_this.lObjectType].disable) && isArray(leafletScope.eventBroadcast[_this.lObjectType].disable)) eventsDisable = true;
4807
4808 if (eventsEnable && eventsDisable) {
4809 // Both are active, this is an error
4810 $log.warn(errorHeader + "can not enable and disable events at the same time");
4811 } else if (!eventsEnable && !eventsDisable) {
4812 // Both are inactive, this is an error
4813 $log.warn(errorHeader + "must enable or disable events");
4814 } else {
4815 // At this point the object is OK, lets enable or disable events
4816 if (eventsEnable) {
4817 // Enable events
4818 leafletScope.eventBroadcast[this.lObjectType].enable.forEach(function (eventName) {
4819 // Do we have already the event enabled?
4820 if (events.indexOf(eventName) !== -1) {
4821 // Repeated event, this is an error
4822 $log.warn(errorHeader + "This event " + eventName + " is already enabled");
4823 } else {
4824 // Does the event exists?
4825 if (_this.getAvailableEvents().indexOf(eventName) === -1) {
4826 // The event does not exists, this is an error
4827 $log.warn(errorHeader + "This event " + eventName + " does not exist");
4828 } else {
4829 // All ok enable the event
4830 events.push(eventName);
4831 }
4832 }
4833 });
4834 } else {
4835 // Disable events
4836 events = this.getAvailableEvents();
4837 leafletScope.eventBroadcast[_this.lObjectType].disable.forEach(function (eventName) {
4838 var index = events.indexOf(eventName);
4839 if (index === -1) {
4840 // The event does not exist
4841 $log.warn(errorHeader + "This event " + eventName + " does not exist or has been already disabled");
4842 } else {
4843 events.splice(index, 1);
4844 }
4845 });
4846 }
4847 }
4848 }
4849 }
4850
4851 events.forEach(function (eventName) {
4852 lObject.on(eventName, _this.genDispatchEvent(maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName, extra));
4853 });
4854 return logic;
4855 };
4856
4857 return EventsHelper;
4858}]).service('leafletEventsHelpers', ["leafletEventsHelpersFactory", function (leafletEventsHelpersFactory) {
4859 return new leafletEventsHelpersFactory();
4860}]);
4861
4862'use strict';
4863
4864angular.module('ui-leaflet').factory('leafletGeoJsonEvents', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", "leafletEventsHelpersFactory", "leafletData", function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpersFactory, leafletData) {
4865 var safeApply = leafletHelpers.safeApply,
4866 EventsHelper = leafletEventsHelpersFactory;
4867 // $log = leafletLogger;
4868
4869 var GeoJsonEvents = function GeoJsonEvents() {
4870 EventsHelper.call(this, 'leafletDirectiveGeoJson', 'geojson');
4871 };
4872
4873 GeoJsonEvents.prototype = new EventsHelper();
4874
4875 GeoJsonEvents.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName, extra) {
4876 var base = EventsHelper.prototype.genDispatchEvent.call(this, maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName),
4877 _this = this;
4878
4879 return function (e) {
4880 if (eventName === 'mouseout') {
4881 if (extra.resetStyleOnMouseout) {
4882 leafletData.getGeoJSON(extra.mapId).then(function (leafletGeoJSON) {
4883 //this is broken on nested needs to traverse or user layerName (nested)
4884 var lobj = layerName ? leafletGeoJSON[layerName] : leafletGeoJSON;
4885 lobj.resetStyle(e.target);
4886 });
4887 }
4888 safeApply(leafletScope, function () {
4889 $rootScope.$broadcast(_this.rootBroadcastName + '.mouseout', e);
4890 });
4891 }
4892 base(e); //common
4893 };
4894 };
4895
4896 GeoJsonEvents.prototype.getAvailableEvents = function () {
4897 return ['click', 'dblclick', 'mouseover', 'mouseout'];
4898 };
4899
4900 return new GeoJsonEvents();
4901}]);
4902
4903'use strict';
4904
4905angular.module('ui-leaflet').factory('leafletLabelEvents', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", "leafletEventsHelpersFactory", function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpersFactory) {
4906 var Helpers = leafletHelpers,
4907 EventsHelper = leafletEventsHelpersFactory;
4908 //$log = leafletLogger;
4909
4910 var LabelEvents = function LabelEvents() {
4911 EventsHelper.call(this, 'leafletDirectiveLabel', 'markers');
4912 };
4913 LabelEvents.prototype = new EventsHelper();
4914
4915 LabelEvents.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
4916 var markerName = name.replace('markers.', '');
4917 return EventsHelper.prototype.genDispatchEvent.call(this, maybeMapId, eventName, logic, leafletScope, lObject, markerName, model, layerName);
4918 };
4919
4920 LabelEvents.prototype.getAvailableEvents = function () {
4921 return ['click', 'dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
4922 };
4923
4924 LabelEvents.prototype.genEvents = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
4925 var _this = this;
4926 var labelEvents = this.getAvailableEvents();
4927 var scopeWatchName = Helpers.getObjectArrayPath("markers." + name);
4928 labelEvents.forEach(function (eventName) {
4929 lObject.label.on(eventName, _this.genDispatchEvent(maybeMapId, eventName, logic, leafletScope, lObject.label, scopeWatchName, model, layerName));
4930 });
4931 };
4932
4933 LabelEvents.prototype.bindEvents = function (maybeMapId, lObject, name, model, leafletScope, layerName) {};
4934
4935 return new LabelEvents();
4936}]);
4937
4938'use strict';
4939
4940angular.module('ui-leaflet').factory('leafletMapEvents', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", "leafletEventsHelpers", "leafletIterators", function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpers, leafletIterators) {
4941 var isDefined = leafletHelpers.isDefined,
4942 fire = leafletEventsHelpers.fire;
4943
4944 var _getAvailableMapEvents = function _getAvailableMapEvents() {
4945 return ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'contextmenu', 'focus', 'blur', 'preclick', 'load', 'unload', 'viewreset', 'movestart', 'move', 'moveend', 'dragstart', 'drag', 'dragend', 'zoomstart', 'zoomanim', 'zoomend', 'zoomlevelschange', 'resize', 'autopanstart', 'layeradd', 'layerremove', 'baselayerchange', 'overlayadd', 'overlayremove', 'locationfound', 'locationerror', 'popupopen', 'popupclose', 'draw:created', 'draw:edited', 'draw:deleted', 'draw:drawstart', 'draw:drawstop', 'draw:editstart', 'draw:editstop', 'draw:deletestart', 'draw:deletestop'];
4946 };
4947
4948 var _genDispatchMapEvent = function _genDispatchMapEvent(scope, eventName, logic, maybeMapId) {
4949 if (maybeMapId) {
4950 maybeMapId = maybeMapId + '.';
4951 }
4952 return function (e) {
4953 // Put together broadcast name
4954 var broadcastName = 'leafletDirectiveMap.' + maybeMapId + eventName;
4955 leafletLogger.debug(broadcastName);
4956 // Safely broadcast the event
4957 fire(scope, broadcastName, logic, e, e.target, scope);
4958 };
4959 };
4960
4961 var _notifyCenterChangedToBounds = function _notifyCenterChangedToBounds(scope) {
4962 scope.$broadcast("boundsChanged");
4963 };
4964
4965 var _notifyCenterUrlHashChanged = function _notifyCenterUrlHashChanged(scope, map, attrs, search) {
4966 if (!isDefined(attrs.urlHashCenter)) {
4967 return;
4968 }
4969 var center = map.getCenter();
4970 var centerUrlHash = center.lat.toFixed(4) + ":" + center.lng.toFixed(4) + ":" + map.getZoom();
4971 if (!isDefined(search.c) || search.c !== centerUrlHash) {
4972 //$log.debug("notified new center...");
4973 scope.$emit("centerUrlHash", centerUrlHash);
4974 }
4975 };
4976
4977 var _addEvents = function _addEvents(map, mapId, mapEvents, contextName, scope, logic) {
4978 leafletIterators.each(mapEvents, function (eventName) {
4979 var context = {};
4980 context[contextName] = eventName;
4981 if (!mapId) {
4982 mapId = map._container.id || '';
4983 }
4984
4985 map.on(eventName, _genDispatchMapEvent(scope, eventName, logic, mapId), context);
4986 });
4987 };
4988
4989 return {
4990 getAvailableMapEvents: _getAvailableMapEvents,
4991 genDispatchMapEvent: _genDispatchMapEvent,
4992 notifyCenterChangedToBounds: _notifyCenterChangedToBounds,
4993 notifyCenterUrlHashChanged: _notifyCenterUrlHashChanged,
4994 addEvents: _addEvents
4995 };
4996}]);
4997
4998'use strict';
4999
5000angular.module('ui-leaflet').factory('leafletMarkerEvents', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", "leafletEventsHelpersFactory", "leafletLabelEvents", function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpersFactory, leafletLabelEvents) {
5001 var safeApply = leafletHelpers.safeApply,
5002 isDefined = leafletHelpers.isDefined,
5003 Helpers = leafletHelpers,
5004 lblHelp = leafletLabelEvents,
5005 EventsHelper = leafletEventsHelpersFactory,
5006 $log = leafletLogger;
5007
5008 var MarkerEvents = function MarkerEvents() {
5009 EventsHelper.call(this, 'leafletDirectiveMarker', 'markers');
5010 };
5011
5012 MarkerEvents.prototype = new EventsHelper();
5013
5014 MarkerEvents.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
5015 var handle = EventsHelper.prototype.genDispatchEvent.call(this, maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName);
5016 return function (e) {
5017 // Broadcast old marker click name for backwards compatibility
5018 if (eventName === "click") {
5019 safeApply(leafletScope, function () {
5020 $rootScope.$broadcast('leafletDirectiveMarkersClick', name);
5021 });
5022 } else if (eventName === 'dragend') {
5023 safeApply(leafletScope, function () {
5024 model.lat = lObject.getLatLng().lat;
5025 model.lng = lObject.getLatLng().lng;
5026 });
5027 if (model.message && model.focus === true) {
5028 lObject.openPopup();
5029 }
5030 }
5031 handle(e); //common
5032 };
5033 };
5034
5035 MarkerEvents.prototype.getAvailableEvents = function () {
5036 return ['click', 'dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu', 'dragstart', 'drag', 'dragend', 'move', 'remove', 'popupopen', 'popupclose', 'touchend', 'touchstart', 'touchmove', 'touchcancel', 'touchleave'];
5037 };
5038
5039 MarkerEvents.prototype.bindEvents = function (maybeMapId, lObject, name, model, leafletScope, layerName) {
5040 var logic = EventsHelper.prototype.bindEvents.call(this, maybeMapId, lObject, name, model, leafletScope, layerName);
5041
5042 if (Helpers.LabelPlugin.isLoaded() && isDefined(lObject.label)) {
5043 lblHelp.genEvents(maybeMapId, name, logic, leafletScope, lObject, model, layerName);
5044 }
5045 };
5046
5047 return new MarkerEvents();
5048}]);
5049
5050'use strict';
5051
5052var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
5053
5054angular.module('ui-leaflet').factory('leafletPathEvents', ["$rootScope", "$q", "leafletLogger", "leafletHelpers", "leafletLabelEvents", "leafletEventsHelpers", function ($rootScope, $q, leafletLogger, leafletHelpers, leafletLabelEvents, leafletEventsHelpers) {
5055 var isDefined = leafletHelpers.isDefined,
5056 isObject = leafletHelpers.isObject,
5057 Helpers = leafletHelpers,
5058 errorHeader = leafletHelpers.errorHeader,
5059 lblHelp = leafletLabelEvents,
5060 fire = leafletEventsHelpers.fire,
5061 $log = leafletLogger;
5062
5063 /*
5064 TODO (nmccready) This EventsHelper needs to be derrived from leafletEventsHelpers to elminate copy and paste code.
5065 */
5066
5067 var _genDispatchPathEvent = function _genDispatchPathEvent(maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
5068 maybeMapId = maybeMapId || '';
5069
5070 if (maybeMapId) maybeMapId = '.' + maybeMapId;
5071
5072 return function (e) {
5073 var broadcastName = 'leafletDirectivePath' + maybeMapId + '.' + eventName;
5074 $log.debug(broadcastName);
5075 fire(leafletScope, broadcastName, logic, e, e.target || lObject, model, name, layerName);
5076 };
5077 };
5078
5079 var _bindPathEvents = function _bindPathEvents(maybeMapId, lObject, name, model, leafletScope) {
5080 var pathEvents = [],
5081 i,
5082 eventName,
5083 logic = "broadcast";
5084
5085 if (!isDefined(leafletScope.eventBroadcast)) {
5086 // Backward compatibility, if no event-broadcast attribute, all events are broadcasted
5087 pathEvents = _getAvailablePathEvents();
5088 } else if (!isObject(leafletScope.eventBroadcast)) {
5089 // Not a valid object
5090 $log.error(errorHeader + "event-broadcast must be an object check your model.");
5091 } else {
5092 // We have a possible valid object
5093 if (!isDefined(leafletScope.eventBroadcast.path)) {
5094 // We do not have events enable/disable do we do nothing (all enabled by default)
5095 pathEvents = _getAvailablePathEvents();
5096 } else if (isObject(leafletScope.eventBroadcast.paths)) {
5097 // Not a valid object
5098 $log.warn(errorHeader + "event-broadcast.path must be an object check your model.");
5099 } else {
5100 // We have a possible valid map object
5101 // Event propadation logic
5102 if (leafletScope.eventBroadcast.path.logic !== undefined && leafletScope.eventBroadcast.path.logic !== null) {
5103 // We take care of possible propagation logic
5104 if (leafletScope.eventBroadcast.path.logic !== "emit" && leafletScope.eventBroadcast.path.logic !== "broadcast") {
5105 // This is an error
5106 $log.warn(errorHeader + "Available event propagation logic are: 'emit' or 'broadcast'.");
5107 } else if (leafletScope.eventBroadcast.path.logic === "emit") {
5108 logic = "emit";
5109 }
5110 }
5111 // Enable / Disable
5112 var pathEventsEnable = false,
5113 pathEventsDisable = false;
5114 if (leafletScope.eventBroadcast.path.enable !== undefined && leafletScope.eventBroadcast.path.enable !== null) {
5115 if (_typeof(leafletScope.eventBroadcast.path.enable) === 'object') {
5116 pathEventsEnable = true;
5117 }
5118 }
5119 if (leafletScope.eventBroadcast.path.disable !== undefined && leafletScope.eventBroadcast.path.disable !== null) {
5120 if (_typeof(leafletScope.eventBroadcast.path.disable) === 'object') {
5121 pathEventsDisable = true;
5122 }
5123 }
5124 if (pathEventsEnable && pathEventsDisable) {
5125 // Both are active, this is an error
5126 $log.warn(errorHeader + "can not enable and disable events at the same time");
5127 } else if (!pathEventsEnable && !pathEventsDisable) {
5128 // Both are inactive, this is an error
5129 $log.warn(errorHeader + "must enable or disable events");
5130 } else {
5131 // At this point the path object is OK, lets enable or disable events
5132 if (pathEventsEnable) {
5133 // Enable events
5134 for (i = 0; i < leafletScope.eventBroadcast.path.enable.length; i++) {
5135 eventName = leafletScope.eventBroadcast.path.enable[i];
5136 // Do we have already the event enabled?
5137 if (pathEvents.indexOf(eventName) !== -1) {
5138 // Repeated event, this is an error
5139 $log.warn(errorHeader + "This event " + eventName + " is already enabled");
5140 } else {
5141 // Does the event exists?
5142 if (_getAvailablePathEvents().indexOf(eventName) === -1) {
5143 // The event does not exists, this is an error
5144 $log.warn(errorHeader + "This event " + eventName + " does not exist");
5145 } else {
5146 // All ok enable the event
5147 pathEvents.push(eventName);
5148 }
5149 }
5150 }
5151 } else {
5152 // Disable events
5153 pathEvents = _getAvailablePathEvents();
5154 for (i = 0; i < leafletScope.eventBroadcast.path.disable.length; i++) {
5155 eventName = leafletScope.eventBroadcast.path.disable[i];
5156 var index = pathEvents.indexOf(eventName);
5157 if (index === -1) {
5158 // The event does not exist
5159 $log.warn(errorHeader + "This event " + eventName + " does not exist or has been already disabled");
5160 } else {
5161 pathEvents.splice(index, 1);
5162 }
5163 }
5164 }
5165 }
5166 }
5167 }
5168
5169 for (i = 0; i < pathEvents.length; i++) {
5170 eventName = pathEvents[i];
5171 lObject.on(eventName, _genDispatchPathEvent(maybeMapId, eventName, logic, leafletScope, pathEvents, name));
5172 }
5173
5174 if (Helpers.LabelPlugin.isLoaded() && isDefined(lObject.label)) {
5175 lblHelp.genEvents(maybeMapId, name, logic, leafletScope, lObject, model);
5176 }
5177 };
5178
5179 var _getAvailablePathEvents = function _getAvailablePathEvents() {
5180 return ['click', 'dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu', 'add', 'remove', 'popupopen', 'popupclose'];
5181 };
5182
5183 return {
5184 getAvailablePathEvents: _getAvailablePathEvents,
5185 bindPathEvents: _bindPathEvents
5186 };
5187}]);
5188
5189}(angular));