You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5188 lines
221 KiB

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