UNPKG

ui.leaflet.webpack

Version:

Webpack version of ui-leaflet (https://github.com/angular-ui/ui-leaflet)

600 lines (520 loc) 30.4 kB
angular.module('ui-leaflet').service('leafletMarkersHelpers', /** @ngInject */ [ '$rootScope', '$timeout', 'leafletHelpers', 'leafletLogger', '$compile', 'leafletGeoJsonHelpers', 'leafletWatchHelpers', 'L', function ($rootScope, $timeout, leafletHelpers, leafletLogger, $compile, leafletGeoJsonHelpers, leafletWatchHelpers, L) { var isDefined = leafletHelpers.isDefined, defaultTo = leafletHelpers.defaultTo, MarkerClusterPlugin = leafletHelpers.MarkerClusterPlugin, AwesomeMarkersPlugin = leafletHelpers.AwesomeMarkersPlugin, VectorMarkersPlugin = leafletHelpers.VectorMarkersPlugin, MakiMarkersPlugin = leafletHelpers.MakiMarkersPlugin, ExtraMarkersPlugin = leafletHelpers.ExtraMarkersPlugin, DomMarkersPlugin = leafletHelpers.DomMarkersPlugin, safeApply = leafletHelpers.safeApply, Helpers = leafletHelpers, isString = leafletHelpers.isString, isNumber = leafletHelpers.isNumber, isObject = leafletHelpers.isObject, groups = {}, geoHlp = leafletGeoJsonHelpers, errorHeader = leafletHelpers.errorHeader, maybeWatch = leafletWatchHelpers.maybeWatch, $log = leafletLogger; var _string = function (marker) { //this exists since JSON.stringify barfs on cyclic var retStr = ''; ['_icon', '_latlng', '_leaflet_id', '_map', '_shadow'].forEach(function (prop) { retStr += prop + ': ' + defaultTo(marker[prop], 'undefined') + ' \n'; }); return '[leafletMarker] : \n' + retStr; }; var _log = function (marker, useConsole) { var logger = useConsole ? console : $log; logger.debug(_string(marker)); }; var existDomContainer = function (groupName) { return angular.element(groups[groupName]._map._container).parent().length > 0; }; var createLeafletIcon = function (iconData) { if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'awesomeMarker') { if (!AwesomeMarkersPlugin.isLoaded()) { $log.error(errorHeader + ' The AwesomeMarkers Plugin is not loaded.'); } return new L.AwesomeMarkers.icon(iconData); } if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'vectorMarker') { if (!VectorMarkersPlugin.isLoaded()) { $log.error(errorHeader + ' The VectorMarkers Plugin is not loaded.'); } return new L.VectorMarkers.icon(iconData); } if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'makiMarker') { if (!MakiMarkersPlugin.isLoaded()) { $log.error(errorHeader + 'The MakiMarkers Plugin is not loaded.'); } return new L.MakiMarkers.icon(iconData); } if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'extraMarker') { if (!ExtraMarkersPlugin.isLoaded()) { $log.error(errorHeader + 'The ExtraMarkers Plugin is not loaded.'); } return new L.ExtraMarkers.icon(iconData); } if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'div') { return new L.divIcon(iconData); } if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'dom') { if (!DomMarkersPlugin.isLoaded()) { $log.error(errorHeader + 'The DomMarkers Plugin is not loaded.'); } var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope().$new() : $rootScope, template = $compile(iconData.template)(markerScope), iconDataCopy = angular.copy(iconData); iconDataCopy.ngElement = template; iconDataCopy.element = template[0]; if(angular.isFunction(iconData.getMarkerScope)) iconDataCopy.scope = markerScope; return new L.DomMarkers.icon(iconDataCopy); } // allow for any custom icon to be used... assumes the icon has already been initialized if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'icon') { return iconData.icon; } var base64icon = "data:image/png;base64,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"; 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="; if (!isDefined(iconData) || !isDefined(iconData.iconUrl)) { return new L.Icon.Default({ iconUrl: base64icon, shadowUrl: base64shadow, iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); } return new L.Icon(iconData); }; var _resetMarkerGroup = function (groupName) { if (isDefined(groups[groupName])) { delete groups[groupName]; } }; var _resetMarkerGroups = function () { groups = {}; }; var _resetUnusedMarkerGroups = function (){ for(var groupName in groups) { if (!existDomContainer(groupName)) { _resetMarkerGroup(groupName); } } }; var _cleanDomIcon = function _cleanDomIcon(marker) { if( marker.options.icon.options.ngElement) { marker.options.icon.options.ngElement.remove(); } if( marker.options.icon.options.scope) { marker.options.icon.options.scope.$destroy(); } }; var _deleteMarker = function (marker, map, layers) { marker.closePopup(); // if it's a dom icon, clean it if(marker.options.icon && marker.options.icon.options && marker.options.icon.options.type === 'dom') { _cleanDomIcon(marker); } // There is no easy way to know if a marker is added to a layer, so we search for it // if there are overlays if (isDefined(layers) && isDefined(layers.overlays)) { for (var key in layers.overlays) { if (layers.overlays[key] instanceof L.LayerGroup || layers.overlays[key] instanceof L.FeatureGroup) { if (layers.overlays[key].hasLayer(marker)) { layers.overlays[key].removeLayer(marker); return; } } } } if (isDefined(groups)) { for (var groupKey in groups) { if (groups[groupKey].hasLayer(marker)) { groups[groupKey].removeLayer(marker); } } } if (map.hasLayer(marker)) { map.removeLayer(marker); } }; var adjustPopupPan = function(marker, map) { var containerHeight = marker._popup._container.offsetHeight, layerPos = new L.Point(marker._popup._containerLeft, -containerHeight - marker._popup._containerBottom), containerPos = map.layerPointToContainerPoint(layerPos); if (containerPos !== null) { marker._popup._adjustPan(); } }; var compilePopup = function(marker, markerScope) { $compile(marker._popup._contentNode)(markerScope); }; var updatePopup = function (marker, markerScope, map) { //The innerText should be more than 1 once angular has compiled. //We need to keep trying until angular has compiled before we _updateLayout and _updatePosition //This should take care of any scenario , eg ngincludes, whatever. //Is there a better way to check for this? var innerText = marker._popup._contentNode.innerText || marker._popup._contentNode.textContent; if (innerText.length < 1) { $timeout(function () { updatePopup(marker, markerScope, map); }); } //cause a reflow - this is also very important - if we don't do this then the widths are from before $compile var reflow = marker._popup._contentNode.offsetWidth; marker._popup._updateLayout(); marker._popup._updatePosition(); if (marker._popup.options.autoPan) { adjustPopupPan(marker, map); } //using / returning reflow so jshint doesn't moan return reflow; }; var _manageOpenPopup = function (marker, markerData, map) { // The marker may provide a scope returning function used to compile the message // default to $rootScope otherwise var markerScope = angular.isFunction(markerData.getMessageScope) ? markerData.getMessageScope() : $rootScope, compileMessage = isDefined(markerData.compileMessage) ? markerData.compileMessage : true; if (compileMessage) { if (!isDefined(marker._popup) || !isDefined(marker._popup._contentNode)) { $log.error(errorHeader + 'Popup is invalid or does not have any content.'); return false; } compilePopup(marker, markerScope); updatePopup(marker, markerData, map); } }; var _manageOpenLabel = function (marker, markerData) { var markerScope = angular.isFunction(markerData.getMessageScope) ? markerData.getMessageScope() : $rootScope, labelScope = angular.isFunction(markerData.getLabelScope) ? markerData.getLabelScope() : markerScope, compileMessage = isDefined(markerData.compileMessage) ? markerData.compileMessage : true; if (Helpers.LabelPlugin.isLoaded() && isDefined(markerData.label)) { if (isDefined(markerData.label.options) && markerData.label.options.noHide === true) { marker.showLabel(); } if (compileMessage && isDefined(marker.label)) { $compile(marker.label._container)(labelScope); } } }; var _updateMarker = function (markerData, oldMarkerData, marker, name, leafletScope, layers, map) { if (!isDefined(oldMarkerData)) { return; } // Update the lat-lng property (always present in marker properties) if (!geoHlp.validateCoords(markerData)) { $log.warn('There are problems with lat-lng data, please verify your marker model'); _deleteMarker(marker, map, layers); return; } // watch is being initialized if old and new object is the same var isInitializing = markerData === oldMarkerData; // Update marker rotation if (isDefined(markerData.iconAngle) && oldMarkerData.iconAngle !== markerData.iconAngle) { marker.setIconAngle(markerData.iconAngle); } // It is possible that the layer has been removed or the layer marker does not exist // Update the layer group if present or move it to the map if not if (!isString(markerData.layer)) { // There is no layer information, we move the marker to the map if it was in a layer group if (isString(oldMarkerData.layer)) { // Remove from the layer group that is supposed to be if (isDefined(layers.overlays[oldMarkerData.layer]) && layers.overlays[oldMarkerData.layer].hasLayer(marker)) { layers.overlays[oldMarkerData.layer].removeLayer(marker); marker.closePopup(); } // Test if it is not on the map and add it if (!map.hasLayer(marker)) { map.addLayer(marker); } } } if ((isNumber(markerData.opacity) || isNumber(parseFloat(markerData.opacity))) && markerData.opacity !== oldMarkerData.opacity) { // There was a different opacity so we update it marker.setOpacity(markerData.opacity); } if (isString(markerData.layer) && oldMarkerData.layer !== markerData.layer) { // If it was on a layer group we have to remove it if (isString(oldMarkerData.layer) && isDefined(layers.overlays[oldMarkerData.layer]) && layers.overlays[oldMarkerData.layer].hasLayer(marker)) { layers.overlays[oldMarkerData.layer].removeLayer(marker); } marker.closePopup(); // Remove it from the map in case the new layer is hidden or there is an error in the new layer if (map.hasLayer(marker)) { map.removeLayer(marker); } // The markerData.layer is defined so we add the marker to the layer if it is different from the old data if (!isDefined(layers.overlays[markerData.layer])) { $log.error(errorHeader + 'You must use a name of an existing layer'); return; } // Is a group layer? var layerGroup = layers.overlays[markerData.layer]; if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) { $log.error(errorHeader + 'A marker can only be added to a layer of type "group" or "featureGroup"'); return; } // The marker goes to a correct layer group, so first of all we add it layerGroup.addLayer(marker); // The marker is automatically added to the map depending on the visibility // of the layer, so we only have to open the popup if the marker is in the map if (map.hasLayer(marker) && markerData.focus === true) { marker.openPopup(); } } // Update the draggable property if (markerData.draggable !== true && oldMarkerData.draggable === true && (isDefined(marker.dragging))) { marker.dragging.disable(); } if (markerData.draggable === true && oldMarkerData.draggable !== true) { // The markerData.draggable property must be true so we update if there wasn't a previous value or it wasn't true if (marker.dragging) { marker.dragging.enable(); } else { if (L.Handler.MarkerDrag) { marker.dragging = new L.Handler.MarkerDrag(marker); marker.options.draggable = true; marker.dragging.enable(); } } } // Update the icon property if (!isObject(markerData.icon)) { // If there is no icon property or it's not an object if (isObject(oldMarkerData.icon)) { if(oldMarkerData.icon.type === 'dom') { // clean previous icon if it's a dom one _cleanDomIcon(marker); } // If there was an icon before restore to the default marker.setIcon(createLeafletIcon()); marker.closePopup(); marker.unbindPopup(); if (isString(markerData.message)) { marker.bindPopup(markerData.message, markerData.popupOptions); } } } if (isObject(markerData.icon) && isObject(oldMarkerData.icon) && !angular.equals(markerData.icon, oldMarkerData.icon)) { var dragG = false; if (marker.dragging) { dragG = marker.dragging.enabled(); } if(oldMarkerData.icon.type === 'dom') { // clean previous icon if it's a dom one _cleanDomIcon(marker); } marker.setIcon(createLeafletIcon(markerData.icon)); if (dragG) { marker.dragging.enable(); } marker.closePopup(); marker.unbindPopup(); if (isString(markerData.message)) { marker.bindPopup(markerData.message, markerData.popupOptions); // if marker has been already focused, reopen popup if (map.hasLayer(marker) && markerData.focus === true) { marker.openPopup(); } } } // Update the Popup message property if (!isString(markerData.message) && isString(oldMarkerData.message)) { marker.closePopup(); marker.unbindPopup(); } // Update the label content or bind a new label if the old one has been removed. if (Helpers.LabelPlugin.isLoaded()) { if (isDefined(markerData.label) && isDefined(markerData.label.message)) { if ('label' in oldMarkerData && 'message' in oldMarkerData.label && !angular.equals(markerData.label.message, oldMarkerData.label.message)) { marker.updateLabelContent(markerData.label.message); } else if (!angular.isFunction(marker.getLabel) || angular.isFunction(marker.getLabel) && !isDefined(marker.getLabel())) { marker.bindLabel(markerData.label.message, markerData.label.options); _manageOpenLabel(marker, markerData); } else { _manageOpenLabel(marker, markerData); } } else if (!('label' in markerData && !('message' in markerData.label))) { if (angular.isFunction(marker.unbindLabel)) { marker.unbindLabel(); } } } // There is some text in the popup, so we must show the text or update existing if (isString(markerData.message) && !isString(oldMarkerData.message)) { // There was no message before so we create it marker.bindPopup(markerData.message, markerData.popupOptions); } if (isString(markerData.message) && isString(oldMarkerData.message) && markerData.message !== oldMarkerData.message) { // There was a different previous message so we update it marker.setPopupContent(markerData.message); } // Update the focus property var updatedFocus = false; if (markerData.focus !== true && oldMarkerData.focus === true) { // If there was a focus property and was true we turn it off marker.closePopup(); updatedFocus = true; } // The markerData.focus property must be true so we update if there wasn't a previous value or it wasn't true if (markerData.focus === true && ( !isDefined(oldMarkerData.focus) || oldMarkerData.focus === false) || (isInitializing && markerData.focus === true)) { // Reopen the popup when focus is still true marker.openPopup(); updatedFocus = true; } // zIndexOffset adjustment if (oldMarkerData.zIndexOffset !== markerData.zIndexOffset) { marker.setZIndexOffset(markerData.zIndexOffset); } var markerLatLng = marker.getLatLng(); var isCluster = (isString(markerData.layer) && Helpers.MarkerClusterPlugin.is(layers.overlays[markerData.layer])); // If the marker is in a cluster it has to be removed and added to the layer when the location is changed if (isCluster) { // The focus has changed even by a user click or programatically if (updatedFocus) { // We only have to update the location if it was changed programatically, because it was // changed by a user drag the marker data has already been updated by the internal event // listened by the directive if ((markerData.lat !== oldMarkerData.lat) || (markerData.lng !== oldMarkerData.lng)) { layers.overlays[markerData.layer].removeLayer(marker); marker.setLatLng([markerData.lat, markerData.lng]); layers.overlays[markerData.layer].addLayer(marker); } } else { // The marker has possibly moved. It can be moved by a user drag (marker location and data are equal but old // data is diferent) or programatically (marker location and data are diferent) if ((markerLatLng.lat !== markerData.lat) || (markerLatLng.lng !== markerData.lng)) { // The marker was moved by a user drag layers.overlays[markerData.layer].removeLayer(marker); marker.setLatLng([markerData.lat, markerData.lng]); layers.overlays[markerData.layer].addLayer(marker); } else if ((markerData.lat !== oldMarkerData.lat) || (markerData.lng !== oldMarkerData.lng)) { // The marker was moved programatically layers.overlays[markerData.layer].removeLayer(marker); marker.setLatLng([markerData.lat, markerData.lng]); layers.overlays[markerData.layer].addLayer(marker); } else if (isObject(markerData.icon) && isObject(oldMarkerData.icon) && !angular.equals(markerData.icon, oldMarkerData.icon)) { layers.overlays[markerData.layer].removeLayer(marker); layers.overlays[markerData.layer].addLayer(marker); } } } else if (markerLatLng.lat !== markerData.lat || markerLatLng.lng !== markerData.lng) { marker.setLatLng([markerData.lat, markerData.lng]); } }; var _getLayerModels = function (models, layerName){ if (!isDefined(models)) return; if (layerName) return models[layerName]; return models; }; var _getModelFromModels = function (models, id, layerName){ if(!isDefined(models)) return; if(!id){ $log.error(errorHeader + 'marker id missing in getMarker'); return; } if(layerName) return models[layerName][id]; return models[id]; }; return { resetMarkerGroup: _resetMarkerGroup, resetMarkerGroups: _resetMarkerGroups, resetUnusedMarkerGroups: _resetUnusedMarkerGroups, deleteMarker: _deleteMarker, manageOpenPopup: _manageOpenPopup, manageOpenLabel: _manageOpenLabel, createMarker: function (markerData) { if (!isDefined(markerData) || !geoHlp.validateCoords(markerData)) { $log.error(errorHeader + 'The marker definition is not valid.'); return; } var coords = geoHlp.getCoords(markerData); if (!isDefined(coords)) { $log.error(errorHeader + 'Unable to get coordinates from markerData.'); return; } var markerOptions = { icon: createLeafletIcon(markerData.icon), title: isDefined(markerData.title) ? markerData.title : '', draggable: isDefined(markerData.draggable) ? markerData.draggable : false, clickable: isDefined(markerData.clickable) ? markerData.clickable : true, riseOnHover: isDefined(markerData.riseOnHover) ? markerData.riseOnHover : false, zIndexOffset: isDefined(markerData.zIndexOffset) ? markerData.zIndexOffset : 0, iconAngle: isDefined(markerData.iconAngle) ? markerData.iconAngle : 0 }; // Add any other options not added above to markerOptions for (var markerDatum in markerData) { if (markerData.hasOwnProperty(markerDatum) && !markerOptions.hasOwnProperty(markerDatum)) { markerOptions[markerDatum] = markerData[markerDatum]; } } var marker = new L.marker(coords, markerOptions); if (!isString(markerData.message)) { marker.unbindPopup(); } return marker; }, addMarkerToGroup: function (marker, groupName, groupOptions, map) { if (!isString(groupName)) { $log.error(errorHeader + 'The marker group you have specified is invalid.'); return; } if (!MarkerClusterPlugin.isLoaded()) { $log.error(errorHeader + "The MarkerCluster plugin is not loaded."); return; } if (!isDefined(groups[groupName])) { groups[groupName] = new L.MarkerClusterGroup(groupOptions); map.addLayer(groups[groupName]); } groups[groupName].addLayer(marker); }, listenMarkerEvents: function (marker, markerData, leafletScope, watchType, map) { marker.on("popupopen", function (/* event */) { safeApply(leafletScope, function () { if (isDefined(marker._popup) || isDefined(marker._popup._contentNode)) { markerData.focus = true; _manageOpenPopup(marker, markerData, map);//needed since markerData is now a copy } }); }); marker.on("popupclose", function (/* event */) { safeApply(leafletScope, function () { markerData.focus = false; }); }); marker.on("add", function (/* event */) { safeApply(leafletScope, function () { if ('label' in markerData) _manageOpenLabel(marker, markerData); }); }); }, updateMarker: _updateMarker, addMarkerWatcher: function (marker, name, leafletScope, layers, map, watchOptions) { var markerWatchPath = Helpers.getObjectArrayPath("markers." + name); maybeWatch(leafletScope, markerWatchPath, watchOptions, function(markerData, oldMarkerData, clearWatch){ if (!isDefined(markerData)) { _deleteMarker(marker, map, layers); clearWatch(); return; } _updateMarker(markerData, oldMarkerData, marker, name, leafletScope, layers, map); }); }, string: _string, log: _log, getModelFromModels : _getModelFromModels, getLayerModels : _getLayerModels }; }]);