From decc786758d8d643f538d2f8dbcc655f6190c217 Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 6 Nov 2015 10:01:13 +0530 Subject: [PATCH 1/7] Added wrapX attribute to source object for each type --- src/services/olHelpers.js | 60 ++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/services/olHelpers.js b/src/services/olHelpers.js index a526525f..5a27733a 100644 --- a/src/services/olHelpers.js +++ b/src/services/olHelpers.js @@ -207,7 +207,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.XYZ({ url: url, attributions: createAttribution(source), - tilePixelRatio: pixelRatio > 1 ? 2 : 1 + tilePixelRatio: pixelRatio > 1 ? 2 : 1, + wrapX: source.wrapX ? source.wrapX : true }); break; case 'ImageWMS': @@ -219,7 +220,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: source.url, attributions: createAttribution(source), crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, - params: source.params + params: source.params, + wrapX: source.wrapX ? source.wrapX : true }); break; @@ -232,7 +234,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ var wmsConfiguration = { crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, - attributions: createAttribution(source) + attributions: createAttribution(source), + wrapX: source.wrapX ? source.wrapX : true }; if (source.url) { @@ -264,7 +267,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ origin: source.tileGrid.origin, resolutions: source.tileGrid.resolutions, matrixIds: source.tileGrid.matrixIds - }) + }), + wrapX: source.wrapX ? source.wrapX : true }; if (isDefined(source.url)) { @@ -280,7 +284,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ case 'OSM': oSource = new ol.source.OSM({ - attributions: createAttribution(source) + attributions: createAttribution(source), + wrapX: source.wrapX ? source.wrapX : true }); if (source.url) { @@ -298,7 +303,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ key: source.key, attributions: createAttribution(source), imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], - culture: source.culture + culture: source.culture, + wrapX: source.wrapX ? source.wrapX : true }; if (source.maxZoom) { @@ -316,7 +322,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.MapQuest({ attributions: createAttribution(source), - layer: source.layer + layer: source.layer, + wrapX: source.wrapX ? source.wrapX : true }); break; @@ -332,7 +339,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.XYZ({ attributions: createAttribution(source), - url: _url + url: _url, + wrapX: source.wrapX ? source.wrapX : true }); break; @@ -347,7 +355,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ if (isDefined(source.url)) { oSource = new ol.source.Vector({ format: new ol.format.GeoJSON(), - url: source.url + url: source.url, + wrapX: source.wrapX ? source.wrapX : true }); } else { oSource = new ol.source.Vector(); @@ -382,7 +391,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ }).error(function(response) { $log(response); }); - } + }, + wrapX: source.wrapX ? source.wrapX : true }); } break; @@ -396,11 +406,13 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ if (source.url) { oSource = new ol.source.Vector({ format: new ol.format.TopoJSON(), - url: source.url + url: source.url, + wrapX: source.wrapX ? source.wrapX : true }); } else { oSource = new ol.source.Vector(angular.extend(source.topojson, { - format: new ol.format.TopoJSON() + format: new ol.format.TopoJSON(), + wrapX: source.wrapX ? source.wrapX : true })); } break; @@ -408,7 +420,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.TileJSON({ url: source.url, attributions: createAttribution(source), - crossOrigin: 'anonymous' + crossOrigin: 'anonymous', + wrapX: source.wrapX ? source.wrapX : true }); break; @@ -423,7 +436,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ format: source.format, tileGrid: new ol.tilegrid.createXYZ({ maxZoom: source.maxZoom || 19 - }) + }), + wrapX: source.wrapX ? source.wrapX : true }); break; @@ -452,7 +466,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ var url = source.url + z + '/' + x + '/' + y + '.png'; return url; - } + }, + wrapX: source.wrapX ? source.wrapX : true }); break; case 'TileImage': @@ -472,7 +487,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ .replace('{x}', x.toString()) .replace('{y}', y.toString()); return url; - } + }, + wrapX: source.wrapX ? source.wrapX : true }); break; case 'KML': @@ -481,7 +497,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: source.url, format: new ol.format.KML(), radius: source.radius, - extractStyles: extractStyles + extractStyles: extractStyles, + wrapX: source.wrapX ? source.wrapX : true }); break; case 'Stamen': @@ -490,7 +507,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ return; } oSource = new ol.source.Stamen({ - layer: source.layer + layer: source.layer, + wrapX: source.wrapX ? source.wrapX : true }); break; case 'ImageStatic': @@ -505,7 +523,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ imageSize: source.imageSize, projection: projection, imageExtent: projection.getExtent(), - imageLoadFunction: source.imageLoadFunction + imageLoadFunction: source.imageLoadFunction, + wrapX: source.wrapX ? source.wrapX : true }); break; case 'XYZ': @@ -516,7 +535,8 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: source.url, attributions: createAttribution(source), minZoom: source.minZoom, - maxZoom: source.maxZoom + maxZoom: source.maxZoom, + wrapX: source.wrapX ? source.wrapX : true }); break; } From 6315c599190de5c6cfcdd6d0fde0bb4f6c391544 Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 6 Nov 2015 15:08:32 +0530 Subject: [PATCH 2/7] Changes did for olHelpers to get in use of wrapX attribute for single map default it is for multiple maps. --- .gitignore | 1 - CONTRIBUTING.md | 2 +- dist/angular-openlayers-directive.css | 58 + dist/angular-openlayers-directive.js | 2228 +++++++++++++++++ dist/angular-openlayers-directive.min.js | 31 + ...ular-openlayers-directive.min.no-header.js | 2 + dist/angular-openlayers-directive.pre.js | 2228 +++++++++++++++++ src/services/olHelpers.js | 40 +- 8 files changed, 4568 insertions(+), 22 deletions(-) create mode 100644 dist/angular-openlayers-directive.css create mode 100644 dist/angular-openlayers-directive.js create mode 100644 dist/angular-openlayers-directive.min.js create mode 100644 dist/angular-openlayers-directive.min.no-header.js create mode 100644 dist/angular-openlayers-directive.pre.js diff --git a/.gitignore b/.gitignore index 57eb4608..352ad9bc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ lib temp node_modules/ bower_components/ -dist/ libpeerconnection.log *.swp .*.swp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50e30384..af335b9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -139,7 +139,7 @@ Running "jshint:grunt" (jshint) task Running "concat:dist" (concat) task File "dist/angular-openlayers-directive.js" created. -Running "ngmin:directives" (ngmin) task +Running "ngAnnotate" (ngAnnotate) task ngminifying dist/angular-openlayers-directive.js Running "uglify:dist" (uglify) task diff --git a/dist/angular-openlayers-directive.css b/dist/angular-openlayers-directive.css new file mode 100644 index 00000000..fd9933e0 --- /dev/null +++ b/dist/angular-openlayers-directive.css @@ -0,0 +1,58 @@ +.popup-label { + background-color: #fff; + border: 2px #444 solid; + border-radius: 7px; + -webkit-box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); + -moz-box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); + box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); + color: #111; + font: 12px/20px "Helvetica Neue", Arial, Helvetica, sans-serif; + font-weight: bold; + padding: 3px 6px; + position: absolute; + white-space: nowrap; + top: -35px; + left: 20px; + display: none; +} + +.popup-label img { + vertical-align: middle; +} + +.popup-label.marker:before { + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + content: ""; + border-right: 6px solid black; + border-right-color: inherit; + position: absolute; + left: -8px; + top: 5px; +} + +.angular-openlayers-map:-moz-full-screen { + height: 100%; +} +.angular-openlayers-map:-webkit-full-screen { + height: 100%; +} +.angular-openlayers-map:full-screen { + height: 100%; +} + +.angular-openlayers-map:not(-moz-full-screen) { + height: 400px; +} + +.angular-openlayers-map:not(-webkit-full-screen) { + height: 400px; +} + +.angular-openlayers-map:not(full-screen) { + height: 400px; +} +.ol-full-screen { + position: absolute; + top: 50%; +} diff --git a/dist/angular-openlayers-directive.js b/dist/angular-openlayers-directive.js new file mode 100644 index 00000000..2c1e55c8 --- /dev/null +++ b/dist/angular-openlayers-directive.js @@ -0,0 +1,2228 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. + define(['ol'], function (ol) { + return root.angularOpenlayersDirective = factory(ol); + }); + } else { + // Browser globals + root.angularOpenlayersDirective = factory(root.ol); + } +}(this, function (ol) { +angular.module('openlayers-directive', ['ngSanitize']).directive('openlayers', ["$log", "$q", "$compile", "olHelpers", "olMapDefaults", "olData", function($log, $q, $compile, olHelpers, + olMapDefaults, olData) { + return { + restrict: 'EA', + transclude: true, + replace: true, + scope: { + center: '=olCenter', + defaults: '=olDefaults', + view: '=olView', + events: '=olEvents' + }, + template: '
', + controller: ["$scope", function($scope) { + var _map = $q.defer(); + $scope.getMap = function() { + return _map.promise; + }; + + $scope.setMap = function(map) { + _map.resolve(map); + }; + + this.getOpenlayersScope = function() { + return $scope; + }; + }], + link: function(scope, element, attrs) { + var isDefined = olHelpers.isDefined; + var createLayer = olHelpers.createLayer; + var setMapEvents = olHelpers.setMapEvents; + var setViewEvents = olHelpers.setViewEvents; + var createView = olHelpers.createView; + var defaults = olMapDefaults.setDefaults(scope); + + // Set width and height if they are defined + if (isDefined(attrs.width)) { + if (isNaN(attrs.width)) { + element.css('width', attrs.width); + } else { + element.css('width', attrs.width + 'px'); + } + } + + if (isDefined(attrs.height)) { + if (isNaN(attrs.height)) { + element.css('height', attrs.height); + } else { + element.css('height', attrs.height + 'px'); + } + } + + if (isDefined(attrs.lat)) { + defaults.center.lat = parseFloat(attrs.lat); + } + + if (isDefined(attrs.lon)) { + defaults.center.lon = parseFloat(attrs.lon); + } + + if (isDefined(attrs.zoom)) { + defaults.center.zoom = parseFloat(attrs.zoom); + } + + var controls = ol.control.defaults(defaults.controls); + var interactions = ol.interaction.defaults(defaults.interactions); + var view = createView(defaults.view); + + // Create the Openlayers Map Object with the options + var map = new ol.Map({ + target: element[0], + controls: controls, + interactions: interactions, + renderer: defaults.renderer, + view: view + }); + + // If no layer is defined, set the default tileLayer + if (!attrs.customLayers) { + var l = { + type: 'Tile', + source: { + type: 'OSM' + } + }; + var layer = createLayer(l, view.getProjection(), 'default'); + map.addLayer(layer); + map.set('default', true); + } + + if (!isDefined(attrs.olCenter)) { + var c = ol.proj.transform([defaults.center.lon, + defaults.center.lat + ], + defaults.center.projection, view.getProjection() + ); + view.setCenter(c); + view.setZoom(defaults.center.zoom); + } + + // Set the Default events for the map + setMapEvents(defaults.events, map, scope); + + //Set the Default events for the map view + setViewEvents(defaults.events, map, scope); + + // Resolve the map object to the promises + scope.setMap(map); + olData.setMap(map, attrs.id); + + } + }; + }]); + +angular.module('openlayers-directive').directive('olCenter', ["$log", "$location", "olMapDefaults", "olHelpers", function($log, $location, olMapDefaults, olHelpers) { + + return { + restrict: 'A', + scope: false, + replace: false, + require: 'openlayers', + + link: function(scope, element, attrs, controller) { + var safeApply = olHelpers.safeApply; + var isValidCenter = olHelpers.isValidCenter; + var isDefined = olHelpers.isDefined; + var isArray = olHelpers.isArray; + var isNumber = olHelpers.isNumber; + var isSameCenterOnMap = olHelpers.isSameCenterOnMap; + var setCenter = olHelpers.setCenter; + var setZoom = olHelpers.setZoom; + var olScope = controller.getOpenlayersScope(); + + olScope.getMap().then(function(map) { + var defaults = olMapDefaults.getDefaults(olScope); + var view = map.getView(); + var center = olScope.center; + + if (attrs.olCenter.search('-') !== -1) { + $log.error('[AngularJS - Openlayers] The "center" variable can\'t use ' + + 'a "-" on his key name: "' + attrs.center + '".'); + setCenter(view, defaults.view.projection, defaults.center, map); + return; + } + + if (!isDefined(center)) { + center = {}; + } + + if (!isValidCenter(center)) { + $log.warn('[AngularJS - Openlayers] invalid \'center\''); + center.lat = defaults.center.lat; + center.lon = defaults.center.lon; + center.zoom = defaults.center.zoom; + center.projection = defaults.center.projection; + } + + if (!center.projection) { + if (defaults.view.projection !== 'pixel') { + center.projection = defaults.center.projection; + } else { + center.projection = 'pixel'; + } + } + + if (!isNumber(center.zoom)) { + center.zoom = 1; + } + + setCenter(view, defaults.view.projection, center, map); + view.setZoom(center.zoom); + + var centerUrlHash; + if (center.centerUrlHash === true) { + var extractCenterFromUrl = function() { + var search = $location.search(); + var centerParam; + if (isDefined(search.c)) { + var cParam = search.c.split(':'); + if (cParam.length === 3) { + centerParam = { + lat: parseFloat(cParam[0]), + lon: parseFloat(cParam[1]), + zoom: parseInt(cParam[2], 10) + }; + } + } + return centerParam; + }; + centerUrlHash = extractCenterFromUrl(); + + olScope.$on('$locationChangeSuccess', function() { + var urlCenter = extractCenterFromUrl(); + if (urlCenter && !isSameCenterOnMap(urlCenter, map)) { + safeApply(olScope, function(scope) { + scope.center.lat = urlCenter.lat; + scope.center.lon = urlCenter.lon; + scope.center.zoom = urlCenter.zoom; + }); + } + }); + } + + var geolocation; + olScope.$watchCollection('center', function(center) { + + if (!center) { + return; + } + + if (!center.projection) { + center.projection = defaults.center.projection; + } + + if (center.autodiscover) { + if (!geolocation) { + geolocation = new ol.Geolocation({ + projection: ol.proj.get(center.projection) + }); + + geolocation.on('change', function() { + if (center.autodiscover) { + var location = geolocation.getPosition(); + safeApply(olScope, function(scope) { + scope.center.lat = location[1]; + scope.center.lon = location[0]; + scope.center.zoom = 12; + scope.center.autodiscover = false; + geolocation.setTracking(false); + }); + } + }); + } + geolocation.setTracking(true); + return; + } + + if (!isValidCenter(center)) { + $log.warn('[AngularJS - Openlayers] invalid \'center\''); + center = defaults.center; + } + + var viewCenter = view.getCenter(); + if (viewCenter) { + if (defaults.view.projection === 'pixel') { + view.setCenter(center.coord); + return; + } + var actualCenter = ol.proj.transform(viewCenter, defaults.view.projection, center.projection); + if (!(actualCenter[1] === center.lat && actualCenter[0] === center.lon)) { + setCenter(view, defaults.view.projection, center, map); + } + } + + if (view.getZoom() !== center.zoom) { + setZoom(view, center.zoom, map); + } + }); + + map.on('moveend', function() { + safeApply(olScope, function(scope) { + + if (!isDefined(scope.center)) { + return; + } + + var center = map.getView().getCenter(); + scope.center.zoom = view.getZoom(); + + if (defaults.view.projection === 'pixel') { + scope.center.coord = center; + return; + } + + if (scope.center) { + var proj = ol.proj.transform(center, defaults.view.projection, scope.center.projection); + scope.center.lat = proj[1]; + scope.center.lon = proj[0]; + + // Notify the controller about a change in the center position + olHelpers.notifyCenterUrlHashChanged(olScope, scope.center, $location.search()); + + // Calculate the bounds if needed + if (isArray(scope.center.bounds)) { + var extent = view.calculateExtent(map.getSize()); + var centerProjection = scope.center.projection; + var viewProjection = defaults.view.projection; + scope.center.bounds = ol.proj.transformExtent(extent, viewProjection, centerProjection); + } + } + }); + }); + + }); + } + }; +}]); + +angular.module('openlayers-directive').directive('olLayer', ["$log", "$q", "olMapDefaults", "olHelpers", function($log, $q, olMapDefaults, olHelpers) { + + return { + restrict: 'E', + scope: { + properties: '=olLayerProperties' + }, + replace: false, + require: '^openlayers', + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var equals = olHelpers.equals; + var olScope = controller.getOpenlayersScope(); + var createLayer = olHelpers.createLayer; + var setVectorLayerEvents = olHelpers.setVectorLayerEvents; + var detectLayerType = olHelpers.detectLayerType; + var createStyle = olHelpers.createStyle; + var isBoolean = olHelpers.isBoolean; + var addLayerBeforeMarkers = olHelpers.addLayerBeforeMarkers; + var isNumber = olHelpers.isNumber; + var insertLayer = olHelpers.insertLayer; + var removeLayer = olHelpers.removeLayer; + var addLayerToGroup = olHelpers.addLayerToGroup; + var removeLayerFromGroup = olHelpers.removeLayerFromGroup; + var getGroup = olHelpers.getGroup; + + olScope.getMap().then(function(map) { + var projection = map.getView().getProjection(); + var defaults = olMapDefaults.setDefaults(olScope); + var layerCollection = map.getLayers(); + var olLayer; + + scope.$on('$destroy', function() { + if (scope.properties.group) { + removeLayerFromGroup(layerCollection, olLayer, scope.properties.group); + } else { + removeLayer(layerCollection, olLayer.index); + } + + map.removeLayer(olLayer); + }); + + if (!isDefined(scope.properties)) { + if (isDefined(attrs.sourceType) && isDefined(attrs.sourceUrl)) { + var l = { + source: { + url: attrs.sourceUrl, + type: attrs.sourceType + } + }; + + olLayer = createLayer(l, projection, attrs.layerName); + if (detectLayerType(l) === 'Vector') { + setVectorLayerEvents(defaults.events, map, scope, attrs.name); + } + addLayerBeforeMarkers(layerCollection, olLayer); + } + return; + } + + scope.$watch('properties', function(properties, oldProperties) { + if (!isDefined(properties.source) || !isDefined(properties.source.type)) { + return; + } + + if (!isDefined(properties.visible)) { + properties.visible = true; + return; + } + + if (!isDefined(properties.opacity)) { + properties.opacity = 1; + return; + } + + var style; + var group; + var collection; + if (!isDefined(olLayer)) { + olLayer = createLayer(properties, projection); + if (isDefined(properties.group)) { + addLayerToGroup(layerCollection, olLayer, properties.group); + } else if (isDefined(properties.index)) { + insertLayer(layerCollection, properties.index, olLayer); + } else { + addLayerBeforeMarkers(layerCollection, olLayer); + } + + if (detectLayerType(properties) === 'Vector') { + setVectorLayerEvents(defaults.events, map, scope, properties.name); + } + + if (isBoolean(properties.visible)) { + olLayer.setVisible(properties.visible); + } + + if (properties.opacity) { + olLayer.setOpacity(properties.opacity); + } + + if (angular.isArray(properties.extent)) { + olLayer.setExtent(properties.extent); + } + + if (properties.style) { + if (!angular.isFunction(properties.style)) { + style = createStyle(properties.style); + } else { + style = properties.style; + } + // not every layer has a setStyle method + if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { + olLayer.setStyle(style); + } + } + + } else { + var isNewLayer = (function(olLayer) { + // this function can be used to verify whether a new layer instance has + // been created. This is needed in order to re-assign styles, opacity + // etc... + return function(layer) { + return layer !== olLayer; + }; + })(olLayer); + + // set source properties + if (isDefined(oldProperties) && !equals(properties.source, oldProperties.source)) { + var idx = olLayer.index; + collection = layerCollection; + group = olLayer.get('group'); + + if (group) { + collection = getGroup(layerCollection, group).getLayers(); + } + + collection.removeAt(idx); + + olLayer = createLayer(properties, projection); + olLayer.set('group', group); + + if (isDefined(olLayer)) { + insertLayer(collection, idx, olLayer); + + if (detectLayerType(properties) === 'Vector') { + setVectorLayerEvents(defaults.events, map, scope, properties.name); + } + } + } + + // set opacity + if (isDefined(oldProperties) && + properties.opacity !== oldProperties.opacity || isNewLayer(olLayer)) { + if (isNumber(properties.opacity) || isNumber(parseFloat(properties.opacity))) { + olLayer.setOpacity(properties.opacity); + } + } + + // set index + if (isDefined(properties.index) && properties.index !== olLayer.index) { + collection = layerCollection; + group = olLayer.get('group'); + + if (group) { + collection = getGroup(layerCollection, group).getLayers(); + } + + removeLayer(collection, olLayer.index); + insertLayer(collection, properties.index, olLayer); + } + + // set group + if (isDefined(properties.group) && properties.group !== oldProperties.group) { + removeLayerFromGroup(layerCollection, olLayer, oldProperties.group); + addLayerToGroup(layerCollection, olLayer, properties.group); + } + + // set visibility + if (isDefined(oldProperties) && + isBoolean(properties.visible) && + properties.visible !== oldProperties.visible || isNewLayer(olLayer)) { + olLayer.setVisible(properties.visible); + } + + // set style + if (isDefined(properties.style) && + !equals(properties.style, oldProperties.style) || isNewLayer(olLayer)) { + if (!angular.isFunction(properties.style)) { + style = createStyle(properties.style); + } else { + style = properties.style; + } + // not every layer has a setStyle method + if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { + olLayer.setStyle(style); + } + } + } + }, true); + }); + } + }; +}]); + +angular.module('openlayers-directive').directive('olPath', ["$log", "$q", "olMapDefaults", "olHelpers", function($log, $q, olMapDefaults, olHelpers) { + + return { + restrict: 'E', + scope: { + properties: '=olGeomProperties' + }, + require: '^openlayers', + replace: true, + template: '', + + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var createFeature = olHelpers.createFeature; + var createOverlay = olHelpers.createOverlay; + var createVectorLayer = olHelpers.createVectorLayer; + var insertLayer = olHelpers.insertLayer; + var removeLayer = olHelpers.removeLayer; + var olScope = controller.getOpenlayersScope(); + + olScope.getMap().then(function(map) { + var mapDefaults = olMapDefaults.getDefaults(olScope); + var viewProjection = mapDefaults.view.projection; + + var layer = createVectorLayer(); + var layerCollection = map.getLayers(); + + insertLayer(layerCollection, layerCollection.getLength(), layer); + + scope.$on('$destroy', function() { + removeLayer(layerCollection, layer.index); + }); + + if (isDefined(attrs.coords)) { + var proj = attrs.proj || 'EPSG:4326'; + var coords = JSON.parse(attrs.coords); + var data = { + type: 'Polygon', + coords: coords, + projection: proj, + style: mapDefaults.styles.path + }; + var feature = createFeature(data, viewProjection); + layer.getSource().addFeature(feature); + + if (attrs.message) { + scope.message = attrs.message; + var extent = feature.getGeometry().getExtent(); + var label = createOverlay(element, extent); + map.addOverlay(label); + } + return; + } + }); + } + }; +}]); + +angular.module('openlayers-directive').directive('olView', ["$log", "$q", "olData", "olMapDefaults", "olHelpers", function($log, $q, olData, olMapDefaults, olHelpers) { + return { + restrict: 'A', + scope: false, + replace: false, + require: 'openlayers', + link: function(scope, element, attrs, controller) { + var olScope = controller.getOpenlayersScope(); + var isNumber = olHelpers.isNumber; + var safeApply = olHelpers.safeApply; + var createView = olHelpers.createView; + + olScope.getMap().then(function(map) { + var defaults = olMapDefaults.getDefaults(olScope); + var view = olScope.view; + + if (!view.projection) { + view.projection = defaults.view.projection; + } + + if (!view.maxZoom) { + view.maxZoom = defaults.view.maxZoom; + } + + if (!view.minZoom) { + view.minZoom = defaults.view.minZoom; + } + + if (!view.rotation) { + view.rotation = defaults.view.rotation; + } + + var mapView = createView(view); + map.setView(mapView); + + olScope.$watchCollection('view', function(view) { + if (isNumber(view.rotation)) { + mapView.setRotation(view.rotation); + } + }); + + mapView.on('change:rotation', function() { + safeApply(olScope, function(scope) { + scope.view.rotation = map.getView().getRotation(); + }); + }); + + }); + } + }; +}]); + +angular.module('openlayers-directive').directive('olControl', ["$log", "$q", "olData", "olMapDefaults", "olHelpers", function($log, $q, olData, olMapDefaults, olHelpers) { + + return { + restrict: 'E', + scope: { + properties: '=olControlProperties' + }, + replace: false, + require: '^openlayers', + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var olScope = controller.getOpenlayersScope(); + var olControl; + var olControlOps; + + olScope.getMap().then(function(map) { + var getControlClasses = olHelpers.getControlClasses; + var controlClasses = getControlClasses(); + + scope.$on('$destroy', function() { + map.removeControl(olControl); + }); + + if (!isDefined(scope.properties) || !isDefined(scope.properties.control)) { + if (attrs.name) { + if (isDefined(scope.properties)) { + olControlOps = scope.properties; + } + olControl = new controlClasses[attrs.name](olControlOps); + map.addControl(olControl); + } + return; + } + + olControl = scope.properties.control; + map.addControl(olControl); + }); + } + }; +}]); + +angular.module('openlayers-directive').directive('olMarker', ["$log", "$q", "olMapDefaults", "olHelpers", function($log, $q, olMapDefaults, olHelpers) { + + var getMarkerDefaults = function() { + return { + projection: 'EPSG:4326', + lat: 0, + lon: 0, + coord: [], + show: true, + showOnMouseOver: false, + showOnMouseClick: false, + keepOneOverlayVisible: false + }; + }; + + var markerLayerManager = (function() { + var mapDict = []; + + function getMapIndex(map) { + return mapDict.map(function(record) { + return record.map; + }).indexOf(map); + } + + return { + getInst: function getMarkerLayerInst(scope, map) { + var mapIndex = getMapIndex(map); + + if (mapIndex === -1) { + var markerLayer = olHelpers.createVectorLayer(); + markerLayer.set('markers', true); + map.addLayer(markerLayer); + mapDict.push({ + map: map, + markerLayer: markerLayer, + instScopes: [] + }); + mapIndex = mapDict.length - 1; + } + + mapDict[mapIndex].instScopes.push(scope); + + return mapDict[mapIndex].markerLayer; + }, + deregisterScope: function deregisterScope(scope, map) { + var mapIndex = getMapIndex(map); + if (mapIndex === -1) { + throw Error('This map has no markers'); + } + + var scopes = mapDict[mapIndex].instScopes; + var scopeIndex = scopes.indexOf(scope); + if (scopeIndex === -1) { + throw Error('Scope wan\'t registered'); + } + + scopes.splice(scopeIndex, 1); + + if (!scopes.length) { + map.removeLayer(mapDict[mapIndex].markerLayer); + delete mapDict[mapIndex]; + } + } + }; + })(); + return { + restrict: 'E', + scope: { + lat: '=lat', + lon: '=lon', + label: '=label', + properties: '=olMarkerProperties', + style: '=olStyle' + }, + transclude: true, + require: '^openlayers', + replace: true, + template: + '', + + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var olScope = controller.getOpenlayersScope(); + var createFeature = olHelpers.createFeature; + var createOverlay = olHelpers.createOverlay; + + var hasTranscluded = element.find('ng-transclude').children().length > 0; + + olScope.getMap().then(function(map) { + var markerLayer = markerLayerManager.getInst(scope, map); + var data = getMarkerDefaults(); + + var mapDefaults = olMapDefaults.getDefaults(olScope); + var viewProjection = mapDefaults.view.projection; + var label; + var pos; + var marker; + + // This function handles dragging a marker + var pickOffset = null; + var pickProperties = null; + function handleDrag(evt) { + var coord = evt.coordinate; + var proj = map.getView().getProjection().getCode(); + if (proj === 'pixel') { + coord = coord.map(function(v) { + return parseInt(v, 10); + }); + } else { + coord = ol.proj.transform(coord, proj, 'EPSG:4326'); + } + + if (evt.type === 'pointerdown') { + // Get feature under mouse if any + var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { + return feature; + }); + // Get associated marker properties + pickProperties = (feature ? feature.get('marker') : null); + if (!pickProperties || !pickProperties.draggable) { + pickProperties = null; + return; + } + map.getTarget().style.cursor = 'pointer'; + if (proj === 'pixel') { + pickOffset = [coord[0] - pickProperties.coord[0], coord[1] - pickProperties.coord[1]]; + } else { + pickOffset = [coord[0] - pickProperties.lon, coord[1] - pickProperties.lat]; + } + evt.preventDefault(); + } else if (pickOffset && pickProperties) { + if (evt.type === 'pointerup') { + map.getTarget().style.cursor = ''; + pickOffset = null; + pickProperties = null; + evt.preventDefault(); + } else if (evt.type === 'pointerdrag') { + evt.preventDefault(); + scope.$apply(function() { + // Add current delta to marker initial position + if (proj === 'pixel') { + pickProperties.coord[0] = coord[0] - pickOffset[0]; + pickProperties.coord[1] = coord[1] - pickOffset[1]; + } else { + pickProperties.lon = coord[0] - pickOffset[0]; + pickProperties.lat = coord[1] - pickOffset[1]; + } + }); + } + } + } + + // Setup generic handlers for marker drag + map.on('pointerdown', handleDrag); + map.on('pointerup', handleDrag); + map.on('pointerdrag', handleDrag); + + scope.$on('$destroy', function() { + markerLayer.getSource().removeFeature(marker); + if (isDefined(label)) { + map.removeOverlay(label); + } + markerLayerManager.deregisterScope(scope, map); + }); + + if (!isDefined(scope.properties)) { + data.lat = scope.lat ? scope.lat : data.lat; + data.lon = scope.lon ? scope.lon : data.lon; + data.message = attrs.message; + data.style = scope.style ? scope.style : mapDefaults.styles.marker; + + marker = createFeature(data, viewProjection); + if (!isDefined(marker)) { + $log.error('[AngularJS - Openlayers] Received invalid data on ' + + 'the marker.'); + } + // Add a link between the feature and the marker properties + marker.set('marker', scope); + markerLayer.getSource().addFeature(marker); + + if (data.message || hasTranscluded) { + scope.message = attrs.message; + pos = ol.proj.transform([data.lon, data.lat], data.projection, + viewProjection); + label = createOverlay(element, pos); + map.addOverlay(label); + } + return; + } + + scope.$watch('properties', function(properties) { + + // Remove previous listeners if any + map.getViewport().removeEventListener('mousemove', properties.handleInteraction); + map.getViewport().removeEventListener('click', properties.handleTapInteraction); + map.getViewport().querySelector('canvas.ol-unselectable').removeEventListener( + 'touchend', properties.handleTapInteraction); + map.getViewport().removeEventListener('mousemove', properties.showAtLeastOneOverlay); + map.getViewport().removeEventListener('click', properties.removeAllOverlays); + + // This function handles popup on mouse over/click + properties.handleInteraction = function(evt) { + if (properties.label.show) { + return; + } + var found = false; + var pixel = map.getEventPixel(evt); + var feature = map.forEachFeatureAtPixel(pixel, function(feature) { + return feature; + }); + + var actionTaken = false; + if (feature === marker) { + actionTaken = true; + found = true; + if (!isDefined(label)) { + if (data.projection === 'pixel') { + pos = properties.coord; + } else { + pos = ol.proj.transform([properties.lon, properties.lat], + data.projection, viewProjection); + } + label = createOverlay(element, pos); + map.addOverlay(label); + } + + if (properties.onClick && (evt.type === 'click' || evt.type === 'touchend')) { + scope.$apply(function() { + properties.onClick.call(marker, evt, properties); + }); + } + map.getTarget().style.cursor = 'pointer'; + } + + if (!found && label) { + actionTaken = true; + map.removeOverlay(label); + label = undefined; + map.getTarget().style.cursor = ''; + } + + if (actionTaken) { + evt.preventDefault(); + } + }; + + // Made to filter out click/tap events if both are being triggered on this platform + properties.handleTapInteraction = (function() { + var cooldownActive = false; + var prevTimeout; + + // Sets the cooldown flag to filter out any subsequent events within 500 ms + function activateCooldown() { + cooldownActive = true; + if (prevTimeout) { + clearTimeout(prevTimeout); + } + prevTimeout = setTimeout(function() { + cooldownActive = false; + prevTimeout = null; + }, 500); + } + + // Preventing from 'touchend' to be considered a tap, if fired immediately after 'touchmove' + map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( + 'touchmove', activateCooldown); + + return function() { + if (!cooldownActive) { + properties.handleInteraction.apply(null, arguments); + activateCooldown(); + } + }; + })(); + + properties.showAtLeastOneOverlay = function(evt) { + if (properties.label.show) { + return; + } + var found = false; + var pixel = map.getEventPixel(evt); + var feature = map.forEachFeatureAtPixel(pixel, function(feature) { + return feature; + }); + + var actionTaken = false; + if (feature === marker) { + actionTaken = true; + found = true; + if (!isDefined(label)) { + if (data.projection === 'pixel') { + pos = data.coord; + } else { + pos = ol.proj.transform([data.lon, data.lat], + data.projection, viewProjection); + } + label = createOverlay(element, pos); + angular.forEach(map.getOverlays(), function(value) { + map.removeOverlay(value); + }); + map.addOverlay(label); + } + map.getTarget().style.cursor = 'pointer'; + } + + if (!found && label) { + actionTaken = true; + label = undefined; + map.getTarget().style.cursor = ''; + } + + if (actionTaken) { + evt.preventDefault(); + } + }; + + properties.removeAllOverlays = function(evt) { + angular.forEach(map.getOverlays(), function(value) { + map.removeOverlay(value); + }); + evt.preventDefault(); + }; + + if (!isDefined(marker)) { + data.projection = properties.projection ? properties.projection : + data.projection; + data.coord = properties.coord ? properties.coord : data.coord; + data.lat = properties.lat ? properties.lat : data.lat; + data.lon = properties.lon ? properties.lon : data.lon; + + if (isDefined(properties.style)) { + data.style = properties.style; + } else { + data.style = mapDefaults.styles.marker; + } + + marker = createFeature(data, viewProjection); + if (!isDefined(marker)) { + $log.error('[AngularJS - Openlayers] Received invalid data on ' + + 'the marker.'); + } + // Add a link between the feature and the marker properties + marker.set('marker', properties); + markerLayer.getSource().addFeature(marker); + } else { + var requestedPosition; + if (properties.projection === 'pixel') { + requestedPosition = properties.coord; + } else { + requestedPosition = ol.proj.transform([properties.lon, properties.lat], data.projection, + map.getView().getProjection()); + } + + if (!angular.equals(marker.getGeometry().getCoordinates(), requestedPosition)) { + var geometry = new ol.geom.Point(requestedPosition); + marker.setGeometry(geometry); + } + } + + if (isDefined(label)) { + map.removeOverlay(label); + } + + if (!isDefined(properties.label)) { + return; + } + + scope.message = properties.label.message; + if (!hasTranscluded && (!isDefined(scope.message) || scope.message.length === 0)) { + return; + } + + if (properties.label && properties.label.show === true) { + if (data.projection === 'pixel') { + pos = data.coord; + } else { + pos = ol.proj.transform([properties.lon, properties.lat], data.projection, + viewProjection); + } + label = createOverlay(element, pos); + map.addOverlay(label); + } + + if (label && properties.label && properties.label.show === false) { + map.removeOverlay(label); + label = undefined; + } + + // Then setup new ones according to properties + if (properties.label && properties.label.show === false && + properties.label.showOnMouseOver) { + map.getViewport().addEventListener('mousemove', properties.handleInteraction); + } + + if ((properties.label && properties.label.show === false && + properties.label.showOnMouseClick) || + properties.onClick) { + map.getViewport().addEventListener('click', properties.handleTapInteraction); + map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( + 'touchend', properties.handleTapInteraction); + } + + if ((properties.label && properties.label.show === false && + properties.label.keepOneOverlayVisible)) { + map.getViewport().addEventListener('mousemove', properties.showAtLeastOneOverlay); + map.getViewport().addEventListener('click', properties.removeAllOverlays); + } + }, true); + }); + } + }; +}]); + +angular.module('openlayers-directive').service('olData', ["$log", "$q", "olHelpers", function($log, $q, olHelpers) { + + var obtainEffectiveMapId = olHelpers.obtainEffectiveMapId; + + var maps = {}; + + var setResolvedDefer = function(d, mapId) { + var id = obtainEffectiveMapId(d, mapId); + d[id].resolvedDefer = true; + }; + + var getUnresolvedDefer = function(d, mapId) { + var id = obtainEffectiveMapId(d, mapId); + var defer; + + if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) { + defer = $q.defer(); + d[id] = { + defer: defer, + resolvedDefer: false + }; + } else { + defer = d[id].defer; + } + return defer; + }; + + var getDefer = function(d, mapId) { + var id = obtainEffectiveMapId(d, mapId); + var defer; + + if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) { + defer = getUnresolvedDefer(d, mapId); + } else { + defer = d[id].defer; + } + return defer; + }; + + this.setMap = function(olMap, scopeId) { + var defer = getUnresolvedDefer(maps, scopeId); + defer.resolve(olMap); + setResolvedDefer(maps, scopeId); + }; + + this.getMap = function(scopeId) { + var defer = getDefer(maps, scopeId); + return defer.promise; + }; + +}]); + +angular.module('openlayers-directive').factory('olHelpers', ["$q", "$log", "$http", function($q, $log, $http) { + + var isDefined = function(value) { + return angular.isDefined(value); + }; + + var isDefinedAndNotNull = function(value) { + return angular.isDefined(value) && value !== null; + }; + + var setEvent = function(map, eventType, scope) { + map.on(eventType, function(event) { + var coord = event.coordinate; + var proj = map.getView().getProjection().getCode(); + if (proj === 'pixel') { + coord = coord.map(function(v) { + return parseInt(v, 10); + }); + } + scope.$emit('openlayers.map.' + eventType, { + 'coord': coord, + 'projection': proj, + 'event': event + }); + }); + }; + + var bingImagerySets = [ + 'Road', + 'Aerial', + 'AerialWithLabels', + 'collinsBart', + 'ordnanceSurvey' + ]; + + var getControlClasses = function() { + return { + attribution: ol.control.Attribution, + fullscreen: ol.control.FullScreen, + mouseposition: ol.control.MousePosition, + rotate: ol.control.Rotate, + scaleline: ol.control.ScaleLine, + zoom: ol.control.Zoom, + zoomslider: ol.control.ZoomSlider, + zoomtoextent: ol.control.ZoomToExtent + }; + }; + + var mapQuestLayers = ['osm', 'sat', 'hyb']; + + var esriBaseLayers = ['World_Imagery', 'World_Street_Map', 'World_Topo_Map', + 'World_Physical_Map', 'World_Terrain_Base', + 'Ocean_Basemap', 'NatGeo_World_Map']; + + var styleMap = { + 'style': ol.style.Style, + 'fill': ol.style.Fill, + 'stroke': ol.style.Stroke, + 'circle': ol.style.Circle, + 'icon': ol.style.Icon, + 'image': ol.style.Image, + 'regularshape': ol.style.RegularShape, + 'text': ol.style.Text + }; + + var optionalFactory = function(style, Constructor) { + if (Constructor && style instanceof Constructor) { + return style; + } else if (Constructor) { + return new Constructor(style); + } else { + return style; + } + }; + + //Parse the style tree calling the appropriate constructors. + //The keys in styleMap can be used and the OpenLayers constructors can be + //used directly. + var createStyle = function recursiveStyle(data, styleName) { + var style; + if (!styleName) { + styleName = 'style'; + style = data; + } else { + style = data[styleName]; + } + //Instead of defining one style for the layer, we've been given a style function + //to apply to each feature. + if (styleName === 'style' && data instanceof Function) { + return data; + } + + if (!(style instanceof Object)) { + return style; + } + + var styleObject; + if (Object.prototype.toString.call(style) === '[object Object]') { + styleObject = {}; + var styleConstructor = styleMap[styleName]; + if (styleConstructor && style instanceof styleConstructor) { + return style; + } + Object.getOwnPropertyNames(style).forEach(function(val, idx, array) { + //Consider the case + //image: { + // circle: { + // fill: { + // color: 'red' + // } + // } + // + //An ol.style.Circle is an instance of ol.style.Image, so we do not want to construct + //an Image and then construct a Circle. We assume that if we have an instanceof + //relationship, that the JSON parent has exactly one child. + //We check to see if an inheritance relationship exists. + //If it does, then for the parent we create an instance of the child. + var valConstructor = styleMap[val]; + if (styleConstructor && valConstructor && + valConstructor.prototype instanceof styleMap[styleName]) { + console.assert(array.length === 1, 'Extra parameters for ' + styleName); + styleObject = recursiveStyle(style, val); + return optionalFactory(styleObject, valConstructor); + } else { + styleObject[val] = recursiveStyle(style, val); + + // if the value is 'text' and it contains a String, then it should be interpreted + // as such, 'cause the text style might effectively contain a text to display + if (val !== 'text' && typeof styleObject[val] !== 'string') { + styleObject[val] = optionalFactory(styleObject[val], styleMap[val]); + } + } + }); + } else { + styleObject = style; + } + return optionalFactory(styleObject, styleMap[styleName]); + }; + + var detectLayerType = function(layer) { + if (layer.type) { + return layer.type; + } else { + switch (layer.source.type) { + case 'ImageWMS': + return 'Image'; + case 'ImageStatic': + return 'Image'; + case 'GeoJSON': + case 'JSONP': + case 'TopoJSON': + case 'KML': + case 'TileVector': + return 'Vector'; + default: + return 'Tile'; + } + } + }; + + var createProjection = function(view) { + var oProjection; + + switch (view.projection) { + case 'pixel': + if (!isDefined(view.extent)) { + $log.error('[AngularJS - Openlayers] - You must provide the extent of the image ' + + 'if using pixel projection'); + return; + } + oProjection = new ol.proj.Projection({ + code: 'pixel', + units: 'pixels', + extent: view.extent + }); + break; + default: + oProjection = new ol.proj.get(view.projection); + break; + } + + return oProjection; + }; + + var isValidStamenLayer = function(layer) { + return ['watercolor', 'terrain', 'toner'].indexOf(layer) !== -1; + }; + + var createSource = function(source, projection) { + var oSource; + + switch (source.type) { + case 'MapBox': + if (!source.mapId || !source.accessToken) { + $log.error('[AngularJS - Openlayers] - MapBox layer requires the map id and the access token'); + return; + } + var url = 'http://api.tiles.mapbox.com/v4/' + source.mapId + '/{z}/{x}/{y}.png?access_token=' + + source.accessToken; + + var pixelRatio = window.devicePixelRatio; + + if (pixelRatio > 1) { + url = url.replace('.png', '@2x.png'); + } + + oSource = new ol.source.XYZ({ + url: url, + attributions: createAttribution(source), + tilePixelRatio: pixelRatio > 1 ? 2 : 1, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'ImageWMS': + if (!source.url || !source.params) { + $log.error('[AngularJS - Openlayers] - ImageWMS Layer needs ' + + 'valid server url and params properties'); + } + oSource = new ol.source.ImageWMS({ + url: source.url, + attributions: createAttribution(source), + crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, + params: source.params, + wrapX: source.wrapX ? 0 : 1 + }); + break; + + case 'TileWMS': + if ((!source.url && !source.urls) || !source.params) { + $log.error('[AngularJS - Openlayers] - TileWMS Layer needs ' + + 'valid url (or urls) and params properties'); + } + + var wmsConfiguration = { + crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, + params: source.params, + attributions: createAttribution(source), + wrapX: source.wrapX ? 0 : 1 + }; + + if (source.url) { + wmsConfiguration.url = source.url; + } + + if (source.urls) { + wmsConfiguration.urls = source.urls; + } + + oSource = new ol.source.TileWMS(wmsConfiguration); + break; + + case 'WMTS': + if ((!source.url && !source.urls) || !source.tileGrid) { + $log.error('[AngularJS - Openlayers] - WMTS Layer needs valid url ' + + '(or urls) and tileGrid properties'); + } + + var wmtsConfiguration = { + projection: projection, + layer: source.layer, + attributions: createAttribution(source), + matrixSet: (source.matrixSet === 'undefined') ? projection : source.matrixSet, + format: (source.format === 'undefined') ? 'image/jpeg' : source.format, + requestEncoding: (source.requestEncoding === 'undefined') ? + 'KVP' : source.requestEncoding, + tileGrid: new ol.tilegrid.WMTS({ + origin: source.tileGrid.origin, + resolutions: source.tileGrid.resolutions, + matrixIds: source.tileGrid.matrixIds + }), + wrapX: source.wrapX ? 0 : 1 + }; + + if (isDefined(source.url)) { + wmtsConfiguration.url = source.url; + } + + if (isDefined(source.urls)) { + wmtsConfiguration.urls = source.urls; + } + + oSource = new ol.source.WMTS(wmtsConfiguration); + break; + + case 'OSM': + oSource = new ol.source.OSM({ + attributions: createAttribution(source), + wrapX: (source.wrapX === true) ? 1 : 0 + }); + + if (source.url) { + oSource.setUrl(source.url); + } + + break; + case 'BingMaps': + if (!source.key) { + $log.error('[AngularJS - Openlayers] - You need an API key to show the Bing Maps.'); + return; + } + + var bingConfiguration = { + key: source.key, + attributions: createAttribution(source), + imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], + culture: source.culture, + wrapX: (source.wrapX === true) ? 1 : 0 + }; + + if (source.maxZoom) { + bingConfiguration.maxZoom = source.maxZoom; + } + + oSource = new ol.source.BingMaps(bingConfiguration); + break; + + case 'MapQuest': + if (!source.layer || mapQuestLayers.indexOf(source.layer) === -1) { + $log.error('[AngularJS - Openlayers] - MapQuest layers needs a valid \'layer\' property.'); + return; + } + + oSource = new ol.source.MapQuest({ + attributions: createAttribution(source), + layer: source.layer, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + + break; + + case 'EsriBaseMaps': + if (!source.layer || esriBaseLayers.indexOf(source.layer) === -1) { + $log.error('[AngularJS - Openlayers] - ESRI layers needs a valid \'layer\' property.'); + return; + } + + var _urlBase = 'http://services.arcgisonline.com/ArcGIS/rest/services/'; + var _url = _urlBase + source.layer + '/MapServer/tile/{z}/{y}/{x}'; + + oSource = new ol.source.XYZ({ + attributions: createAttribution(source), + url: _url, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + + break; + + case 'GeoJSON': + if (!(source.geojson || source.url)) { + $log.error('[AngularJS - Openlayers] - You need a geojson ' + + 'property to add a GeoJSON layer.'); + return; + } + + if (isDefined(source.url)) { + oSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + url: source.url, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + } else { + oSource = new ol.source.Vector(); + + var projectionToUse = projection; + if (isDefined(source.geojson.projection)) { + projectionToUse = source.geojson.projection; + } + + var geojsonFormat = new ol.format.GeoJSON(); + var features = geojsonFormat.readFeatures( + source.geojson.object, { featureProjection: projectionToUse }); + + oSource.addFeatures(features); + } + + break; + case 'JSONP': + if (!(source.url)) { + $log.error('[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.'); + return; + } + + if (isDefined(source.url)) { + oSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + loader: function(/*extent, resolution, projection*/) { + var url = source.url + + '&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK'; + $http.jsonp(url, { cache: source.cache}).success(function(response) { + oSource.addFeatures(oSource.readFeatures(response)); + }).error(function(response) { + $log(response); + }); + }, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + } + break; + case 'TopoJSON': + if (!(source.topojson || source.url)) { + $log.error('[AngularJS - Openlayers] - You need a topojson ' + + 'property to add a TopoJSON layer.'); + return; + } + + if (source.url) { + oSource = new ol.source.Vector({ + format: new ol.format.TopoJSON(), + url: source.url, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + } else { + oSource = new ol.source.Vector(angular.extend(source.topojson, { + format: new ol.format.TopoJSON(), + wrapX: (source.wrapX === true) ? 1 : 0 + })); + } + break; + case 'TileJSON': + oSource = new ol.source.TileJSON({ + url: source.url, + attributions: createAttribution(source), + crossOrigin: 'anonymous', + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + + case 'TileVector': + if (!source.url || !source.format) { + $log.error('[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties'); + } + oSource = new ol.source.TileVector({ + url: source.url, + projection: projection, + attributions: createAttribution(source), + format: source.format, + tileGrid: new ol.tilegrid.createXYZ({ + maxZoom: source.maxZoom || 19 + }), + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + + case 'TileTMS': + if (!source.url || !source.tileGrid) { + $log.error('[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties'); + } + oSource = new ol.source.TileImage({ + url: source.url, + maxExtent: source.maxExtent, + attributions: createAttribution(source), + tileGrid: new ol.tilegrid.TileGrid({ + origin: source.tileGrid.origin, + resolutions: source.tileGrid.resolutions + }), + tileUrlFunction: function(tileCoord) { + + var z = tileCoord[0]; + var x = tileCoord[1]; + var y = tileCoord[2]; //(1 << z) - tileCoord[2] - 1; + + if (x < 0 || y < 0) { + return ''; + } + + var url = source.url + z + '/' + x + '/' + y + '.png'; + + return url; + }, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'TileImage': + oSource = new ol.source.TileImage({ + url: source.url, + attributions: createAttribution(source), + tileGrid: new ol.tilegrid.TileGrid({ + origin: source.tileGrid.origin, // top left corner of the pixel projection's extent + resolutions: source.tileGrid.resolutions + }), + tileUrlFunction: function(tileCoord/*, pixelRatio, projection*/) { + var z = tileCoord[0]; + var x = tileCoord[1]; + var y = -tileCoord[2] - 1; + var url = source.url + .replace('{z}', z.toString()) + .replace('{x}', x.toString()) + .replace('{y}', y.toString()); + return url; + }, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'KML': + var extractStyles = source.extractStyles || false; + oSource = new ol.source.Vector({ + url: source.url, + format: new ol.format.KML(), + radius: source.radius, + extractStyles: extractStyles, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'Stamen': + if (!source.layer || !isValidStamenLayer(source.layer)) { + $log.error('[AngularJS - Openlayers] - You need a valid Stamen layer.'); + return; + } + oSource = new ol.source.Stamen({ + layer: source.layer, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'ImageStatic': + if (!source.url || !angular.isArray(source.imageSize) || source.imageSize.length !== 2) { + $log.error('[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.'); + return; + } + + oSource = new ol.source.ImageStatic({ + url: source.url, + attributions: createAttribution(source), + imageSize: source.imageSize, + projection: projection, + imageExtent: projection.getExtent(), + imageLoadFunction: source.imageLoadFunction, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'XYZ': + if (!source.url) { + $log.error('[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties'); + } + oSource = new ol.source.XYZ({ + url: source.url, + attributions: createAttribution(source), + minZoom: source.minZoom, + maxZoom: source.maxZoom, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + } + + // log a warning when no source could be created for the given type + if (!oSource) { + $log.warn('[AngularJS - Openlayers] - No source could be found for type "' + source.type + '"'); + } + + return oSource; + }; + + var createAttribution = function(source) { + var attributions = []; + if (isDefined(source.attribution)) { + attributions.unshift(new ol.Attribution({html: source.attribution})); + } + return attributions; + }; + + var createGroup = function(name) { + var olGroup = new ol.layer.Group(); + olGroup.set('name', name); + + return olGroup; + }; + + var getGroup = function(layers, name) { + var layer; + + angular.forEach(layers, function(l) { + if (l instanceof ol.layer.Group && l.get('name') === name) { + layer = l; + return; + } + }); + + return layer; + }; + + var addLayerBeforeMarkers = function(layers, layer) { + var markersIndex; + for (var i = 0; i < layers.getLength(); i++) { + var l = layers.item(i); + + if (l.get('markers')) { + markersIndex = i; + break; + } + } + + if (isDefined(markersIndex)) { + var markers = layers.item(markersIndex); + layer.index = markersIndex; + layers.setAt(markersIndex, layer); + markers.index = layers.getLength(); + layers.push(markers); + } else { + layer.index = layers.getLength(); + layers.push(layer); + } + + }; + + var removeLayer = function(layers, index) { + layers.removeAt(index); + for (var i = index; i < layers.getLength(); i++) { + var l = layers.item(i); + if (l === null) { + layers.insertAt(i, null); + break; + } else { + l.index = i; + } + } + }; + + return { + // Determine if a reference is defined + isDefined: isDefined, + + // Determine if a reference is a number + isNumber: function(value) { + return angular.isNumber(value); + }, + + createView: function(view) { + var projection = createProjection(view); + + return new ol.View({ + projection: projection, + maxZoom: view.maxZoom, + minZoom: view.minZoom, + extent: view.extent + }); + }, + + // Determine if a reference is defined and not null + isDefinedAndNotNull: isDefinedAndNotNull, + + // Determine if a reference is a string + isString: function(value) { + return angular.isString(value); + }, + + // Determine if a reference is an array + isArray: function(value) { + return angular.isArray(value); + }, + + // Determine if a reference is an object + isObject: function(value) { + return angular.isObject(value); + }, + + // Determine if two objects have the same properties + equals: function(o1, o2) { + return angular.equals(o1, o2); + }, + + isValidCenter: function(center) { + return angular.isDefined(center) && + (typeof center.autodiscover === 'boolean' || + angular.isNumber(center.lat) && angular.isNumber(center.lon) || + (angular.isArray(center.coord) && center.coord.length === 2 && + angular.isNumber(center.coord[0]) && angular.isNumber(center.coord[1])) || + (angular.isArray(center.bounds) && center.bounds.length === 4 && + angular.isNumber(center.bounds[0]) && angular.isNumber(center.bounds[1]) && + angular.isNumber(center.bounds[1]) && angular.isNumber(center.bounds[2]))); + }, + + safeApply: function($scope, fn) { + var phase = $scope.$root.$$phase; + if (phase === '$apply' || phase === '$digest') { + $scope.$eval(fn); + } else { + $scope.$apply(fn); + } + }, + + isSameCenterOnMap: function(center, map) { + var urlProj = center.projection || 'EPSG:4326'; + var urlCenter = [center.lon, center.lat]; + var mapProj = map.getView().getProjection(); + var mapCenter = ol.proj.transform(map.getView().getCenter(), mapProj, urlProj); + var zoom = map.getView().getZoom(); + if (mapCenter[1].toFixed(4) === urlCenter[1].toFixed(4) && + mapCenter[0].toFixed(4) === urlCenter[0].toFixed(4) && + zoom === center.zoom) { + return true; + } + return false; + }, + + setCenter: function(view, projection, newCenter, map) { + + if (map && view.getCenter()) { + var pan = ol.animation.pan({ + duration: 150, + source: (view.getCenter()) + }); + map.beforeRender(pan); + } + + if (newCenter.projection === projection) { + view.setCenter([newCenter.lon, newCenter.lat]); + } else { + var coord = [newCenter.lon, newCenter.lat]; + view.setCenter(ol.proj.transform(coord, newCenter.projection, projection)); + } + }, + + setZoom: function(view, zoom, map) { + var z = ol.animation.zoom({ + duration: 150, + resolution: map.getView().getResolution() + }); + map.beforeRender(z); + view.setZoom(zoom); + }, + + isBoolean: function(value) { + return typeof value === 'boolean'; + }, + + obtainEffectiveMapId: function(d, mapId) { + var id; + var i; + if (!angular.isDefined(mapId)) { + if (Object.keys(d).length === 1) { + for (i in d) { + if (d.hasOwnProperty(i)) { + id = i; + } + } + } else if (Object.keys(d).length === 0) { + id = 'main'; + } else { + $log.error('[AngularJS - Openlayers] - You have more than 1 map on the DOM, ' + + 'you must provide the map ID to the olData.getXXX call'); + } + } else { + id = mapId; + } + return id; + }, + + createStyle: createStyle, + + setMapEvents: function(events, map, scope) { + if (isDefined(events) && angular.isArray(events.map)) { + for (var i in events.map) { + var event = events.map[i]; + setEvent(map, event, scope); + } + } + }, + + setVectorLayerEvents: function(events, map, scope, layerName) { + if (isDefined(events) && angular.isArray(events.layers)) { + angular.forEach(events.layers, function(eventType) { + angular.element(map.getViewport()).on(eventType, function(evt) { + var pixel = map.getEventPixel(evt); + var feature = map.forEachFeatureAtPixel(pixel, function(feature, olLayer) { + // only return the feature if it is in this layer (based on the name) + return (isDefinedAndNotNull(olLayer) && olLayer.get('name') === layerName) ? feature : null; + }); + if (isDefinedAndNotNull(feature)) { + scope.$emit('openlayers.layers.' + layerName + '.' + eventType, feature, evt); + } + }); + }); + } + }, + + setViewEvents: function(events, map, scope) { + if (isDefined(events) && angular.isArray(events.view)) { + var view = map.getView(); + angular.forEach(events.view, function(eventType) { + view.on(eventType, function(event) { + scope.$emit('openlayers.view.' + eventType, view, event); + }); + }); + } + }, + + detectLayerType: detectLayerType, + + createLayer: function(layer, projection, name) { + var oLayer; + var type = detectLayerType(layer); + var oSource = createSource(layer.source, projection); + if (!oSource) { + return; + } + + // Manage clustering + if ((type === 'Vector') && layer.clustering) { + oSource = new ol.source.Cluster({ + source: oSource, + distance: layer.clusteringDistance, + }); + } + + switch (type) { + case 'Image': + oLayer = new ol.layer.Image({ source: oSource }); + break; + case 'Tile': + oLayer = new ol.layer.Tile({ source: oSource }); + break; + case 'Heatmap': + oLayer = new ol.layer.Heatmap({ source: oSource }); + break; + case 'Vector': + oLayer = new ol.layer.Vector({ source: oSource }); + break; + } + + // set a layer name if given + if (isDefined(name)) { + oLayer.set('name', name); + } else if (isDefined(layer.name)) { + oLayer.set('name', layer.name); + } + + return oLayer; + }, + + createVectorLayer: function() { + return new ol.layer.Vector({ + source: new ol.source.Vector() + }); + }, + + notifyCenterUrlHashChanged: function(scope, center, search) { + if (center.centerUrlHash) { + var centerUrlHash = center.lat.toFixed(4) + ':' + center.lon.toFixed(4) + ':' + center.zoom; + if (!isDefined(search.c) || search.c !== centerUrlHash) { + scope.$emit('centerUrlHash', centerUrlHash); + } + } + }, + + getControlClasses: getControlClasses, + + detectControls: function(controls) { + var actualControls = {}; + var controlClasses = getControlClasses(); + + controls.forEach(function(control) { + for (var i in controlClasses) { + if (control instanceof controlClasses[i]) { + actualControls[i] = control; + } + } + }); + + return actualControls; + }, + + createFeature: function(data, viewProjection) { + var geometry; + + switch (data.type) { + case 'Polygon': + geometry = new ol.geom.Polygon(data.coords); + break; + default: + if (isDefined(data.coord) && data.projection === 'pixel') { + geometry = new ol.geom.Point(data.coord); + } else { + geometry = new ol.geom.Point([data.lon, data.lat]); + } + break; + } + + if (isDefined(data.projection) && data.projection !== 'pixel') { + geometry = geometry.transform(data.projection, viewProjection); + } + + var feature = new ol.Feature({ + geometry: geometry + }); + + if (isDefined(data.style)) { + var style = createStyle(data.style); + feature.setStyle(style); + } + return feature; + }, + + addLayerBeforeMarkers: addLayerBeforeMarkers, + + getGroup: getGroup, + + addLayerToGroup: function(layers, layer, name) { + var groupLayer = getGroup(layers, name); + + if (!isDefined(groupLayer)) { + groupLayer = createGroup(name); + addLayerBeforeMarkers(layers,groupLayer); + } + + layer.set('group', name); + addLayerBeforeMarkers(groupLayer.getLayers(), layer); + }, + + removeLayerFromGroup: function(layers, layer, name) { + var groupLayer = getGroup(layers, name); + layer.set('group'); + removeLayer(groupLayer.getLayers(), layer.index); + }, + + removeLayer: removeLayer, + + insertLayer: function(layers, index, layer) { + if (layers.getLength() < index) { + while (layers.getLength() < index) { + layers.push(null); + } + layer.index = index; + layers.push(layer); + } else { + layer.index = index; + layers.insertAt(layer.index, layer); + for (var i = index + 1; i < layers.getLength(); i++) { + var l = layers.item(i); + if (l === null) { + layers.removeAt(i); + break; + } else { + l.index = i; + } + } + } + }, + + createOverlay: function(element, pos) { + element.css('display', 'block'); + var ov = new ol.Overlay({ + position: pos, + element: element, + positioning: 'center-left' + }); + + return ov; + } + }; +}]); + +angular.module('openlayers-directive').factory('olMapDefaults', ["$q", "olHelpers", function($q, olHelpers) { + + var base64icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw' + + '7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGq' + + 'KII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR' + + '6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWV' + + 'MqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23' + + 'h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o' + + '+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzq' + + 'Bk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0g' + + 'pBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF' + + '3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAw' + + 'AhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5W' + + 'YnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRcha' + + 'h8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1E' + + 'IlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk' + + '4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/' + + 'tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdW' + + 'r7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0' + + 'ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIP' + + 'hP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmql' + + 'yvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsY' + + 'J7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/' + + 'WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIa' + + 'vznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV' + + '3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R' + + '3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDl' + + 'lwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQ' + + 'SCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92' + + 'H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GC' + + 'LVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjN' + + 'cNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg=='; + + var _getDefaults = function() { + return { + view: { + projection: 'EPSG:3857', + minZoom: undefined, + maxZoom: undefined, + rotation: 0, + extent: undefined + }, + center: { + lat: 0, + lon: 0, + zoom: 1, + autodiscover: false, + bounds: [], + centerUrlHash: false, + projection: 'EPSG:4326' + }, + styles: { + path: { + stroke: { + color: 'blue', + width: 8 + } + }, + marker: { + image: new ol.style.Icon({ + anchor: [0.5, 1], + anchorXUnits: 'fraction', + anchorYUnits: 'fraction', + opacity: 0.90, + src: base64icon + }) + } + }, + events: { + map: [], + markers: [], + layers: [] + }, + controls: { + attribution: true, + rotate: false, + zoom: true + }, + interactions: { + mouseWheelZoom: false + }, + renderer: 'canvas' + }; + }; + + var isDefined = olHelpers.isDefined; + var defaults = {}; + + // Get the _defaults dictionary, and override the properties defined by the user + return { + getDefaults: function(scope) { + if (!isDefined(scope)) { + for (var i in defaults) { + return defaults[i]; + } + } + return defaults[scope.$id]; + }, + + setDefaults: function(scope) { + var userDefaults = scope.defaults; + var scopeId = scope.$id; + var newDefaults = _getDefaults(); + + if (isDefined(userDefaults)) { + + if (isDefined(userDefaults.layers)) { + newDefaults.layers = angular.copy(userDefaults.layers); + } + + if (isDefined(userDefaults.controls)) { + newDefaults.controls = angular.copy(userDefaults.controls); + } + + if (isDefined(userDefaults.events)) { + newDefaults.events = angular.copy(userDefaults.events); + } + + if (isDefined(userDefaults.interactions)) { + newDefaults.interactions = angular.copy(userDefaults.interactions); + } + + if (isDefined(userDefaults.renderer)) { + newDefaults.renderer = userDefaults.renderer; + } + + if (isDefined(userDefaults.view)) { + newDefaults.view.maxZoom = userDefaults.view.maxZoom || newDefaults.view.maxZoom; + newDefaults.view.minZoom = userDefaults.view.minZoom || newDefaults.view.minZoom; + newDefaults.view.projection = userDefaults.view.projection || newDefaults.view.projection; + newDefaults.view.extent = userDefaults.view.extent || newDefaults.view.extent; + } + + if (isDefined(userDefaults.styles)) { + newDefaults.styles = angular.extend(newDefaults.styles, userDefaults.styles); + } + + } + + defaults[scopeId] = newDefaults; + return newDefaults; + } + }; +}]); + +})); \ No newline at end of file diff --git a/dist/angular-openlayers-directive.min.js b/dist/angular-openlayers-directive.min.js new file mode 100644 index 00000000..925988a4 --- /dev/null +++ b/dist/angular-openlayers-directive.min.js @@ -0,0 +1,31 @@ +/**! + * The MIT License + * + * Copyright (c) 2013 the angular-openlayers-directive Team, http://tombatossals.github.io/angular-openlayers-directive + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * angular-google-maps + * https://github.com/tombatossals/angular-openlayers-directive + * + * @authors https://github.com/tombatossals/angular-openlayers-directive/graphs/contributors + */ + +/*! angular-openlayers-directive 06-11-2015 */ +!function(a,b){"function"==typeof define&&define.amd?define(["ol"],function(c){return a.angularOpenlayersDirective=b(c)}):a.angularOpenlayersDirective=b(a.ol)}(this,function(a){angular.module("openlayers-directive",["ngSanitize"]).directive("openlayers",["$log","$q","$compile","olHelpers","olMapDefaults","olData",function(b,c,d,e,f,g){return{restrict:"EA",transclude:!0,replace:!0,scope:{center:"=olCenter",defaults:"=olDefaults",view:"=olView",events:"=olEvents"},template:'
',controller:["$scope",function(a){var b=c.defer();a.getMap=function(){return b.promise},a.setMap=function(a){b.resolve(a)},this.getOpenlayersScope=function(){return a}}],link:function(b,c,d){var h=e.isDefined,i=e.createLayer,j=e.setMapEvents,k=e.setViewEvents,l=e.createView,m=f.setDefaults(b);h(d.width)&&(isNaN(d.width)?c.css("width",d.width):c.css("width",d.width+"px")),h(d.height)&&(isNaN(d.height)?c.css("height",d.height):c.css("height",d.height+"px")),h(d.lat)&&(m.center.lat=parseFloat(d.lat)),h(d.lon)&&(m.center.lon=parseFloat(d.lon)),h(d.zoom)&&(m.center.zoom=parseFloat(d.zoom));var n=a.control.defaults(m.controls),o=a.interaction.defaults(m.interactions),p=l(m.view),q=new a.Map({target:c[0],controls:n,interactions:o,renderer:m.renderer,view:p});if(!d.customLayers){var r={type:"Tile",source:{type:"OSM"}},s=i(r,p.getProjection(),"default");q.addLayer(s),q.set("default",!0)}if(!h(d.olCenter)){var t=a.proj.transform([m.center.lon,m.center.lat],m.center.projection,p.getProjection());p.setCenter(t),p.setZoom(m.center.zoom)}j(m.events,q,b),k(m.events,q,b),b.setMap(q),g.setMap(q,d.id)}}}]),angular.module("openlayers-directive").directive("olCenter",["$log","$location","olMapDefaults","olHelpers",function(b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(f,g,h,i){var j=e.safeApply,k=e.isValidCenter,l=e.isDefined,m=e.isArray,n=e.isNumber,o=e.isSameCenterOnMap,p=e.setCenter,q=e.setZoom,r=i.getOpenlayersScope();r.getMap().then(function(f){var g=d.getDefaults(r),i=f.getView(),s=r.center;if(-1!==h.olCenter.search("-"))return b.error('[AngularJS - Openlayers] The "center" variable can\'t use a "-" on his key name: "'+h.center+'".'),void p(i,g.view.projection,g.center,f);l(s)||(s={}),k(s)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),s.lat=g.center.lat,s.lon=g.center.lon,s.zoom=g.center.zoom,s.projection=g.center.projection),s.projection||("pixel"!==g.view.projection?s.projection=g.center.projection:s.projection="pixel"),n(s.zoom)||(s.zoom=1),p(i,g.view.projection,s,f),i.setZoom(s.zoom);var t;if(s.centerUrlHash===!0){var u=function(){var a,b=c.search();if(l(b.c)){var d=b.c.split(":");3===d.length&&(a={lat:parseFloat(d[0]),lon:parseFloat(d[1]),zoom:parseInt(d[2],10)})}return a};t=u(),r.$on("$locationChangeSuccess",function(){var a=u();a&&!o(a,f)&&j(r,function(b){b.center.lat=a.lat,b.center.lon=a.lon,b.center.zoom=a.zoom})})}var v;r.$watchCollection("center",function(c){if(c){if(c.projection||(c.projection=g.center.projection),c.autodiscover)return v||(v=new a.Geolocation({projection:a.proj.get(c.projection)}),v.on("change",function(){if(c.autodiscover){var a=v.getPosition();j(r,function(b){b.center.lat=a[1],b.center.lon=a[0],b.center.zoom=12,b.center.autodiscover=!1,v.setTracking(!1)})}})),void v.setTracking(!0);k(c)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),c=g.center);var d=i.getCenter();if(d){if("pixel"===g.view.projection)return void i.setCenter(c.coord);var e=a.proj.transform(d,g.view.projection,c.projection);(e[1]!==c.lat||e[0]!==c.lon)&&p(i,g.view.projection,c,f)}i.getZoom()!==c.zoom&&q(i,c.zoom,f)}}),f.on("moveend",function(){j(r,function(b){if(l(b.center)){var d=f.getView().getCenter();if(b.center.zoom=i.getZoom(),"pixel"===g.view.projection)return void(b.center.coord=d);if(b.center){var h=a.proj.transform(d,g.view.projection,b.center.projection);if(b.center.lat=h[1],b.center.lon=h[0],e.notifyCenterUrlHashChanged(r,b.center,c.search()),m(b.center.bounds)){var j=i.calculateExtent(f.getSize()),k=b.center.projection,n=g.view.projection;b.center.bounds=a.proj.transformExtent(j,n,k)}}}})})})}}}]),angular.module("openlayers-directive").directive("olLayer",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olLayerProperties"},replace:!1,require:"^openlayers",link:function(a,b,e,f){var g=d.isDefined,h=d.equals,i=f.getOpenlayersScope(),j=d.createLayer,k=d.setVectorLayerEvents,l=d.detectLayerType,m=d.createStyle,n=d.isBoolean,o=d.addLayerBeforeMarkers,p=d.isNumber,q=d.insertLayer,r=d.removeLayer,s=d.addLayerToGroup,t=d.removeLayerFromGroup,u=d.getGroup;i.getMap().then(function(b){var d,f=b.getView().getProjection(),v=c.setDefaults(i),w=b.getLayers();if(a.$on("$destroy",function(){a.properties.group?t(w,d,a.properties.group):r(w,d.index),b.removeLayer(d)}),g(a.properties))a.$watch("properties",function(c,e){if(g(c.source)&&g(c.source.type)){if(!g(c.visible))return void(c.visible=!0);if(!g(c.opacity))return void(c.opacity=1);var i,x,y;if(g(d)){var z=function(a){return function(b){return b!==a}}(d);if(g(e)&&!h(c.source,e.source)){var A=d.index;y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),y.removeAt(A),d=j(c,f),d.set("group",x),g(d)&&(q(y,A,d),"Vector"===l(c)&&k(v.events,b,a,c.name))}(g(e)&&c.opacity!==e.opacity||z(d))&&(p(c.opacity)||p(parseFloat(c.opacity)))&&d.setOpacity(c.opacity),g(c.index)&&c.index!==d.index&&(y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),r(y,d.index),q(y,c.index,d)),g(c.group)&&c.group!==e.group&&(t(w,d,e.group),s(w,d,c.group)),(g(e)&&n(c.visible)&&c.visible!==e.visible||z(d))&&d.setVisible(c.visible),(g(c.style)&&!h(c.style,e.style)||z(d))&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}else d=j(c,f),g(c.group)?s(w,d,c.group):g(c.index)?q(w,c.index,d):o(w,d),"Vector"===l(c)&&k(v.events,b,a,c.name),n(c.visible)&&d.setVisible(c.visible),c.opacity&&d.setOpacity(c.opacity),angular.isArray(c.extent)&&d.setExtent(c.extent),c.style&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}},!0);else if(g(e.sourceType)&&g(e.sourceUrl)){var x={source:{url:e.sourceUrl,type:e.sourceType}};d=j(x,f,e.layerName),"Vector"===l(x)&&k(v.events,b,a,e.name),o(w,d)}})}}}]),angular.module("openlayers-directive").directive("olPath",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olGeomProperties"},require:"^openlayers",replace:!0,template:'',link:function(a,b,e,f){var g=d.isDefined,h=d.createFeature,i=d.createOverlay,j=d.createVectorLayer,k=d.insertLayer,l=d.removeLayer,m=f.getOpenlayersScope();m.getMap().then(function(d){var f=c.getDefaults(m),n=f.view.projection,o=j(),p=d.getLayers();if(k(p,p.getLength(),o),a.$on("$destroy",function(){l(p,o.index)}),g(e.coords)){var q=e.proj||"EPSG:4326",r=JSON.parse(e.coords),s={type:"Polygon",coords:r,projection:q,style:f.styles.path},t=h(s,n);if(o.getSource().addFeature(t),e.message){a.message=e.message;var u=t.getGeometry().getExtent(),v=i(b,u);d.addOverlay(v)}}else;})}}}]),angular.module("openlayers-directive").directive("olView",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(a,b,c,f){var g=f.getOpenlayersScope(),h=e.isNumber,i=e.safeApply,j=e.createView;g.getMap().then(function(a){var b=d.getDefaults(g),c=g.view;c.projection||(c.projection=b.view.projection),c.maxZoom||(c.maxZoom=b.view.maxZoom),c.minZoom||(c.minZoom=b.view.minZoom),c.rotation||(c.rotation=b.view.rotation);var e=j(c);a.setView(e),g.$watchCollection("view",function(a){h(a.rotation)&&e.setRotation(a.rotation)}),e.on("change:rotation",function(){i(g,function(b){b.view.rotation=a.getView().getRotation()})})})}}}]),angular.module("openlayers-directive").directive("olControl",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"E",scope:{properties:"=olControlProperties"},replace:!1,require:"^openlayers",link:function(a,b,c,d){var f,g,h=e.isDefined,i=d.getOpenlayersScope();i.getMap().then(function(b){var d=e.getControlClasses,i=d();return a.$on("$destroy",function(){b.removeControl(f)}),h(a.properties)&&h(a.properties.control)?(f=a.properties.control,void b.addControl(f)):void(c.name&&(h(a.properties)&&(g=a.properties),f=new i[c.name](g),b.addControl(f)))})}}}]),angular.module("openlayers-directive").directive("olMarker",["$log","$q","olMapDefaults","olHelpers",function(b,c,d,e){var f=function(){return{projection:"EPSG:4326",lat:0,lon:0,coord:[],show:!0,showOnMouseOver:!1,showOnMouseClick:!1,keepOneOverlayVisible:!1}},g=function(){function a(a){return b.map(function(a){return a.map}).indexOf(a)}var b=[];return{getInst:function(c,d){var f=a(d);if(-1===f){var g=e.createVectorLayer();g.set("markers",!0),d.addLayer(g),b.push({map:d,markerLayer:g,instScopes:[]}),f=b.length-1}return b[f].instScopes.push(c),b[f].markerLayer},deregisterScope:function(c,d){var e=a(d);if(-1===e)throw Error("This map has no markers");var f=b[e].instScopes,g=f.indexOf(c);if(-1===g)throw Error("Scope wan't registered");f.splice(g,1),f.length||(d.removeLayer(b[e].markerLayer),delete b[e])}}}();return{restrict:"E",scope:{lat:"=lat",lon:"=lon",label:"=label",properties:"=olMarkerProperties",style:"=olStyle"},transclude:!0,require:"^openlayers",replace:!0,template:'',link:function(c,h,i,j){var k=e.isDefined,l=j.getOpenlayersScope(),m=e.createFeature,n=e.createOverlay,o=h.find("ng-transclude").children().length>0;l.getMap().then(function(e){function j(b){var d=b.coordinate,f=e.getView().getProjection().getCode();if(d="pixel"===f?d.map(function(a){return parseInt(a,10)}):a.proj.transform(d,f,"EPSG:4326"),"pointerdown"===b.type){var g=e.forEachFeatureAtPixel(b.pixel,function(a){return a});if(x=g?g.get("marker"):null,!x||!x.draggable)return void(x=null);e.getTarget().style.cursor="pointer",w="pixel"===f?[d[0]-x.coord[0],d[1]-x.coord[1]]:[d[0]-x.lon,d[1]-x.lat],b.preventDefault()}else w&&x&&("pointerup"===b.type?(e.getTarget().style.cursor="",w=null,x=null,b.preventDefault()):"pointerdrag"===b.type&&(b.preventDefault(),c.$apply(function(){"pixel"===f?(x.coord[0]=d[0]-w[0],x.coord[1]=d[1]-w[1]):(x.lon=d[0]-w[0],x.lat=d[1]-w[1])})))}var p,q,r,s=g.getInst(c,e),t=f(),u=d.getDefaults(l),v=u.view.projection,w=null,x=null;return e.on("pointerdown",j),e.on("pointerup",j),e.on("pointerdrag",j),c.$on("$destroy",function(){s.getSource().removeFeature(r),k(p)&&e.removeOverlay(p),g.deregisterScope(c,e)}),k(c.properties)?void c.$watch("properties",function(d){if(e.getViewport().removeEventListener("mousemove",d.handleInteraction),e.getViewport().removeEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").removeEventListener("touchend",d.handleTapInteraction),e.getViewport().removeEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().removeEventListener("click",d.removeAllOverlays),d.handleInteraction=function(b){if(!d.label.show){var f=!1,g=e.getEventPixel(b),i=e.forEachFeatureAtPixel(g,function(a){return a}),j=!1;i===r&&(j=!0,f=!0,k(p)||(q="pixel"===t.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),!d.onClick||"click"!==b.type&&"touchend"!==b.type||c.$apply(function(){d.onClick.call(r,b,d)}),e.getTarget().style.cursor="pointer"),!f&&p&&(j=!0,e.removeOverlay(p),p=void 0,e.getTarget().style.cursor=""),j&&b.preventDefault()}},d.handleTapInteraction=function(){function a(){c=!0,b&&clearTimeout(b),b=setTimeout(function(){c=!1,b=null},500)}var b,c=!1;return e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchmove",a),function(){c||(d.handleInteraction.apply(null,arguments),a())}}(),d.showAtLeastOneOverlay=function(b){if(!d.label.show){var c=!1,f=e.getEventPixel(b),g=e.forEachFeatureAtPixel(f,function(a){return a}),i=!1;g===r&&(i=!0,c=!0,k(p)||(q="pixel"===t.projection?t.coord:a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),e.addOverlay(p)),e.getTarget().style.cursor="pointer"),!c&&p&&(i=!0,p=void 0,e.getTarget().style.cursor=""),i&&b.preventDefault()}},d.removeAllOverlays=function(a){angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),a.preventDefault()},k(r)){var f;if(f="pixel"===d.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,e.getView().getProjection()),!angular.equals(r.getGeometry().getCoordinates(),f)){var g=new a.geom.Point(f);r.setGeometry(g)}}else t.projection=d.projection?d.projection:t.projection,t.coord=d.coord?d.coord:t.coord,t.lat=d.lat?d.lat:t.lat,t.lon=d.lon?d.lon:t.lon,k(d.style)?t.style=d.style:t.style=u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",d),s.getSource().addFeature(r);k(p)&&e.removeOverlay(p),k(d.label)&&(c.message=d.label.message,(o||k(c.message)&&0!==c.message.length)&&(d.label&&d.label.show===!0&&(q="pixel"===t.projection?t.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),p&&d.label&&d.label.show===!1&&(e.removeOverlay(p),p=void 0),d.label&&d.label.show===!1&&d.label.showOnMouseOver&&e.getViewport().addEventListener("mousemove",d.handleInteraction),(d.label&&d.label.show===!1&&d.label.showOnMouseClick||d.onClick)&&(e.getViewport().addEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchend",d.handleTapInteraction)),d.label&&d.label.show===!1&&d.label.keepOneOverlayVisible&&(e.getViewport().addEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().addEventListener("click",d.removeAllOverlays))))},!0):(t.lat=c.lat?c.lat:t.lat,t.lon=c.lon?c.lon:t.lon,t.message=i.message,t.style=c.style?c.style:u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",c),s.getSource().addFeature(r),void((t.message||o)&&(c.message=i.message,q=a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),e.addOverlay(p))))})}}}]),angular.module("openlayers-directive").service("olData",["$log","$q","olHelpers",function(a,b,c){var d=c.obtainEffectiveMapId,e={},f=function(a,b){var c=d(a,b);a[c].resolvedDefer=!0},g=function(a,c){var e,f=d(a,c);return angular.isDefined(a[f])&&a[f].resolvedDefer!==!0?e=a[f].defer:(e=b.defer(),a[f]={defer:e,resolvedDefer:!1}),e},h=function(a,b){var c,e=d(a,b);return c=angular.isDefined(a[e])&&a[e].resolvedDefer!==!1?a[e].defer:g(a,b)};this.setMap=function(a,b){var c=g(e,b);c.resolve(a),f(e,b)},this.getMap=function(a){var b=h(e,a);return b.promise}}]),angular.module("openlayers-directive").factory("olHelpers",["$q","$log","$http",function(b,c,d){var e=function(a){return angular.isDefined(a)},f=function(a){return angular.isDefined(a)&&null!==a},g=function(a,b,c){a.on(b,function(d){var e=d.coordinate,f=a.getView().getProjection().getCode();"pixel"===f&&(e=e.map(function(a){return parseInt(a,10)})),c.$emit("openlayers.map."+b,{coord:e,projection:f,event:d})})},h=["Road","Aerial","AerialWithLabels","collinsBart","ordnanceSurvey"],i=function(){return{attribution:a.control.Attribution,fullscreen:a.control.FullScreen,mouseposition:a.control.MousePosition,rotate:a.control.Rotate,scaleline:a.control.ScaleLine,zoom:a.control.Zoom,zoomslider:a.control.ZoomSlider,zoomtoextent:a.control.ZoomToExtent}},j=["osm","sat","hyb"],k=["World_Imagery","World_Street_Map","World_Topo_Map","World_Physical_Map","World_Terrain_Base","Ocean_Basemap","NatGeo_World_Map"],l={style:a.style.Style,fill:a.style.Fill,stroke:a.style.Stroke,circle:a.style.Circle,icon:a.style.Icon,image:a.style.Image,regularshape:a.style.RegularShape,text:a.style.Text},m=function(a,b){return b&&a instanceof b?a:b?new b(a):a},n=function x(a,b){var c;if(b?c=a[b]:(b="style",c=a),"style"===b&&a instanceof Function)return a;if(!(c instanceof Object))return c;var d;if("[object Object]"===Object.prototype.toString.call(c)){d={};var e=l[b];if(e&&c instanceof e)return c;Object.getOwnPropertyNames(c).forEach(function(a,f,g){var h=l[a];return e&&h&&h.prototype instanceof l[b]?(console.assert(1===g.length,"Extra parameters for "+b),d=x(c,a),m(d,h)):(d[a]=x(c,a),void("text"!==a&&"string"!=typeof d[a]&&(d[a]=m(d[a],l[a]))))})}else d=c;return m(d,l[b])},o=function(a){if(a.type)return a.type;switch(a.source.type){case"ImageWMS":return"Image";case"ImageStatic":return"Image";case"GeoJSON":case"JSONP":case"TopoJSON":case"KML":case"TileVector":return"Vector";default:return"Tile"}},p=function(b){var d;switch(b.projection){case"pixel":if(!e(b.extent))return void c.error("[AngularJS - Openlayers] - You must provide the extent of the image if using pixel projection");d=new a.proj.Projection({code:"pixel",units:"pixels",extent:b.extent});break;default:d=new a.proj.get(b.projection)}return d},q=function(a){return-1!==["watercolor","terrain","toner"].indexOf(a)},r=function(b,f){var g;switch(b.type){case"MapBox":if(!b.mapId||!b.accessToken)return void c.error("[AngularJS - Openlayers] - MapBox layer requires the map id and the access token");var i="http://api.tiles.mapbox.com/v4/"+b.mapId+"/{z}/{x}/{y}.png?access_token="+b.accessToken,l=window.devicePixelRatio;l>1&&(i=i.replace(".png","@2x.png")),g=new a.source.XYZ({url:i,attributions:s(b),tilePixelRatio:l>1?2:1,wrapX:b.wrapX===!0?1:0});break;case"ImageWMS":b.url&&b.params||c.error("[AngularJS - Openlayers] - ImageWMS Layer needs valid server url and params properties"),g=new a.source.ImageWMS({url:b.url,attributions:s(b),crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,wrapX:b.wrapX?0:1});break;case"TileWMS":(b.url||b.urls)&&b.params||c.error("[AngularJS - Openlayers] - TileWMS Layer needs valid url (or urls) and params properties");var m={crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,attributions:s(b),wrapX:b.wrapX?0:1};b.url&&(m.url=b.url),b.urls&&(m.urls=b.urls),g=new a.source.TileWMS(m);break;case"WMTS":(b.url||b.urls)&&b.tileGrid||c.error("[AngularJS - Openlayers] - WMTS Layer needs valid url (or urls) and tileGrid properties");var n={projection:f,layer:b.layer,attributions:s(b),matrixSet:"undefined"===b.matrixSet?f:b.matrixSet,format:"undefined"===b.format?"image/jpeg":b.format,requestEncoding:"undefined"===b.requestEncoding?"KVP":b.requestEncoding,tileGrid:new a.tilegrid.WMTS({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions,matrixIds:b.tileGrid.matrixIds}),wrapX:b.wrapX?0:1};e(b.url)&&(n.url=b.url),e(b.urls)&&(n.urls=b.urls),g=new a.source.WMTS(n);break;case"OSM":g=new a.source.OSM({attributions:s(b),wrapX:b.wrapX===!0?1:0}),b.url&&g.setUrl(b.url);break;case"BingMaps":if(!b.key)return void c.error("[AngularJS - Openlayers] - You need an API key to show the Bing Maps.");var o={key:b.key,attributions:s(b),imagerySet:b.imagerySet?b.imagerySet:h[0],culture:b.culture,wrapX:b.wrapX===!0?1:0};b.maxZoom&&(o.maxZoom=b.maxZoom),g=new a.source.BingMaps(o);break;case"MapQuest":if(!b.layer||-1===j.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - MapQuest layers needs a valid 'layer' property.");g=new a.source.MapQuest({attributions:s(b),layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"EsriBaseMaps":if(!b.layer||-1===k.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - ESRI layers needs a valid 'layer' property.");var p="http://services.arcgisonline.com/ArcGIS/rest/services/",r=p+b.layer+"/MapServer/tile/{z}/{y}/{x}";g=new a.source.XYZ({attributions:s(b),url:r,wrapX:b.wrapX===!0?1:0});break;case"GeoJSON":if(!b.geojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a geojson property to add a GeoJSON layer.");if(e(b.url))g=new a.source.Vector({format:new a.format.GeoJSON,url:b.url,wrapX:b.wrapX===!0?1:0});else{g=new a.source.Vector;var t=f;e(b.geojson.projection)&&(t=b.geojson.projection);var u=new a.format.GeoJSON,v=u.readFeatures(b.geojson.object,{featureProjection:t});g.addFeatures(v)}break;case"JSONP":if(!b.url)return void c.error("[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.");e(b.url)&&(g=new a.source.Vector({format:new a.format.GeoJSON,loader:function(){var a=b.url+"&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK";d.jsonp(a,{cache:b.cache}).success(function(a){g.addFeatures(g.readFeatures(a))}).error(function(a){c(a)})},wrapX:b.wrapX===!0?1:0}));break;case"TopoJSON":if(!b.topojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a topojson property to add a TopoJSON layer.");g=b.url?new a.source.Vector({format:new a.format.TopoJSON,url:b.url,wrapX:b.wrapX===!0?1:0}):new a.source.Vector(angular.extend(b.topojson,{format:new a.format.TopoJSON,wrapX:b.wrapX===!0?1:0}));break;case"TileJSON":g=new a.source.TileJSON({url:b.url,attributions:s(b),crossOrigin:"anonymous",wrapX:b.wrapX===!0?1:0});break;case"TileVector":b.url&&b.format||c.error("[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties"),g=new a.source.TileVector({url:b.url,projection:f,attributions:s(b),format:b.format,tileGrid:new a.tilegrid.createXYZ({maxZoom:b.maxZoom||19}),wrapX:b.wrapX===!0?1:0});break;case"TileTMS":b.url&&b.tileGrid||c.error("[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties"),g=new a.source.TileImage({url:b.url,maxExtent:b.maxExtent,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=a[2];if(0>d||0>e)return"";var f=b.url+c+"/"+d+"/"+e+".png";return f},wrapX:b.wrapX===!0?1:0});break;case"TileImage":g=new a.source.TileImage({url:b.url,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=-a[2]-1,f=b.url.replace("{z}",c.toString()).replace("{x}",d.toString()).replace("{y}",e.toString());return f},wrapX:b.wrapX===!0?1:0});break;case"KML":var w=b.extractStyles||!1;g=new a.source.Vector({url:b.url,format:new a.format.KML,radius:b.radius,extractStyles:w,wrapX:b.wrapX===!0?1:0});break;case"Stamen":if(!b.layer||!q(b.layer))return void c.error("[AngularJS - Openlayers] - You need a valid Stamen layer.");g=new a.source.Stamen({layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"ImageStatic":if(!b.url||!angular.isArray(b.imageSize)||2!==b.imageSize.length)return void c.error("[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.");g=new a.source.ImageStatic({url:b.url,attributions:s(b),imageSize:b.imageSize,projection:f,imageExtent:f.getExtent(),imageLoadFunction:b.imageLoadFunction,wrapX:b.wrapX===!0?1:0});break;case"XYZ":b.url||c.error("[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties"),g=new a.source.XYZ({url:b.url,attributions:s(b),minZoom:b.minZoom,maxZoom:b.maxZoom,wrapX:b.wrapX===!0?1:0})}return g||c.warn('[AngularJS - Openlayers] - No source could be found for type "'+b.type+'"'),g},s=function(b){var c=[];return e(b.attribution)&&c.unshift(new a.Attribution({html:b.attribution})),c},t=function(b){var c=new a.layer.Group;return c.set("name",b),c},u=function(b,c){var d;return angular.forEach(b,function(b){return b instanceof a.layer.Group&&b.get("name")===c?void(d=b):void 0}),d},v=function(a,b){for(var c,d=0;d',controller:["$scope",function(a){var b=c.defer();a.getMap=function(){return b.promise},a.setMap=function(a){b.resolve(a)},this.getOpenlayersScope=function(){return a}}],link:function(b,c,d){var h=e.isDefined,i=e.createLayer,j=e.setMapEvents,k=e.setViewEvents,l=e.createView,m=f.setDefaults(b);h(d.width)&&(isNaN(d.width)?c.css("width",d.width):c.css("width",d.width+"px")),h(d.height)&&(isNaN(d.height)?c.css("height",d.height):c.css("height",d.height+"px")),h(d.lat)&&(m.center.lat=parseFloat(d.lat)),h(d.lon)&&(m.center.lon=parseFloat(d.lon)),h(d.zoom)&&(m.center.zoom=parseFloat(d.zoom));var n=a.control.defaults(m.controls),o=a.interaction.defaults(m.interactions),p=l(m.view),q=new a.Map({target:c[0],controls:n,interactions:o,renderer:m.renderer,view:p});if(!d.customLayers){var r={type:"Tile",source:{type:"OSM"}},s=i(r,p.getProjection(),"default");q.addLayer(s),q.set("default",!0)}if(!h(d.olCenter)){var t=a.proj.transform([m.center.lon,m.center.lat],m.center.projection,p.getProjection());p.setCenter(t),p.setZoom(m.center.zoom)}j(m.events,q,b),k(m.events,q,b),b.setMap(q),g.setMap(q,d.id)}}}]),angular.module("openlayers-directive").directive("olCenter",["$log","$location","olMapDefaults","olHelpers",function(b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(f,g,h,i){var j=e.safeApply,k=e.isValidCenter,l=e.isDefined,m=e.isArray,n=e.isNumber,o=e.isSameCenterOnMap,p=e.setCenter,q=e.setZoom,r=i.getOpenlayersScope();r.getMap().then(function(f){var g=d.getDefaults(r),i=f.getView(),s=r.center;if(-1!==h.olCenter.search("-"))return b.error('[AngularJS - Openlayers] The "center" variable can\'t use a "-" on his key name: "'+h.center+'".'),void p(i,g.view.projection,g.center,f);l(s)||(s={}),k(s)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),s.lat=g.center.lat,s.lon=g.center.lon,s.zoom=g.center.zoom,s.projection=g.center.projection),s.projection||("pixel"!==g.view.projection?s.projection=g.center.projection:s.projection="pixel"),n(s.zoom)||(s.zoom=1),p(i,g.view.projection,s,f),i.setZoom(s.zoom);var t;if(s.centerUrlHash===!0){var u=function(){var a,b=c.search();if(l(b.c)){var d=b.c.split(":");3===d.length&&(a={lat:parseFloat(d[0]),lon:parseFloat(d[1]),zoom:parseInt(d[2],10)})}return a};t=u(),r.$on("$locationChangeSuccess",function(){var a=u();a&&!o(a,f)&&j(r,function(b){b.center.lat=a.lat,b.center.lon=a.lon,b.center.zoom=a.zoom})})}var v;r.$watchCollection("center",function(c){if(c){if(c.projection||(c.projection=g.center.projection),c.autodiscover)return v||(v=new a.Geolocation({projection:a.proj.get(c.projection)}),v.on("change",function(){if(c.autodiscover){var a=v.getPosition();j(r,function(b){b.center.lat=a[1],b.center.lon=a[0],b.center.zoom=12,b.center.autodiscover=!1,v.setTracking(!1)})}})),void v.setTracking(!0);k(c)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),c=g.center);var d=i.getCenter();if(d){if("pixel"===g.view.projection)return void i.setCenter(c.coord);var e=a.proj.transform(d,g.view.projection,c.projection);(e[1]!==c.lat||e[0]!==c.lon)&&p(i,g.view.projection,c,f)}i.getZoom()!==c.zoom&&q(i,c.zoom,f)}}),f.on("moveend",function(){j(r,function(b){if(l(b.center)){var d=f.getView().getCenter();if(b.center.zoom=i.getZoom(),"pixel"===g.view.projection)return void(b.center.coord=d);if(b.center){var h=a.proj.transform(d,g.view.projection,b.center.projection);if(b.center.lat=h[1],b.center.lon=h[0],e.notifyCenterUrlHashChanged(r,b.center,c.search()),m(b.center.bounds)){var j=i.calculateExtent(f.getSize()),k=b.center.projection,n=g.view.projection;b.center.bounds=a.proj.transformExtent(j,n,k)}}}})})})}}}]),angular.module("openlayers-directive").directive("olLayer",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olLayerProperties"},replace:!1,require:"^openlayers",link:function(a,b,e,f){var g=d.isDefined,h=d.equals,i=f.getOpenlayersScope(),j=d.createLayer,k=d.setVectorLayerEvents,l=d.detectLayerType,m=d.createStyle,n=d.isBoolean,o=d.addLayerBeforeMarkers,p=d.isNumber,q=d.insertLayer,r=d.removeLayer,s=d.addLayerToGroup,t=d.removeLayerFromGroup,u=d.getGroup;i.getMap().then(function(b){var d,f=b.getView().getProjection(),v=c.setDefaults(i),w=b.getLayers();if(a.$on("$destroy",function(){a.properties.group?t(w,d,a.properties.group):r(w,d.index),b.removeLayer(d)}),g(a.properties))a.$watch("properties",function(c,e){if(g(c.source)&&g(c.source.type)){if(!g(c.visible))return void(c.visible=!0);if(!g(c.opacity))return void(c.opacity=1);var i,x,y;if(g(d)){var z=function(a){return function(b){return b!==a}}(d);if(g(e)&&!h(c.source,e.source)){var A=d.index;y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),y.removeAt(A),d=j(c,f),d.set("group",x),g(d)&&(q(y,A,d),"Vector"===l(c)&&k(v.events,b,a,c.name))}(g(e)&&c.opacity!==e.opacity||z(d))&&(p(c.opacity)||p(parseFloat(c.opacity)))&&d.setOpacity(c.opacity),g(c.index)&&c.index!==d.index&&(y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),r(y,d.index),q(y,c.index,d)),g(c.group)&&c.group!==e.group&&(t(w,d,e.group),s(w,d,c.group)),(g(e)&&n(c.visible)&&c.visible!==e.visible||z(d))&&d.setVisible(c.visible),(g(c.style)&&!h(c.style,e.style)||z(d))&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}else d=j(c,f),g(c.group)?s(w,d,c.group):g(c.index)?q(w,c.index,d):o(w,d),"Vector"===l(c)&&k(v.events,b,a,c.name),n(c.visible)&&d.setVisible(c.visible),c.opacity&&d.setOpacity(c.opacity),angular.isArray(c.extent)&&d.setExtent(c.extent),c.style&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}},!0);else if(g(e.sourceType)&&g(e.sourceUrl)){var x={source:{url:e.sourceUrl,type:e.sourceType}};d=j(x,f,e.layerName),"Vector"===l(x)&&k(v.events,b,a,e.name),o(w,d)}})}}}]),angular.module("openlayers-directive").directive("olPath",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olGeomProperties"},require:"^openlayers",replace:!0,template:'',link:function(a,b,e,f){var g=d.isDefined,h=d.createFeature,i=d.createOverlay,j=d.createVectorLayer,k=d.insertLayer,l=d.removeLayer,m=f.getOpenlayersScope();m.getMap().then(function(d){var f=c.getDefaults(m),n=f.view.projection,o=j(),p=d.getLayers();if(k(p,p.getLength(),o),a.$on("$destroy",function(){l(p,o.index)}),g(e.coords)){var q=e.proj||"EPSG:4326",r=JSON.parse(e.coords),s={type:"Polygon",coords:r,projection:q,style:f.styles.path},t=h(s,n);if(o.getSource().addFeature(t),e.message){a.message=e.message;var u=t.getGeometry().getExtent(),v=i(b,u);d.addOverlay(v)}}else;})}}}]),angular.module("openlayers-directive").directive("olView",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(a,b,c,f){var g=f.getOpenlayersScope(),h=e.isNumber,i=e.safeApply,j=e.createView;g.getMap().then(function(a){var b=d.getDefaults(g),c=g.view;c.projection||(c.projection=b.view.projection),c.maxZoom||(c.maxZoom=b.view.maxZoom),c.minZoom||(c.minZoom=b.view.minZoom),c.rotation||(c.rotation=b.view.rotation);var e=j(c);a.setView(e),g.$watchCollection("view",function(a){h(a.rotation)&&e.setRotation(a.rotation)}),e.on("change:rotation",function(){i(g,function(b){b.view.rotation=a.getView().getRotation()})})})}}}]),angular.module("openlayers-directive").directive("olControl",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"E",scope:{properties:"=olControlProperties"},replace:!1,require:"^openlayers",link:function(a,b,c,d){var f,g,h=e.isDefined,i=d.getOpenlayersScope();i.getMap().then(function(b){var d=e.getControlClasses,i=d();return a.$on("$destroy",function(){b.removeControl(f)}),h(a.properties)&&h(a.properties.control)?(f=a.properties.control,void b.addControl(f)):void(c.name&&(h(a.properties)&&(g=a.properties),f=new i[c.name](g),b.addControl(f)))})}}}]),angular.module("openlayers-directive").directive("olMarker",["$log","$q","olMapDefaults","olHelpers",function(b,c,d,e){var f=function(){return{projection:"EPSG:4326",lat:0,lon:0,coord:[],show:!0,showOnMouseOver:!1,showOnMouseClick:!1,keepOneOverlayVisible:!1}},g=function(){function a(a){return b.map(function(a){return a.map}).indexOf(a)}var b=[];return{getInst:function(c,d){var f=a(d);if(-1===f){var g=e.createVectorLayer();g.set("markers",!0),d.addLayer(g),b.push({map:d,markerLayer:g,instScopes:[]}),f=b.length-1}return b[f].instScopes.push(c),b[f].markerLayer},deregisterScope:function(c,d){var e=a(d);if(-1===e)throw Error("This map has no markers");var f=b[e].instScopes,g=f.indexOf(c);if(-1===g)throw Error("Scope wan't registered");f.splice(g,1),f.length||(d.removeLayer(b[e].markerLayer),delete b[e])}}}();return{restrict:"E",scope:{lat:"=lat",lon:"=lon",label:"=label",properties:"=olMarkerProperties",style:"=olStyle"},transclude:!0,require:"^openlayers",replace:!0,template:'',link:function(c,h,i,j){var k=e.isDefined,l=j.getOpenlayersScope(),m=e.createFeature,n=e.createOverlay,o=h.find("ng-transclude").children().length>0;l.getMap().then(function(e){function j(b){var d=b.coordinate,f=e.getView().getProjection().getCode();if(d="pixel"===f?d.map(function(a){return parseInt(a,10)}):a.proj.transform(d,f,"EPSG:4326"),"pointerdown"===b.type){var g=e.forEachFeatureAtPixel(b.pixel,function(a){return a});if(x=g?g.get("marker"):null,!x||!x.draggable)return void(x=null);e.getTarget().style.cursor="pointer",w="pixel"===f?[d[0]-x.coord[0],d[1]-x.coord[1]]:[d[0]-x.lon,d[1]-x.lat],b.preventDefault()}else w&&x&&("pointerup"===b.type?(e.getTarget().style.cursor="",w=null,x=null,b.preventDefault()):"pointerdrag"===b.type&&(b.preventDefault(),c.$apply(function(){"pixel"===f?(x.coord[0]=d[0]-w[0],x.coord[1]=d[1]-w[1]):(x.lon=d[0]-w[0],x.lat=d[1]-w[1])})))}var p,q,r,s=g.getInst(c,e),t=f(),u=d.getDefaults(l),v=u.view.projection,w=null,x=null;return e.on("pointerdown",j),e.on("pointerup",j),e.on("pointerdrag",j),c.$on("$destroy",function(){s.getSource().removeFeature(r),k(p)&&e.removeOverlay(p),g.deregisterScope(c,e)}),k(c.properties)?void c.$watch("properties",function(d){if(e.getViewport().removeEventListener("mousemove",d.handleInteraction),e.getViewport().removeEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").removeEventListener("touchend",d.handleTapInteraction),e.getViewport().removeEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().removeEventListener("click",d.removeAllOverlays),d.handleInteraction=function(b){if(!d.label.show){var f=!1,g=e.getEventPixel(b),i=e.forEachFeatureAtPixel(g,function(a){return a}),j=!1;i===r&&(j=!0,f=!0,k(p)||(q="pixel"===t.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),!d.onClick||"click"!==b.type&&"touchend"!==b.type||c.$apply(function(){d.onClick.call(r,b,d)}),e.getTarget().style.cursor="pointer"),!f&&p&&(j=!0,e.removeOverlay(p),p=void 0,e.getTarget().style.cursor=""),j&&b.preventDefault()}},d.handleTapInteraction=function(){function a(){c=!0,b&&clearTimeout(b),b=setTimeout(function(){c=!1,b=null},500)}var b,c=!1;return e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchmove",a),function(){c||(d.handleInteraction.apply(null,arguments),a())}}(),d.showAtLeastOneOverlay=function(b){if(!d.label.show){var c=!1,f=e.getEventPixel(b),g=e.forEachFeatureAtPixel(f,function(a){return a}),i=!1;g===r&&(i=!0,c=!0,k(p)||(q="pixel"===t.projection?t.coord:a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),e.addOverlay(p)),e.getTarget().style.cursor="pointer"),!c&&p&&(i=!0,p=void 0,e.getTarget().style.cursor=""),i&&b.preventDefault()}},d.removeAllOverlays=function(a){angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),a.preventDefault()},k(r)){var f;if(f="pixel"===d.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,e.getView().getProjection()),!angular.equals(r.getGeometry().getCoordinates(),f)){var g=new a.geom.Point(f);r.setGeometry(g)}}else t.projection=d.projection?d.projection:t.projection,t.coord=d.coord?d.coord:t.coord,t.lat=d.lat?d.lat:t.lat,t.lon=d.lon?d.lon:t.lon,k(d.style)?t.style=d.style:t.style=u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",d),s.getSource().addFeature(r);k(p)&&e.removeOverlay(p),k(d.label)&&(c.message=d.label.message,(o||k(c.message)&&0!==c.message.length)&&(d.label&&d.label.show===!0&&(q="pixel"===t.projection?t.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),p&&d.label&&d.label.show===!1&&(e.removeOverlay(p),p=void 0),d.label&&d.label.show===!1&&d.label.showOnMouseOver&&e.getViewport().addEventListener("mousemove",d.handleInteraction),(d.label&&d.label.show===!1&&d.label.showOnMouseClick||d.onClick)&&(e.getViewport().addEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchend",d.handleTapInteraction)),d.label&&d.label.show===!1&&d.label.keepOneOverlayVisible&&(e.getViewport().addEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().addEventListener("click",d.removeAllOverlays))))},!0):(t.lat=c.lat?c.lat:t.lat,t.lon=c.lon?c.lon:t.lon,t.message=i.message,t.style=c.style?c.style:u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",c),s.getSource().addFeature(r),void((t.message||o)&&(c.message=i.message,q=a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),e.addOverlay(p))))})}}}]),angular.module("openlayers-directive").service("olData",["$log","$q","olHelpers",function(a,b,c){var d=c.obtainEffectiveMapId,e={},f=function(a,b){var c=d(a,b);a[c].resolvedDefer=!0},g=function(a,c){var e,f=d(a,c);return angular.isDefined(a[f])&&a[f].resolvedDefer!==!0?e=a[f].defer:(e=b.defer(),a[f]={defer:e,resolvedDefer:!1}),e},h=function(a,b){var c,e=d(a,b);return c=angular.isDefined(a[e])&&a[e].resolvedDefer!==!1?a[e].defer:g(a,b)};this.setMap=function(a,b){var c=g(e,b);c.resolve(a),f(e,b)},this.getMap=function(a){var b=h(e,a);return b.promise}}]),angular.module("openlayers-directive").factory("olHelpers",["$q","$log","$http",function(b,c,d){var e=function(a){return angular.isDefined(a)},f=function(a){return angular.isDefined(a)&&null!==a},g=function(a,b,c){a.on(b,function(d){var e=d.coordinate,f=a.getView().getProjection().getCode();"pixel"===f&&(e=e.map(function(a){return parseInt(a,10)})),c.$emit("openlayers.map."+b,{coord:e,projection:f,event:d})})},h=["Road","Aerial","AerialWithLabels","collinsBart","ordnanceSurvey"],i=function(){return{attribution:a.control.Attribution,fullscreen:a.control.FullScreen,mouseposition:a.control.MousePosition,rotate:a.control.Rotate,scaleline:a.control.ScaleLine,zoom:a.control.Zoom,zoomslider:a.control.ZoomSlider,zoomtoextent:a.control.ZoomToExtent}},j=["osm","sat","hyb"],k=["World_Imagery","World_Street_Map","World_Topo_Map","World_Physical_Map","World_Terrain_Base","Ocean_Basemap","NatGeo_World_Map"],l={style:a.style.Style,fill:a.style.Fill,stroke:a.style.Stroke,circle:a.style.Circle,icon:a.style.Icon,image:a.style.Image,regularshape:a.style.RegularShape,text:a.style.Text},m=function(a,b){return b&&a instanceof b?a:b?new b(a):a},n=function x(a,b){var c;if(b?c=a[b]:(b="style",c=a),"style"===b&&a instanceof Function)return a;if(!(c instanceof Object))return c;var d;if("[object Object]"===Object.prototype.toString.call(c)){d={};var e=l[b];if(e&&c instanceof e)return c;Object.getOwnPropertyNames(c).forEach(function(a,f,g){var h=l[a];return e&&h&&h.prototype instanceof l[b]?(console.assert(1===g.length,"Extra parameters for "+b),d=x(c,a),m(d,h)):(d[a]=x(c,a),void("text"!==a&&"string"!=typeof d[a]&&(d[a]=m(d[a],l[a]))))})}else d=c;return m(d,l[b])},o=function(a){if(a.type)return a.type;switch(a.source.type){case"ImageWMS":return"Image";case"ImageStatic":return"Image";case"GeoJSON":case"JSONP":case"TopoJSON":case"KML":case"TileVector":return"Vector";default:return"Tile"}},p=function(b){var d;switch(b.projection){case"pixel":if(!e(b.extent))return void c.error("[AngularJS - Openlayers] - You must provide the extent of the image if using pixel projection");d=new a.proj.Projection({code:"pixel",units:"pixels",extent:b.extent});break;default:d=new a.proj.get(b.projection)}return d},q=function(a){return-1!==["watercolor","terrain","toner"].indexOf(a)},r=function(b,f){var g;switch(b.type){case"MapBox":if(!b.mapId||!b.accessToken)return void c.error("[AngularJS - Openlayers] - MapBox layer requires the map id and the access token");var i="http://api.tiles.mapbox.com/v4/"+b.mapId+"/{z}/{x}/{y}.png?access_token="+b.accessToken,l=window.devicePixelRatio;l>1&&(i=i.replace(".png","@2x.png")),g=new a.source.XYZ({url:i,attributions:s(b),tilePixelRatio:l>1?2:1,wrapX:b.wrapX===!0?1:0});break;case"ImageWMS":b.url&&b.params||c.error("[AngularJS - Openlayers] - ImageWMS Layer needs valid server url and params properties"),g=new a.source.ImageWMS({url:b.url,attributions:s(b),crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,wrapX:b.wrapX?0:1});break;case"TileWMS":(b.url||b.urls)&&b.params||c.error("[AngularJS - Openlayers] - TileWMS Layer needs valid url (or urls) and params properties");var m={crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,attributions:s(b),wrapX:b.wrapX?0:1};b.url&&(m.url=b.url),b.urls&&(m.urls=b.urls),g=new a.source.TileWMS(m);break;case"WMTS":(b.url||b.urls)&&b.tileGrid||c.error("[AngularJS - Openlayers] - WMTS Layer needs valid url (or urls) and tileGrid properties");var n={projection:f,layer:b.layer,attributions:s(b),matrixSet:"undefined"===b.matrixSet?f:b.matrixSet,format:"undefined"===b.format?"image/jpeg":b.format,requestEncoding:"undefined"===b.requestEncoding?"KVP":b.requestEncoding,tileGrid:new a.tilegrid.WMTS({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions,matrixIds:b.tileGrid.matrixIds}),wrapX:b.wrapX?0:1};e(b.url)&&(n.url=b.url),e(b.urls)&&(n.urls=b.urls),g=new a.source.WMTS(n);break;case"OSM":g=new a.source.OSM({attributions:s(b),wrapX:b.wrapX===!0?1:0}),b.url&&g.setUrl(b.url);break;case"BingMaps":if(!b.key)return void c.error("[AngularJS - Openlayers] - You need an API key to show the Bing Maps.");var o={key:b.key,attributions:s(b),imagerySet:b.imagerySet?b.imagerySet:h[0],culture:b.culture,wrapX:b.wrapX===!0?1:0};b.maxZoom&&(o.maxZoom=b.maxZoom),g=new a.source.BingMaps(o);break;case"MapQuest":if(!b.layer||-1===j.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - MapQuest layers needs a valid 'layer' property.");g=new a.source.MapQuest({attributions:s(b),layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"EsriBaseMaps":if(!b.layer||-1===k.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - ESRI layers needs a valid 'layer' property.");var p="http://services.arcgisonline.com/ArcGIS/rest/services/",r=p+b.layer+"/MapServer/tile/{z}/{y}/{x}";g=new a.source.XYZ({attributions:s(b),url:r,wrapX:b.wrapX===!0?1:0});break;case"GeoJSON":if(!b.geojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a geojson property to add a GeoJSON layer.");if(e(b.url))g=new a.source.Vector({format:new a.format.GeoJSON,url:b.url,wrapX:b.wrapX===!0?1:0});else{g=new a.source.Vector;var t=f;e(b.geojson.projection)&&(t=b.geojson.projection);var u=new a.format.GeoJSON,v=u.readFeatures(b.geojson.object,{featureProjection:t});g.addFeatures(v)}break;case"JSONP":if(!b.url)return void c.error("[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.");e(b.url)&&(g=new a.source.Vector({format:new a.format.GeoJSON,loader:function(){var a=b.url+"&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK";d.jsonp(a,{cache:b.cache}).success(function(a){g.addFeatures(g.readFeatures(a))}).error(function(a){c(a)})},wrapX:b.wrapX===!0?1:0}));break;case"TopoJSON":if(!b.topojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a topojson property to add a TopoJSON layer.");g=b.url?new a.source.Vector({format:new a.format.TopoJSON,url:b.url,wrapX:b.wrapX===!0?1:0}):new a.source.Vector(angular.extend(b.topojson,{format:new a.format.TopoJSON,wrapX:b.wrapX===!0?1:0}));break;case"TileJSON":g=new a.source.TileJSON({url:b.url,attributions:s(b),crossOrigin:"anonymous",wrapX:b.wrapX===!0?1:0});break;case"TileVector":b.url&&b.format||c.error("[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties"),g=new a.source.TileVector({url:b.url,projection:f,attributions:s(b),format:b.format,tileGrid:new a.tilegrid.createXYZ({maxZoom:b.maxZoom||19}),wrapX:b.wrapX===!0?1:0});break;case"TileTMS":b.url&&b.tileGrid||c.error("[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties"),g=new a.source.TileImage({url:b.url,maxExtent:b.maxExtent,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=a[2];if(0>d||0>e)return"";var f=b.url+c+"/"+d+"/"+e+".png";return f},wrapX:b.wrapX===!0?1:0});break;case"TileImage":g=new a.source.TileImage({url:b.url,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=-a[2]-1,f=b.url.replace("{z}",c.toString()).replace("{x}",d.toString()).replace("{y}",e.toString());return f},wrapX:b.wrapX===!0?1:0});break;case"KML":var w=b.extractStyles||!1;g=new a.source.Vector({url:b.url,format:new a.format.KML,radius:b.radius,extractStyles:w,wrapX:b.wrapX===!0?1:0});break;case"Stamen":if(!b.layer||!q(b.layer))return void c.error("[AngularJS - Openlayers] - You need a valid Stamen layer.");g=new a.source.Stamen({layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"ImageStatic":if(!b.url||!angular.isArray(b.imageSize)||2!==b.imageSize.length)return void c.error("[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.");g=new a.source.ImageStatic({url:b.url,attributions:s(b),imageSize:b.imageSize,projection:f,imageExtent:f.getExtent(),imageLoadFunction:b.imageLoadFunction,wrapX:b.wrapX===!0?1:0});break;case"XYZ":b.url||c.error("[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties"),g=new a.source.XYZ({url:b.url,attributions:s(b),minZoom:b.minZoom,maxZoom:b.maxZoom,wrapX:b.wrapX===!0?1:0})}return g||c.warn('[AngularJS - Openlayers] - No source could be found for type "'+b.type+'"'),g},s=function(b){var c=[];return e(b.attribution)&&c.unshift(new a.Attribution({html:b.attribution})),c},t=function(b){var c=new a.layer.Group;return c.set("name",b),c},u=function(b,c){var d;return angular.forEach(b,function(b){return b instanceof a.layer.Group&&b.get("name")===c?void(d=b):void 0}),d},v=function(a,b){for(var c,d=0;d', + controller: function($scope) { + var _map = $q.defer(); + $scope.getMap = function() { + return _map.promise; + }; + + $scope.setMap = function(map) { + _map.resolve(map); + }; + + this.getOpenlayersScope = function() { + return $scope; + }; + }, + link: function(scope, element, attrs) { + var isDefined = olHelpers.isDefined; + var createLayer = olHelpers.createLayer; + var setMapEvents = olHelpers.setMapEvents; + var setViewEvents = olHelpers.setViewEvents; + var createView = olHelpers.createView; + var defaults = olMapDefaults.setDefaults(scope); + + // Set width and height if they are defined + if (isDefined(attrs.width)) { + if (isNaN(attrs.width)) { + element.css('width', attrs.width); + } else { + element.css('width', attrs.width + 'px'); + } + } + + if (isDefined(attrs.height)) { + if (isNaN(attrs.height)) { + element.css('height', attrs.height); + } else { + element.css('height', attrs.height + 'px'); + } + } + + if (isDefined(attrs.lat)) { + defaults.center.lat = parseFloat(attrs.lat); + } + + if (isDefined(attrs.lon)) { + defaults.center.lon = parseFloat(attrs.lon); + } + + if (isDefined(attrs.zoom)) { + defaults.center.zoom = parseFloat(attrs.zoom); + } + + var controls = ol.control.defaults(defaults.controls); + var interactions = ol.interaction.defaults(defaults.interactions); + var view = createView(defaults.view); + + // Create the Openlayers Map Object with the options + var map = new ol.Map({ + target: element[0], + controls: controls, + interactions: interactions, + renderer: defaults.renderer, + view: view + }); + + // If no layer is defined, set the default tileLayer + if (!attrs.customLayers) { + var l = { + type: 'Tile', + source: { + type: 'OSM' + } + }; + var layer = createLayer(l, view.getProjection(), 'default'); + map.addLayer(layer); + map.set('default', true); + } + + if (!isDefined(attrs.olCenter)) { + var c = ol.proj.transform([defaults.center.lon, + defaults.center.lat + ], + defaults.center.projection, view.getProjection() + ); + view.setCenter(c); + view.setZoom(defaults.center.zoom); + } + + // Set the Default events for the map + setMapEvents(defaults.events, map, scope); + + //Set the Default events for the map view + setViewEvents(defaults.events, map, scope); + + // Resolve the map object to the promises + scope.setMap(map); + olData.setMap(map, attrs.id); + + } + }; + }); + +angular.module('openlayers-directive').directive('olCenter', function($log, $location, olMapDefaults, olHelpers) { + + return { + restrict: 'A', + scope: false, + replace: false, + require: 'openlayers', + + link: function(scope, element, attrs, controller) { + var safeApply = olHelpers.safeApply; + var isValidCenter = olHelpers.isValidCenter; + var isDefined = olHelpers.isDefined; + var isArray = olHelpers.isArray; + var isNumber = olHelpers.isNumber; + var isSameCenterOnMap = olHelpers.isSameCenterOnMap; + var setCenter = olHelpers.setCenter; + var setZoom = olHelpers.setZoom; + var olScope = controller.getOpenlayersScope(); + + olScope.getMap().then(function(map) { + var defaults = olMapDefaults.getDefaults(olScope); + var view = map.getView(); + var center = olScope.center; + + if (attrs.olCenter.search('-') !== -1) { + $log.error('[AngularJS - Openlayers] The "center" variable can\'t use ' + + 'a "-" on his key name: "' + attrs.center + '".'); + setCenter(view, defaults.view.projection, defaults.center, map); + return; + } + + if (!isDefined(center)) { + center = {}; + } + + if (!isValidCenter(center)) { + $log.warn('[AngularJS - Openlayers] invalid \'center\''); + center.lat = defaults.center.lat; + center.lon = defaults.center.lon; + center.zoom = defaults.center.zoom; + center.projection = defaults.center.projection; + } + + if (!center.projection) { + if (defaults.view.projection !== 'pixel') { + center.projection = defaults.center.projection; + } else { + center.projection = 'pixel'; + } + } + + if (!isNumber(center.zoom)) { + center.zoom = 1; + } + + setCenter(view, defaults.view.projection, center, map); + view.setZoom(center.zoom); + + var centerUrlHash; + if (center.centerUrlHash === true) { + var extractCenterFromUrl = function() { + var search = $location.search(); + var centerParam; + if (isDefined(search.c)) { + var cParam = search.c.split(':'); + if (cParam.length === 3) { + centerParam = { + lat: parseFloat(cParam[0]), + lon: parseFloat(cParam[1]), + zoom: parseInt(cParam[2], 10) + }; + } + } + return centerParam; + }; + centerUrlHash = extractCenterFromUrl(); + + olScope.$on('$locationChangeSuccess', function() { + var urlCenter = extractCenterFromUrl(); + if (urlCenter && !isSameCenterOnMap(urlCenter, map)) { + safeApply(olScope, function(scope) { + scope.center.lat = urlCenter.lat; + scope.center.lon = urlCenter.lon; + scope.center.zoom = urlCenter.zoom; + }); + } + }); + } + + var geolocation; + olScope.$watchCollection('center', function(center) { + + if (!center) { + return; + } + + if (!center.projection) { + center.projection = defaults.center.projection; + } + + if (center.autodiscover) { + if (!geolocation) { + geolocation = new ol.Geolocation({ + projection: ol.proj.get(center.projection) + }); + + geolocation.on('change', function() { + if (center.autodiscover) { + var location = geolocation.getPosition(); + safeApply(olScope, function(scope) { + scope.center.lat = location[1]; + scope.center.lon = location[0]; + scope.center.zoom = 12; + scope.center.autodiscover = false; + geolocation.setTracking(false); + }); + } + }); + } + geolocation.setTracking(true); + return; + } + + if (!isValidCenter(center)) { + $log.warn('[AngularJS - Openlayers] invalid \'center\''); + center = defaults.center; + } + + var viewCenter = view.getCenter(); + if (viewCenter) { + if (defaults.view.projection === 'pixel') { + view.setCenter(center.coord); + return; + } + var actualCenter = ol.proj.transform(viewCenter, defaults.view.projection, center.projection); + if (!(actualCenter[1] === center.lat && actualCenter[0] === center.lon)) { + setCenter(view, defaults.view.projection, center, map); + } + } + + if (view.getZoom() !== center.zoom) { + setZoom(view, center.zoom, map); + } + }); + + map.on('moveend', function() { + safeApply(olScope, function(scope) { + + if (!isDefined(scope.center)) { + return; + } + + var center = map.getView().getCenter(); + scope.center.zoom = view.getZoom(); + + if (defaults.view.projection === 'pixel') { + scope.center.coord = center; + return; + } + + if (scope.center) { + var proj = ol.proj.transform(center, defaults.view.projection, scope.center.projection); + scope.center.lat = proj[1]; + scope.center.lon = proj[0]; + + // Notify the controller about a change in the center position + olHelpers.notifyCenterUrlHashChanged(olScope, scope.center, $location.search()); + + // Calculate the bounds if needed + if (isArray(scope.center.bounds)) { + var extent = view.calculateExtent(map.getSize()); + var centerProjection = scope.center.projection; + var viewProjection = defaults.view.projection; + scope.center.bounds = ol.proj.transformExtent(extent, viewProjection, centerProjection); + } + } + }); + }); + + }); + } + }; +}); + +angular.module('openlayers-directive').directive('olLayer', function($log, $q, olMapDefaults, olHelpers) { + + return { + restrict: 'E', + scope: { + properties: '=olLayerProperties' + }, + replace: false, + require: '^openlayers', + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var equals = olHelpers.equals; + var olScope = controller.getOpenlayersScope(); + var createLayer = olHelpers.createLayer; + var setVectorLayerEvents = olHelpers.setVectorLayerEvents; + var detectLayerType = olHelpers.detectLayerType; + var createStyle = olHelpers.createStyle; + var isBoolean = olHelpers.isBoolean; + var addLayerBeforeMarkers = olHelpers.addLayerBeforeMarkers; + var isNumber = olHelpers.isNumber; + var insertLayer = olHelpers.insertLayer; + var removeLayer = olHelpers.removeLayer; + var addLayerToGroup = olHelpers.addLayerToGroup; + var removeLayerFromGroup = olHelpers.removeLayerFromGroup; + var getGroup = olHelpers.getGroup; + + olScope.getMap().then(function(map) { + var projection = map.getView().getProjection(); + var defaults = olMapDefaults.setDefaults(olScope); + var layerCollection = map.getLayers(); + var olLayer; + + scope.$on('$destroy', function() { + if (scope.properties.group) { + removeLayerFromGroup(layerCollection, olLayer, scope.properties.group); + } else { + removeLayer(layerCollection, olLayer.index); + } + + map.removeLayer(olLayer); + }); + + if (!isDefined(scope.properties)) { + if (isDefined(attrs.sourceType) && isDefined(attrs.sourceUrl)) { + var l = { + source: { + url: attrs.sourceUrl, + type: attrs.sourceType + } + }; + + olLayer = createLayer(l, projection, attrs.layerName); + if (detectLayerType(l) === 'Vector') { + setVectorLayerEvents(defaults.events, map, scope, attrs.name); + } + addLayerBeforeMarkers(layerCollection, olLayer); + } + return; + } + + scope.$watch('properties', function(properties, oldProperties) { + if (!isDefined(properties.source) || !isDefined(properties.source.type)) { + return; + } + + if (!isDefined(properties.visible)) { + properties.visible = true; + return; + } + + if (!isDefined(properties.opacity)) { + properties.opacity = 1; + return; + } + + var style; + var group; + var collection; + if (!isDefined(olLayer)) { + olLayer = createLayer(properties, projection); + if (isDefined(properties.group)) { + addLayerToGroup(layerCollection, olLayer, properties.group); + } else if (isDefined(properties.index)) { + insertLayer(layerCollection, properties.index, olLayer); + } else { + addLayerBeforeMarkers(layerCollection, olLayer); + } + + if (detectLayerType(properties) === 'Vector') { + setVectorLayerEvents(defaults.events, map, scope, properties.name); + } + + if (isBoolean(properties.visible)) { + olLayer.setVisible(properties.visible); + } + + if (properties.opacity) { + olLayer.setOpacity(properties.opacity); + } + + if (angular.isArray(properties.extent)) { + olLayer.setExtent(properties.extent); + } + + if (properties.style) { + if (!angular.isFunction(properties.style)) { + style = createStyle(properties.style); + } else { + style = properties.style; + } + // not every layer has a setStyle method + if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { + olLayer.setStyle(style); + } + } + + } else { + var isNewLayer = (function(olLayer) { + // this function can be used to verify whether a new layer instance has + // been created. This is needed in order to re-assign styles, opacity + // etc... + return function(layer) { + return layer !== olLayer; + }; + })(olLayer); + + // set source properties + if (isDefined(oldProperties) && !equals(properties.source, oldProperties.source)) { + var idx = olLayer.index; + collection = layerCollection; + group = olLayer.get('group'); + + if (group) { + collection = getGroup(layerCollection, group).getLayers(); + } + + collection.removeAt(idx); + + olLayer = createLayer(properties, projection); + olLayer.set('group', group); + + if (isDefined(olLayer)) { + insertLayer(collection, idx, olLayer); + + if (detectLayerType(properties) === 'Vector') { + setVectorLayerEvents(defaults.events, map, scope, properties.name); + } + } + } + + // set opacity + if (isDefined(oldProperties) && + properties.opacity !== oldProperties.opacity || isNewLayer(olLayer)) { + if (isNumber(properties.opacity) || isNumber(parseFloat(properties.opacity))) { + olLayer.setOpacity(properties.opacity); + } + } + + // set index + if (isDefined(properties.index) && properties.index !== olLayer.index) { + collection = layerCollection; + group = olLayer.get('group'); + + if (group) { + collection = getGroup(layerCollection, group).getLayers(); + } + + removeLayer(collection, olLayer.index); + insertLayer(collection, properties.index, olLayer); + } + + // set group + if (isDefined(properties.group) && properties.group !== oldProperties.group) { + removeLayerFromGroup(layerCollection, olLayer, oldProperties.group); + addLayerToGroup(layerCollection, olLayer, properties.group); + } + + // set visibility + if (isDefined(oldProperties) && + isBoolean(properties.visible) && + properties.visible !== oldProperties.visible || isNewLayer(olLayer)) { + olLayer.setVisible(properties.visible); + } + + // set style + if (isDefined(properties.style) && + !equals(properties.style, oldProperties.style) || isNewLayer(olLayer)) { + if (!angular.isFunction(properties.style)) { + style = createStyle(properties.style); + } else { + style = properties.style; + } + // not every layer has a setStyle method + if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { + olLayer.setStyle(style); + } + } + } + }, true); + }); + } + }; +}); + +angular.module('openlayers-directive').directive('olPath', function($log, $q, olMapDefaults, olHelpers) { + + return { + restrict: 'E', + scope: { + properties: '=olGeomProperties' + }, + require: '^openlayers', + replace: true, + template: '', + + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var createFeature = olHelpers.createFeature; + var createOverlay = olHelpers.createOverlay; + var createVectorLayer = olHelpers.createVectorLayer; + var insertLayer = olHelpers.insertLayer; + var removeLayer = olHelpers.removeLayer; + var olScope = controller.getOpenlayersScope(); + + olScope.getMap().then(function(map) { + var mapDefaults = olMapDefaults.getDefaults(olScope); + var viewProjection = mapDefaults.view.projection; + + var layer = createVectorLayer(); + var layerCollection = map.getLayers(); + + insertLayer(layerCollection, layerCollection.getLength(), layer); + + scope.$on('$destroy', function() { + removeLayer(layerCollection, layer.index); + }); + + if (isDefined(attrs.coords)) { + var proj = attrs.proj || 'EPSG:4326'; + var coords = JSON.parse(attrs.coords); + var data = { + type: 'Polygon', + coords: coords, + projection: proj, + style: mapDefaults.styles.path + }; + var feature = createFeature(data, viewProjection); + layer.getSource().addFeature(feature); + + if (attrs.message) { + scope.message = attrs.message; + var extent = feature.getGeometry().getExtent(); + var label = createOverlay(element, extent); + map.addOverlay(label); + } + return; + } + }); + } + }; +}); + +angular.module('openlayers-directive').directive('olView', function($log, $q, olData, olMapDefaults, olHelpers) { + return { + restrict: 'A', + scope: false, + replace: false, + require: 'openlayers', + link: function(scope, element, attrs, controller) { + var olScope = controller.getOpenlayersScope(); + var isNumber = olHelpers.isNumber; + var safeApply = olHelpers.safeApply; + var createView = olHelpers.createView; + + olScope.getMap().then(function(map) { + var defaults = olMapDefaults.getDefaults(olScope); + var view = olScope.view; + + if (!view.projection) { + view.projection = defaults.view.projection; + } + + if (!view.maxZoom) { + view.maxZoom = defaults.view.maxZoom; + } + + if (!view.minZoom) { + view.minZoom = defaults.view.minZoom; + } + + if (!view.rotation) { + view.rotation = defaults.view.rotation; + } + + var mapView = createView(view); + map.setView(mapView); + + olScope.$watchCollection('view', function(view) { + if (isNumber(view.rotation)) { + mapView.setRotation(view.rotation); + } + }); + + mapView.on('change:rotation', function() { + safeApply(olScope, function(scope) { + scope.view.rotation = map.getView().getRotation(); + }); + }); + + }); + } + }; +}); + +angular.module('openlayers-directive').directive('olControl', function($log, $q, olData, olMapDefaults, olHelpers) { + + return { + restrict: 'E', + scope: { + properties: '=olControlProperties' + }, + replace: false, + require: '^openlayers', + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var olScope = controller.getOpenlayersScope(); + var olControl; + var olControlOps; + + olScope.getMap().then(function(map) { + var getControlClasses = olHelpers.getControlClasses; + var controlClasses = getControlClasses(); + + scope.$on('$destroy', function() { + map.removeControl(olControl); + }); + + if (!isDefined(scope.properties) || !isDefined(scope.properties.control)) { + if (attrs.name) { + if (isDefined(scope.properties)) { + olControlOps = scope.properties; + } + olControl = new controlClasses[attrs.name](olControlOps); + map.addControl(olControl); + } + return; + } + + olControl = scope.properties.control; + map.addControl(olControl); + }); + } + }; +}); + +angular.module('openlayers-directive').directive('olMarker', function($log, $q, olMapDefaults, olHelpers) { + + var getMarkerDefaults = function() { + return { + projection: 'EPSG:4326', + lat: 0, + lon: 0, + coord: [], + show: true, + showOnMouseOver: false, + showOnMouseClick: false, + keepOneOverlayVisible: false + }; + }; + + var markerLayerManager = (function() { + var mapDict = []; + + function getMapIndex(map) { + return mapDict.map(function(record) { + return record.map; + }).indexOf(map); + } + + return { + getInst: function getMarkerLayerInst(scope, map) { + var mapIndex = getMapIndex(map); + + if (mapIndex === -1) { + var markerLayer = olHelpers.createVectorLayer(); + markerLayer.set('markers', true); + map.addLayer(markerLayer); + mapDict.push({ + map: map, + markerLayer: markerLayer, + instScopes: [] + }); + mapIndex = mapDict.length - 1; + } + + mapDict[mapIndex].instScopes.push(scope); + + return mapDict[mapIndex].markerLayer; + }, + deregisterScope: function deregisterScope(scope, map) { + var mapIndex = getMapIndex(map); + if (mapIndex === -1) { + throw Error('This map has no markers'); + } + + var scopes = mapDict[mapIndex].instScopes; + var scopeIndex = scopes.indexOf(scope); + if (scopeIndex === -1) { + throw Error('Scope wan\'t registered'); + } + + scopes.splice(scopeIndex, 1); + + if (!scopes.length) { + map.removeLayer(mapDict[mapIndex].markerLayer); + delete mapDict[mapIndex]; + } + } + }; + })(); + return { + restrict: 'E', + scope: { + lat: '=lat', + lon: '=lon', + label: '=label', + properties: '=olMarkerProperties', + style: '=olStyle' + }, + transclude: true, + require: '^openlayers', + replace: true, + template: + '', + + link: function(scope, element, attrs, controller) { + var isDefined = olHelpers.isDefined; + var olScope = controller.getOpenlayersScope(); + var createFeature = olHelpers.createFeature; + var createOverlay = olHelpers.createOverlay; + + var hasTranscluded = element.find('ng-transclude').children().length > 0; + + olScope.getMap().then(function(map) { + var markerLayer = markerLayerManager.getInst(scope, map); + var data = getMarkerDefaults(); + + var mapDefaults = olMapDefaults.getDefaults(olScope); + var viewProjection = mapDefaults.view.projection; + var label; + var pos; + var marker; + + // This function handles dragging a marker + var pickOffset = null; + var pickProperties = null; + function handleDrag(evt) { + var coord = evt.coordinate; + var proj = map.getView().getProjection().getCode(); + if (proj === 'pixel') { + coord = coord.map(function(v) { + return parseInt(v, 10); + }); + } else { + coord = ol.proj.transform(coord, proj, 'EPSG:4326'); + } + + if (evt.type === 'pointerdown') { + // Get feature under mouse if any + var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { + return feature; + }); + // Get associated marker properties + pickProperties = (feature ? feature.get('marker') : null); + if (!pickProperties || !pickProperties.draggable) { + pickProperties = null; + return; + } + map.getTarget().style.cursor = 'pointer'; + if (proj === 'pixel') { + pickOffset = [coord[0] - pickProperties.coord[0], coord[1] - pickProperties.coord[1]]; + } else { + pickOffset = [coord[0] - pickProperties.lon, coord[1] - pickProperties.lat]; + } + evt.preventDefault(); + } else if (pickOffset && pickProperties) { + if (evt.type === 'pointerup') { + map.getTarget().style.cursor = ''; + pickOffset = null; + pickProperties = null; + evt.preventDefault(); + } else if (evt.type === 'pointerdrag') { + evt.preventDefault(); + scope.$apply(function() { + // Add current delta to marker initial position + if (proj === 'pixel') { + pickProperties.coord[0] = coord[0] - pickOffset[0]; + pickProperties.coord[1] = coord[1] - pickOffset[1]; + } else { + pickProperties.lon = coord[0] - pickOffset[0]; + pickProperties.lat = coord[1] - pickOffset[1]; + } + }); + } + } + } + + // Setup generic handlers for marker drag + map.on('pointerdown', handleDrag); + map.on('pointerup', handleDrag); + map.on('pointerdrag', handleDrag); + + scope.$on('$destroy', function() { + markerLayer.getSource().removeFeature(marker); + if (isDefined(label)) { + map.removeOverlay(label); + } + markerLayerManager.deregisterScope(scope, map); + }); + + if (!isDefined(scope.properties)) { + data.lat = scope.lat ? scope.lat : data.lat; + data.lon = scope.lon ? scope.lon : data.lon; + data.message = attrs.message; + data.style = scope.style ? scope.style : mapDefaults.styles.marker; + + marker = createFeature(data, viewProjection); + if (!isDefined(marker)) { + $log.error('[AngularJS - Openlayers] Received invalid data on ' + + 'the marker.'); + } + // Add a link between the feature and the marker properties + marker.set('marker', scope); + markerLayer.getSource().addFeature(marker); + + if (data.message || hasTranscluded) { + scope.message = attrs.message; + pos = ol.proj.transform([data.lon, data.lat], data.projection, + viewProjection); + label = createOverlay(element, pos); + map.addOverlay(label); + } + return; + } + + scope.$watch('properties', function(properties) { + + // Remove previous listeners if any + map.getViewport().removeEventListener('mousemove', properties.handleInteraction); + map.getViewport().removeEventListener('click', properties.handleTapInteraction); + map.getViewport().querySelector('canvas.ol-unselectable').removeEventListener( + 'touchend', properties.handleTapInteraction); + map.getViewport().removeEventListener('mousemove', properties.showAtLeastOneOverlay); + map.getViewport().removeEventListener('click', properties.removeAllOverlays); + + // This function handles popup on mouse over/click + properties.handleInteraction = function(evt) { + if (properties.label.show) { + return; + } + var found = false; + var pixel = map.getEventPixel(evt); + var feature = map.forEachFeatureAtPixel(pixel, function(feature) { + return feature; + }); + + var actionTaken = false; + if (feature === marker) { + actionTaken = true; + found = true; + if (!isDefined(label)) { + if (data.projection === 'pixel') { + pos = properties.coord; + } else { + pos = ol.proj.transform([properties.lon, properties.lat], + data.projection, viewProjection); + } + label = createOverlay(element, pos); + map.addOverlay(label); + } + + if (properties.onClick && (evt.type === 'click' || evt.type === 'touchend')) { + scope.$apply(function() { + properties.onClick.call(marker, evt, properties); + }); + } + map.getTarget().style.cursor = 'pointer'; + } + + if (!found && label) { + actionTaken = true; + map.removeOverlay(label); + label = undefined; + map.getTarget().style.cursor = ''; + } + + if (actionTaken) { + evt.preventDefault(); + } + }; + + // Made to filter out click/tap events if both are being triggered on this platform + properties.handleTapInteraction = (function() { + var cooldownActive = false; + var prevTimeout; + + // Sets the cooldown flag to filter out any subsequent events within 500 ms + function activateCooldown() { + cooldownActive = true; + if (prevTimeout) { + clearTimeout(prevTimeout); + } + prevTimeout = setTimeout(function() { + cooldownActive = false; + prevTimeout = null; + }, 500); + } + + // Preventing from 'touchend' to be considered a tap, if fired immediately after 'touchmove' + map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( + 'touchmove', activateCooldown); + + return function() { + if (!cooldownActive) { + properties.handleInteraction.apply(null, arguments); + activateCooldown(); + } + }; + })(); + + properties.showAtLeastOneOverlay = function(evt) { + if (properties.label.show) { + return; + } + var found = false; + var pixel = map.getEventPixel(evt); + var feature = map.forEachFeatureAtPixel(pixel, function(feature) { + return feature; + }); + + var actionTaken = false; + if (feature === marker) { + actionTaken = true; + found = true; + if (!isDefined(label)) { + if (data.projection === 'pixel') { + pos = data.coord; + } else { + pos = ol.proj.transform([data.lon, data.lat], + data.projection, viewProjection); + } + label = createOverlay(element, pos); + angular.forEach(map.getOverlays(), function(value) { + map.removeOverlay(value); + }); + map.addOverlay(label); + } + map.getTarget().style.cursor = 'pointer'; + } + + if (!found && label) { + actionTaken = true; + label = undefined; + map.getTarget().style.cursor = ''; + } + + if (actionTaken) { + evt.preventDefault(); + } + }; + + properties.removeAllOverlays = function(evt) { + angular.forEach(map.getOverlays(), function(value) { + map.removeOverlay(value); + }); + evt.preventDefault(); + }; + + if (!isDefined(marker)) { + data.projection = properties.projection ? properties.projection : + data.projection; + data.coord = properties.coord ? properties.coord : data.coord; + data.lat = properties.lat ? properties.lat : data.lat; + data.lon = properties.lon ? properties.lon : data.lon; + + if (isDefined(properties.style)) { + data.style = properties.style; + } else { + data.style = mapDefaults.styles.marker; + } + + marker = createFeature(data, viewProjection); + if (!isDefined(marker)) { + $log.error('[AngularJS - Openlayers] Received invalid data on ' + + 'the marker.'); + } + // Add a link between the feature and the marker properties + marker.set('marker', properties); + markerLayer.getSource().addFeature(marker); + } else { + var requestedPosition; + if (properties.projection === 'pixel') { + requestedPosition = properties.coord; + } else { + requestedPosition = ol.proj.transform([properties.lon, properties.lat], data.projection, + map.getView().getProjection()); + } + + if (!angular.equals(marker.getGeometry().getCoordinates(), requestedPosition)) { + var geometry = new ol.geom.Point(requestedPosition); + marker.setGeometry(geometry); + } + } + + if (isDefined(label)) { + map.removeOverlay(label); + } + + if (!isDefined(properties.label)) { + return; + } + + scope.message = properties.label.message; + if (!hasTranscluded && (!isDefined(scope.message) || scope.message.length === 0)) { + return; + } + + if (properties.label && properties.label.show === true) { + if (data.projection === 'pixel') { + pos = data.coord; + } else { + pos = ol.proj.transform([properties.lon, properties.lat], data.projection, + viewProjection); + } + label = createOverlay(element, pos); + map.addOverlay(label); + } + + if (label && properties.label && properties.label.show === false) { + map.removeOverlay(label); + label = undefined; + } + + // Then setup new ones according to properties + if (properties.label && properties.label.show === false && + properties.label.showOnMouseOver) { + map.getViewport().addEventListener('mousemove', properties.handleInteraction); + } + + if ((properties.label && properties.label.show === false && + properties.label.showOnMouseClick) || + properties.onClick) { + map.getViewport().addEventListener('click', properties.handleTapInteraction); + map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( + 'touchend', properties.handleTapInteraction); + } + + if ((properties.label && properties.label.show === false && + properties.label.keepOneOverlayVisible)) { + map.getViewport().addEventListener('mousemove', properties.showAtLeastOneOverlay); + map.getViewport().addEventListener('click', properties.removeAllOverlays); + } + }, true); + }); + } + }; +}); + +angular.module('openlayers-directive').service('olData', function($log, $q, olHelpers) { + + var obtainEffectiveMapId = olHelpers.obtainEffectiveMapId; + + var maps = {}; + + var setResolvedDefer = function(d, mapId) { + var id = obtainEffectiveMapId(d, mapId); + d[id].resolvedDefer = true; + }; + + var getUnresolvedDefer = function(d, mapId) { + var id = obtainEffectiveMapId(d, mapId); + var defer; + + if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) { + defer = $q.defer(); + d[id] = { + defer: defer, + resolvedDefer: false + }; + } else { + defer = d[id].defer; + } + return defer; + }; + + var getDefer = function(d, mapId) { + var id = obtainEffectiveMapId(d, mapId); + var defer; + + if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) { + defer = getUnresolvedDefer(d, mapId); + } else { + defer = d[id].defer; + } + return defer; + }; + + this.setMap = function(olMap, scopeId) { + var defer = getUnresolvedDefer(maps, scopeId); + defer.resolve(olMap); + setResolvedDefer(maps, scopeId); + }; + + this.getMap = function(scopeId) { + var defer = getDefer(maps, scopeId); + return defer.promise; + }; + +}); + +angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $http) { + + var isDefined = function(value) { + return angular.isDefined(value); + }; + + var isDefinedAndNotNull = function(value) { + return angular.isDefined(value) && value !== null; + }; + + var setEvent = function(map, eventType, scope) { + map.on(eventType, function(event) { + var coord = event.coordinate; + var proj = map.getView().getProjection().getCode(); + if (proj === 'pixel') { + coord = coord.map(function(v) { + return parseInt(v, 10); + }); + } + scope.$emit('openlayers.map.' + eventType, { + 'coord': coord, + 'projection': proj, + 'event': event + }); + }); + }; + + var bingImagerySets = [ + 'Road', + 'Aerial', + 'AerialWithLabels', + 'collinsBart', + 'ordnanceSurvey' + ]; + + var getControlClasses = function() { + return { + attribution: ol.control.Attribution, + fullscreen: ol.control.FullScreen, + mouseposition: ol.control.MousePosition, + rotate: ol.control.Rotate, + scaleline: ol.control.ScaleLine, + zoom: ol.control.Zoom, + zoomslider: ol.control.ZoomSlider, + zoomtoextent: ol.control.ZoomToExtent + }; + }; + + var mapQuestLayers = ['osm', 'sat', 'hyb']; + + var esriBaseLayers = ['World_Imagery', 'World_Street_Map', 'World_Topo_Map', + 'World_Physical_Map', 'World_Terrain_Base', + 'Ocean_Basemap', 'NatGeo_World_Map']; + + var styleMap = { + 'style': ol.style.Style, + 'fill': ol.style.Fill, + 'stroke': ol.style.Stroke, + 'circle': ol.style.Circle, + 'icon': ol.style.Icon, + 'image': ol.style.Image, + 'regularshape': ol.style.RegularShape, + 'text': ol.style.Text + }; + + var optionalFactory = function(style, Constructor) { + if (Constructor && style instanceof Constructor) { + return style; + } else if (Constructor) { + return new Constructor(style); + } else { + return style; + } + }; + + //Parse the style tree calling the appropriate constructors. + //The keys in styleMap can be used and the OpenLayers constructors can be + //used directly. + var createStyle = function recursiveStyle(data, styleName) { + var style; + if (!styleName) { + styleName = 'style'; + style = data; + } else { + style = data[styleName]; + } + //Instead of defining one style for the layer, we've been given a style function + //to apply to each feature. + if (styleName === 'style' && data instanceof Function) { + return data; + } + + if (!(style instanceof Object)) { + return style; + } + + var styleObject; + if (Object.prototype.toString.call(style) === '[object Object]') { + styleObject = {}; + var styleConstructor = styleMap[styleName]; + if (styleConstructor && style instanceof styleConstructor) { + return style; + } + Object.getOwnPropertyNames(style).forEach(function(val, idx, array) { + //Consider the case + //image: { + // circle: { + // fill: { + // color: 'red' + // } + // } + // + //An ol.style.Circle is an instance of ol.style.Image, so we do not want to construct + //an Image and then construct a Circle. We assume that if we have an instanceof + //relationship, that the JSON parent has exactly one child. + //We check to see if an inheritance relationship exists. + //If it does, then for the parent we create an instance of the child. + var valConstructor = styleMap[val]; + if (styleConstructor && valConstructor && + valConstructor.prototype instanceof styleMap[styleName]) { + console.assert(array.length === 1, 'Extra parameters for ' + styleName); + styleObject = recursiveStyle(style, val); + return optionalFactory(styleObject, valConstructor); + } else { + styleObject[val] = recursiveStyle(style, val); + + // if the value is 'text' and it contains a String, then it should be interpreted + // as such, 'cause the text style might effectively contain a text to display + if (val !== 'text' && typeof styleObject[val] !== 'string') { + styleObject[val] = optionalFactory(styleObject[val], styleMap[val]); + } + } + }); + } else { + styleObject = style; + } + return optionalFactory(styleObject, styleMap[styleName]); + }; + + var detectLayerType = function(layer) { + if (layer.type) { + return layer.type; + } else { + switch (layer.source.type) { + case 'ImageWMS': + return 'Image'; + case 'ImageStatic': + return 'Image'; + case 'GeoJSON': + case 'JSONP': + case 'TopoJSON': + case 'KML': + case 'TileVector': + return 'Vector'; + default: + return 'Tile'; + } + } + }; + + var createProjection = function(view) { + var oProjection; + + switch (view.projection) { + case 'pixel': + if (!isDefined(view.extent)) { + $log.error('[AngularJS - Openlayers] - You must provide the extent of the image ' + + 'if using pixel projection'); + return; + } + oProjection = new ol.proj.Projection({ + code: 'pixel', + units: 'pixels', + extent: view.extent + }); + break; + default: + oProjection = new ol.proj.get(view.projection); + break; + } + + return oProjection; + }; + + var isValidStamenLayer = function(layer) { + return ['watercolor', 'terrain', 'toner'].indexOf(layer) !== -1; + }; + + var createSource = function(source, projection) { + var oSource; + + switch (source.type) { + case 'MapBox': + if (!source.mapId || !source.accessToken) { + $log.error('[AngularJS - Openlayers] - MapBox layer requires the map id and the access token'); + return; + } + var url = 'http://api.tiles.mapbox.com/v4/' + source.mapId + '/{z}/{x}/{y}.png?access_token=' + + source.accessToken; + + var pixelRatio = window.devicePixelRatio; + + if (pixelRatio > 1) { + url = url.replace('.png', '@2x.png'); + } + + oSource = new ol.source.XYZ({ + url: url, + attributions: createAttribution(source), + tilePixelRatio: pixelRatio > 1 ? 2 : 1, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'ImageWMS': + if (!source.url || !source.params) { + $log.error('[AngularJS - Openlayers] - ImageWMS Layer needs ' + + 'valid server url and params properties'); + } + oSource = new ol.source.ImageWMS({ + url: source.url, + attributions: createAttribution(source), + crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, + params: source.params, + wrapX: source.wrapX ? 0 : 1 + }); + break; + + case 'TileWMS': + if ((!source.url && !source.urls) || !source.params) { + $log.error('[AngularJS - Openlayers] - TileWMS Layer needs ' + + 'valid url (or urls) and params properties'); + } + + var wmsConfiguration = { + crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, + params: source.params, + attributions: createAttribution(source), + wrapX: source.wrapX ? 0 : 1 + }; + + if (source.url) { + wmsConfiguration.url = source.url; + } + + if (source.urls) { + wmsConfiguration.urls = source.urls; + } + + oSource = new ol.source.TileWMS(wmsConfiguration); + break; + + case 'WMTS': + if ((!source.url && !source.urls) || !source.tileGrid) { + $log.error('[AngularJS - Openlayers] - WMTS Layer needs valid url ' + + '(or urls) and tileGrid properties'); + } + + var wmtsConfiguration = { + projection: projection, + layer: source.layer, + attributions: createAttribution(source), + matrixSet: (source.matrixSet === 'undefined') ? projection : source.matrixSet, + format: (source.format === 'undefined') ? 'image/jpeg' : source.format, + requestEncoding: (source.requestEncoding === 'undefined') ? + 'KVP' : source.requestEncoding, + tileGrid: new ol.tilegrid.WMTS({ + origin: source.tileGrid.origin, + resolutions: source.tileGrid.resolutions, + matrixIds: source.tileGrid.matrixIds + }), + wrapX: source.wrapX ? 0 : 1 + }; + + if (isDefined(source.url)) { + wmtsConfiguration.url = source.url; + } + + if (isDefined(source.urls)) { + wmtsConfiguration.urls = source.urls; + } + + oSource = new ol.source.WMTS(wmtsConfiguration); + break; + + case 'OSM': + oSource = new ol.source.OSM({ + attributions: createAttribution(source), + wrapX: (source.wrapX === true) ? 1 : 0 + }); + + if (source.url) { + oSource.setUrl(source.url); + } + + break; + case 'BingMaps': + if (!source.key) { + $log.error('[AngularJS - Openlayers] - You need an API key to show the Bing Maps.'); + return; + } + + var bingConfiguration = { + key: source.key, + attributions: createAttribution(source), + imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], + culture: source.culture, + wrapX: (source.wrapX === true) ? 1 : 0 + }; + + if (source.maxZoom) { + bingConfiguration.maxZoom = source.maxZoom; + } + + oSource = new ol.source.BingMaps(bingConfiguration); + break; + + case 'MapQuest': + if (!source.layer || mapQuestLayers.indexOf(source.layer) === -1) { + $log.error('[AngularJS - Openlayers] - MapQuest layers needs a valid \'layer\' property.'); + return; + } + + oSource = new ol.source.MapQuest({ + attributions: createAttribution(source), + layer: source.layer, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + + break; + + case 'EsriBaseMaps': + if (!source.layer || esriBaseLayers.indexOf(source.layer) === -1) { + $log.error('[AngularJS - Openlayers] - ESRI layers needs a valid \'layer\' property.'); + return; + } + + var _urlBase = 'http://services.arcgisonline.com/ArcGIS/rest/services/'; + var _url = _urlBase + source.layer + '/MapServer/tile/{z}/{y}/{x}'; + + oSource = new ol.source.XYZ({ + attributions: createAttribution(source), + url: _url, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + + break; + + case 'GeoJSON': + if (!(source.geojson || source.url)) { + $log.error('[AngularJS - Openlayers] - You need a geojson ' + + 'property to add a GeoJSON layer.'); + return; + } + + if (isDefined(source.url)) { + oSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + url: source.url, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + } else { + oSource = new ol.source.Vector(); + + var projectionToUse = projection; + if (isDefined(source.geojson.projection)) { + projectionToUse = source.geojson.projection; + } + + var geojsonFormat = new ol.format.GeoJSON(); + var features = geojsonFormat.readFeatures( + source.geojson.object, { featureProjection: projectionToUse }); + + oSource.addFeatures(features); + } + + break; + case 'JSONP': + if (!(source.url)) { + $log.error('[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.'); + return; + } + + if (isDefined(source.url)) { + oSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + loader: function(/*extent, resolution, projection*/) { + var url = source.url + + '&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK'; + $http.jsonp(url, { cache: source.cache}).success(function(response) { + oSource.addFeatures(oSource.readFeatures(response)); + }).error(function(response) { + $log(response); + }); + }, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + } + break; + case 'TopoJSON': + if (!(source.topojson || source.url)) { + $log.error('[AngularJS - Openlayers] - You need a topojson ' + + 'property to add a TopoJSON layer.'); + return; + } + + if (source.url) { + oSource = new ol.source.Vector({ + format: new ol.format.TopoJSON(), + url: source.url, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + } else { + oSource = new ol.source.Vector(angular.extend(source.topojson, { + format: new ol.format.TopoJSON(), + wrapX: (source.wrapX === true) ? 1 : 0 + })); + } + break; + case 'TileJSON': + oSource = new ol.source.TileJSON({ + url: source.url, + attributions: createAttribution(source), + crossOrigin: 'anonymous', + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + + case 'TileVector': + if (!source.url || !source.format) { + $log.error('[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties'); + } + oSource = new ol.source.TileVector({ + url: source.url, + projection: projection, + attributions: createAttribution(source), + format: source.format, + tileGrid: new ol.tilegrid.createXYZ({ + maxZoom: source.maxZoom || 19 + }), + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + + case 'TileTMS': + if (!source.url || !source.tileGrid) { + $log.error('[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties'); + } + oSource = new ol.source.TileImage({ + url: source.url, + maxExtent: source.maxExtent, + attributions: createAttribution(source), + tileGrid: new ol.tilegrid.TileGrid({ + origin: source.tileGrid.origin, + resolutions: source.tileGrid.resolutions + }), + tileUrlFunction: function(tileCoord) { + + var z = tileCoord[0]; + var x = tileCoord[1]; + var y = tileCoord[2]; //(1 << z) - tileCoord[2] - 1; + + if (x < 0 || y < 0) { + return ''; + } + + var url = source.url + z + '/' + x + '/' + y + '.png'; + + return url; + }, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'TileImage': + oSource = new ol.source.TileImage({ + url: source.url, + attributions: createAttribution(source), + tileGrid: new ol.tilegrid.TileGrid({ + origin: source.tileGrid.origin, // top left corner of the pixel projection's extent + resolutions: source.tileGrid.resolutions + }), + tileUrlFunction: function(tileCoord/*, pixelRatio, projection*/) { + var z = tileCoord[0]; + var x = tileCoord[1]; + var y = -tileCoord[2] - 1; + var url = source.url + .replace('{z}', z.toString()) + .replace('{x}', x.toString()) + .replace('{y}', y.toString()); + return url; + }, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'KML': + var extractStyles = source.extractStyles || false; + oSource = new ol.source.Vector({ + url: source.url, + format: new ol.format.KML(), + radius: source.radius, + extractStyles: extractStyles, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'Stamen': + if (!source.layer || !isValidStamenLayer(source.layer)) { + $log.error('[AngularJS - Openlayers] - You need a valid Stamen layer.'); + return; + } + oSource = new ol.source.Stamen({ + layer: source.layer, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'ImageStatic': + if (!source.url || !angular.isArray(source.imageSize) || source.imageSize.length !== 2) { + $log.error('[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.'); + return; + } + + oSource = new ol.source.ImageStatic({ + url: source.url, + attributions: createAttribution(source), + imageSize: source.imageSize, + projection: projection, + imageExtent: projection.getExtent(), + imageLoadFunction: source.imageLoadFunction, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + case 'XYZ': + if (!source.url) { + $log.error('[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties'); + } + oSource = new ol.source.XYZ({ + url: source.url, + attributions: createAttribution(source), + minZoom: source.minZoom, + maxZoom: source.maxZoom, + wrapX: (source.wrapX === true) ? 1 : 0 + }); + break; + } + + // log a warning when no source could be created for the given type + if (!oSource) { + $log.warn('[AngularJS - Openlayers] - No source could be found for type "' + source.type + '"'); + } + + return oSource; + }; + + var createAttribution = function(source) { + var attributions = []; + if (isDefined(source.attribution)) { + attributions.unshift(new ol.Attribution({html: source.attribution})); + } + return attributions; + }; + + var createGroup = function(name) { + var olGroup = new ol.layer.Group(); + olGroup.set('name', name); + + return olGroup; + }; + + var getGroup = function(layers, name) { + var layer; + + angular.forEach(layers, function(l) { + if (l instanceof ol.layer.Group && l.get('name') === name) { + layer = l; + return; + } + }); + + return layer; + }; + + var addLayerBeforeMarkers = function(layers, layer) { + var markersIndex; + for (var i = 0; i < layers.getLength(); i++) { + var l = layers.item(i); + + if (l.get('markers')) { + markersIndex = i; + break; + } + } + + if (isDefined(markersIndex)) { + var markers = layers.item(markersIndex); + layer.index = markersIndex; + layers.setAt(markersIndex, layer); + markers.index = layers.getLength(); + layers.push(markers); + } else { + layer.index = layers.getLength(); + layers.push(layer); + } + + }; + + var removeLayer = function(layers, index) { + layers.removeAt(index); + for (var i = index; i < layers.getLength(); i++) { + var l = layers.item(i); + if (l === null) { + layers.insertAt(i, null); + break; + } else { + l.index = i; + } + } + }; + + return { + // Determine if a reference is defined + isDefined: isDefined, + + // Determine if a reference is a number + isNumber: function(value) { + return angular.isNumber(value); + }, + + createView: function(view) { + var projection = createProjection(view); + + return new ol.View({ + projection: projection, + maxZoom: view.maxZoom, + minZoom: view.minZoom, + extent: view.extent + }); + }, + + // Determine if a reference is defined and not null + isDefinedAndNotNull: isDefinedAndNotNull, + + // Determine if a reference is a string + isString: function(value) { + return angular.isString(value); + }, + + // Determine if a reference is an array + isArray: function(value) { + return angular.isArray(value); + }, + + // Determine if a reference is an object + isObject: function(value) { + return angular.isObject(value); + }, + + // Determine if two objects have the same properties + equals: function(o1, o2) { + return angular.equals(o1, o2); + }, + + isValidCenter: function(center) { + return angular.isDefined(center) && + (typeof center.autodiscover === 'boolean' || + angular.isNumber(center.lat) && angular.isNumber(center.lon) || + (angular.isArray(center.coord) && center.coord.length === 2 && + angular.isNumber(center.coord[0]) && angular.isNumber(center.coord[1])) || + (angular.isArray(center.bounds) && center.bounds.length === 4 && + angular.isNumber(center.bounds[0]) && angular.isNumber(center.bounds[1]) && + angular.isNumber(center.bounds[1]) && angular.isNumber(center.bounds[2]))); + }, + + safeApply: function($scope, fn) { + var phase = $scope.$root.$$phase; + if (phase === '$apply' || phase === '$digest') { + $scope.$eval(fn); + } else { + $scope.$apply(fn); + } + }, + + isSameCenterOnMap: function(center, map) { + var urlProj = center.projection || 'EPSG:4326'; + var urlCenter = [center.lon, center.lat]; + var mapProj = map.getView().getProjection(); + var mapCenter = ol.proj.transform(map.getView().getCenter(), mapProj, urlProj); + var zoom = map.getView().getZoom(); + if (mapCenter[1].toFixed(4) === urlCenter[1].toFixed(4) && + mapCenter[0].toFixed(4) === urlCenter[0].toFixed(4) && + zoom === center.zoom) { + return true; + } + return false; + }, + + setCenter: function(view, projection, newCenter, map) { + + if (map && view.getCenter()) { + var pan = ol.animation.pan({ + duration: 150, + source: (view.getCenter()) + }); + map.beforeRender(pan); + } + + if (newCenter.projection === projection) { + view.setCenter([newCenter.lon, newCenter.lat]); + } else { + var coord = [newCenter.lon, newCenter.lat]; + view.setCenter(ol.proj.transform(coord, newCenter.projection, projection)); + } + }, + + setZoom: function(view, zoom, map) { + var z = ol.animation.zoom({ + duration: 150, + resolution: map.getView().getResolution() + }); + map.beforeRender(z); + view.setZoom(zoom); + }, + + isBoolean: function(value) { + return typeof value === 'boolean'; + }, + + obtainEffectiveMapId: function(d, mapId) { + var id; + var i; + if (!angular.isDefined(mapId)) { + if (Object.keys(d).length === 1) { + for (i in d) { + if (d.hasOwnProperty(i)) { + id = i; + } + } + } else if (Object.keys(d).length === 0) { + id = 'main'; + } else { + $log.error('[AngularJS - Openlayers] - You have more than 1 map on the DOM, ' + + 'you must provide the map ID to the olData.getXXX call'); + } + } else { + id = mapId; + } + return id; + }, + + createStyle: createStyle, + + setMapEvents: function(events, map, scope) { + if (isDefined(events) && angular.isArray(events.map)) { + for (var i in events.map) { + var event = events.map[i]; + setEvent(map, event, scope); + } + } + }, + + setVectorLayerEvents: function(events, map, scope, layerName) { + if (isDefined(events) && angular.isArray(events.layers)) { + angular.forEach(events.layers, function(eventType) { + angular.element(map.getViewport()).on(eventType, function(evt) { + var pixel = map.getEventPixel(evt); + var feature = map.forEachFeatureAtPixel(pixel, function(feature, olLayer) { + // only return the feature if it is in this layer (based on the name) + return (isDefinedAndNotNull(olLayer) && olLayer.get('name') === layerName) ? feature : null; + }); + if (isDefinedAndNotNull(feature)) { + scope.$emit('openlayers.layers.' + layerName + '.' + eventType, feature, evt); + } + }); + }); + } + }, + + setViewEvents: function(events, map, scope) { + if (isDefined(events) && angular.isArray(events.view)) { + var view = map.getView(); + angular.forEach(events.view, function(eventType) { + view.on(eventType, function(event) { + scope.$emit('openlayers.view.' + eventType, view, event); + }); + }); + } + }, + + detectLayerType: detectLayerType, + + createLayer: function(layer, projection, name) { + var oLayer; + var type = detectLayerType(layer); + var oSource = createSource(layer.source, projection); + if (!oSource) { + return; + } + + // Manage clustering + if ((type === 'Vector') && layer.clustering) { + oSource = new ol.source.Cluster({ + source: oSource, + distance: layer.clusteringDistance, + }); + } + + switch (type) { + case 'Image': + oLayer = new ol.layer.Image({ source: oSource }); + break; + case 'Tile': + oLayer = new ol.layer.Tile({ source: oSource }); + break; + case 'Heatmap': + oLayer = new ol.layer.Heatmap({ source: oSource }); + break; + case 'Vector': + oLayer = new ol.layer.Vector({ source: oSource }); + break; + } + + // set a layer name if given + if (isDefined(name)) { + oLayer.set('name', name); + } else if (isDefined(layer.name)) { + oLayer.set('name', layer.name); + } + + return oLayer; + }, + + createVectorLayer: function() { + return new ol.layer.Vector({ + source: new ol.source.Vector() + }); + }, + + notifyCenterUrlHashChanged: function(scope, center, search) { + if (center.centerUrlHash) { + var centerUrlHash = center.lat.toFixed(4) + ':' + center.lon.toFixed(4) + ':' + center.zoom; + if (!isDefined(search.c) || search.c !== centerUrlHash) { + scope.$emit('centerUrlHash', centerUrlHash); + } + } + }, + + getControlClasses: getControlClasses, + + detectControls: function(controls) { + var actualControls = {}; + var controlClasses = getControlClasses(); + + controls.forEach(function(control) { + for (var i in controlClasses) { + if (control instanceof controlClasses[i]) { + actualControls[i] = control; + } + } + }); + + return actualControls; + }, + + createFeature: function(data, viewProjection) { + var geometry; + + switch (data.type) { + case 'Polygon': + geometry = new ol.geom.Polygon(data.coords); + break; + default: + if (isDefined(data.coord) && data.projection === 'pixel') { + geometry = new ol.geom.Point(data.coord); + } else { + geometry = new ol.geom.Point([data.lon, data.lat]); + } + break; + } + + if (isDefined(data.projection) && data.projection !== 'pixel') { + geometry = geometry.transform(data.projection, viewProjection); + } + + var feature = new ol.Feature({ + geometry: geometry + }); + + if (isDefined(data.style)) { + var style = createStyle(data.style); + feature.setStyle(style); + } + return feature; + }, + + addLayerBeforeMarkers: addLayerBeforeMarkers, + + getGroup: getGroup, + + addLayerToGroup: function(layers, layer, name) { + var groupLayer = getGroup(layers, name); + + if (!isDefined(groupLayer)) { + groupLayer = createGroup(name); + addLayerBeforeMarkers(layers,groupLayer); + } + + layer.set('group', name); + addLayerBeforeMarkers(groupLayer.getLayers(), layer); + }, + + removeLayerFromGroup: function(layers, layer, name) { + var groupLayer = getGroup(layers, name); + layer.set('group'); + removeLayer(groupLayer.getLayers(), layer.index); + }, + + removeLayer: removeLayer, + + insertLayer: function(layers, index, layer) { + if (layers.getLength() < index) { + while (layers.getLength() < index) { + layers.push(null); + } + layer.index = index; + layers.push(layer); + } else { + layer.index = index; + layers.insertAt(layer.index, layer); + for (var i = index + 1; i < layers.getLength(); i++) { + var l = layers.item(i); + if (l === null) { + layers.removeAt(i); + break; + } else { + l.index = i; + } + } + } + }, + + createOverlay: function(element, pos) { + element.css('display', 'block'); + var ov = new ol.Overlay({ + position: pos, + element: element, + positioning: 'center-left' + }); + + return ov; + } + }; +}); + +angular.module('openlayers-directive').factory('olMapDefaults', function($q, olHelpers) { + + var base64icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw' + + '7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGq' + + 'KII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR' + + '6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWV' + + 'MqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23' + + 'h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o' + + '+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzq' + + 'Bk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0g' + + 'pBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF' + + '3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAw' + + 'AhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5W' + + 'YnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRcha' + + 'h8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1E' + + 'IlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk' + + '4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/' + + 'tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdW' + + 'r7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0' + + 'ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIP' + + 'hP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmql' + + 'yvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsY' + + 'J7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/' + + 'WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIa' + + 'vznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV' + + '3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R' + + '3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDl' + + 'lwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQ' + + 'SCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92' + + 'H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GC' + + 'LVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjN' + + 'cNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg=='; + + var _getDefaults = function() { + return { + view: { + projection: 'EPSG:3857', + minZoom: undefined, + maxZoom: undefined, + rotation: 0, + extent: undefined + }, + center: { + lat: 0, + lon: 0, + zoom: 1, + autodiscover: false, + bounds: [], + centerUrlHash: false, + projection: 'EPSG:4326' + }, + styles: { + path: { + stroke: { + color: 'blue', + width: 8 + } + }, + marker: { + image: new ol.style.Icon({ + anchor: [0.5, 1], + anchorXUnits: 'fraction', + anchorYUnits: 'fraction', + opacity: 0.90, + src: base64icon + }) + } + }, + events: { + map: [], + markers: [], + layers: [] + }, + controls: { + attribution: true, + rotate: false, + zoom: true + }, + interactions: { + mouseWheelZoom: false + }, + renderer: 'canvas' + }; + }; + + var isDefined = olHelpers.isDefined; + var defaults = {}; + + // Get the _defaults dictionary, and override the properties defined by the user + return { + getDefaults: function(scope) { + if (!isDefined(scope)) { + for (var i in defaults) { + return defaults[i]; + } + } + return defaults[scope.$id]; + }, + + setDefaults: function(scope) { + var userDefaults = scope.defaults; + var scopeId = scope.$id; + var newDefaults = _getDefaults(); + + if (isDefined(userDefaults)) { + + if (isDefined(userDefaults.layers)) { + newDefaults.layers = angular.copy(userDefaults.layers); + } + + if (isDefined(userDefaults.controls)) { + newDefaults.controls = angular.copy(userDefaults.controls); + } + + if (isDefined(userDefaults.events)) { + newDefaults.events = angular.copy(userDefaults.events); + } + + if (isDefined(userDefaults.interactions)) { + newDefaults.interactions = angular.copy(userDefaults.interactions); + } + + if (isDefined(userDefaults.renderer)) { + newDefaults.renderer = userDefaults.renderer; + } + + if (isDefined(userDefaults.view)) { + newDefaults.view.maxZoom = userDefaults.view.maxZoom || newDefaults.view.maxZoom; + newDefaults.view.minZoom = userDefaults.view.minZoom || newDefaults.view.minZoom; + newDefaults.view.projection = userDefaults.view.projection || newDefaults.view.projection; + newDefaults.view.extent = userDefaults.view.extent || newDefaults.view.extent; + } + + if (isDefined(userDefaults.styles)) { + newDefaults.styles = angular.extend(newDefaults.styles, userDefaults.styles); + } + + } + + defaults[scopeId] = newDefaults; + return newDefaults; + } + }; +}); + +})); \ No newline at end of file diff --git a/src/services/olHelpers.js b/src/services/olHelpers.js index 5a27733a..f53faeb5 100644 --- a/src/services/olHelpers.js +++ b/src/services/olHelpers.js @@ -208,7 +208,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: url, attributions: createAttribution(source), tilePixelRatio: pixelRatio > 1 ? 2 : 1, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; case 'ImageWMS': @@ -221,7 +221,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, - wrapX: source.wrapX ? source.wrapX : true + wrapX: source.wrapX ? 0 : 1 }); break; @@ -235,7 +235,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, attributions: createAttribution(source), - wrapX: source.wrapX ? source.wrapX : true + wrapX: source.wrapX ? 0 : 1 }; if (source.url) { @@ -268,7 +268,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ resolutions: source.tileGrid.resolutions, matrixIds: source.tileGrid.matrixIds }), - wrapX: source.wrapX ? source.wrapX : true + wrapX: source.wrapX ? 0 : 1 }; if (isDefined(source.url)) { @@ -285,7 +285,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ case 'OSM': oSource = new ol.source.OSM({ attributions: createAttribution(source), - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); if (source.url) { @@ -304,7 +304,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], culture: source.culture, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }; if (source.maxZoom) { @@ -323,7 +323,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.MapQuest({ attributions: createAttribution(source), layer: source.layer, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; @@ -340,7 +340,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.XYZ({ attributions: createAttribution(source), url: _url, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; @@ -356,7 +356,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.Vector({ format: new ol.format.GeoJSON(), url: source.url, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); } else { oSource = new ol.source.Vector(); @@ -392,7 +392,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ $log(response); }); }, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); } break; @@ -407,12 +407,12 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.Vector({ format: new ol.format.TopoJSON(), url: source.url, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); } else { oSource = new ol.source.Vector(angular.extend(source.topojson, { format: new ol.format.TopoJSON(), - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 })); } break; @@ -421,7 +421,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: source.url, attributions: createAttribution(source), crossOrigin: 'anonymous', - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; @@ -437,7 +437,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ tileGrid: new ol.tilegrid.createXYZ({ maxZoom: source.maxZoom || 19 }), - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; @@ -467,7 +467,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ return url; }, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; case 'TileImage': @@ -488,7 +488,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ .replace('{y}', y.toString()); return url; }, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; case 'KML': @@ -498,7 +498,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ format: new ol.format.KML(), radius: source.radius, extractStyles: extractStyles, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; case 'Stamen': @@ -508,7 +508,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ } oSource = new ol.source.Stamen({ layer: source.layer, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; case 'ImageStatic': @@ -524,7 +524,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ projection: projection, imageExtent: projection.getExtent(), imageLoadFunction: source.imageLoadFunction, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; case 'XYZ': @@ -536,7 +536,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), minZoom: source.minZoom, maxZoom: source.maxZoom, - wrapX: source.wrapX ? source.wrapX : true + wrapX: (source.wrapX === true) ? 1 : 0 }); break; } From 13b697fe0a080024b79fee0857315cb74db6b3ae Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 6 Nov 2015 15:25:24 +0530 Subject: [PATCH 3/7] added dist/ to .gitignore to give pullrequest --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 352ad9bc..57eb4608 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ lib temp node_modules/ bower_components/ +dist/ libpeerconnection.log *.swp .*.swp From 707abda2bf21178145d2d877ba5dc92d4491230c Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 6 Nov 2015 15:30:54 +0530 Subject: [PATCH 4/7] deleted dist folder for pull request --- dist/angular-openlayers-directive.css | 58 - dist/angular-openlayers-directive.js | 2228 ----------------- dist/angular-openlayers-directive.min.js | 31 - ...ular-openlayers-directive.min.no-header.js | 2 - dist/angular-openlayers-directive.pre.js | 2228 ----------------- 5 files changed, 4547 deletions(-) delete mode 100644 dist/angular-openlayers-directive.css delete mode 100644 dist/angular-openlayers-directive.js delete mode 100644 dist/angular-openlayers-directive.min.js delete mode 100644 dist/angular-openlayers-directive.min.no-header.js delete mode 100644 dist/angular-openlayers-directive.pre.js diff --git a/dist/angular-openlayers-directive.css b/dist/angular-openlayers-directive.css deleted file mode 100644 index fd9933e0..00000000 --- a/dist/angular-openlayers-directive.css +++ /dev/null @@ -1,58 +0,0 @@ -.popup-label { - background-color: #fff; - border: 2px #444 solid; - border-radius: 7px; - -webkit-box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); - -moz-box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); - box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); - color: #111; - font: 12px/20px "Helvetica Neue", Arial, Helvetica, sans-serif; - font-weight: bold; - padding: 3px 6px; - position: absolute; - white-space: nowrap; - top: -35px; - left: 20px; - display: none; -} - -.popup-label img { - vertical-align: middle; -} - -.popup-label.marker:before { - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - content: ""; - border-right: 6px solid black; - border-right-color: inherit; - position: absolute; - left: -8px; - top: 5px; -} - -.angular-openlayers-map:-moz-full-screen { - height: 100%; -} -.angular-openlayers-map:-webkit-full-screen { - height: 100%; -} -.angular-openlayers-map:full-screen { - height: 100%; -} - -.angular-openlayers-map:not(-moz-full-screen) { - height: 400px; -} - -.angular-openlayers-map:not(-webkit-full-screen) { - height: 400px; -} - -.angular-openlayers-map:not(full-screen) { - height: 400px; -} -.ol-full-screen { - position: absolute; - top: 50%; -} diff --git a/dist/angular-openlayers-directive.js b/dist/angular-openlayers-directive.js deleted file mode 100644 index 2c1e55c8..00000000 --- a/dist/angular-openlayers-directive.js +++ /dev/null @@ -1,2228 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. - define(['ol'], function (ol) { - return root.angularOpenlayersDirective = factory(ol); - }); - } else { - // Browser globals - root.angularOpenlayersDirective = factory(root.ol); - } -}(this, function (ol) { -angular.module('openlayers-directive', ['ngSanitize']).directive('openlayers', ["$log", "$q", "$compile", "olHelpers", "olMapDefaults", "olData", function($log, $q, $compile, olHelpers, - olMapDefaults, olData) { - return { - restrict: 'EA', - transclude: true, - replace: true, - scope: { - center: '=olCenter', - defaults: '=olDefaults', - view: '=olView', - events: '=olEvents' - }, - template: '
', - controller: ["$scope", function($scope) { - var _map = $q.defer(); - $scope.getMap = function() { - return _map.promise; - }; - - $scope.setMap = function(map) { - _map.resolve(map); - }; - - this.getOpenlayersScope = function() { - return $scope; - }; - }], - link: function(scope, element, attrs) { - var isDefined = olHelpers.isDefined; - var createLayer = olHelpers.createLayer; - var setMapEvents = olHelpers.setMapEvents; - var setViewEvents = olHelpers.setViewEvents; - var createView = olHelpers.createView; - var defaults = olMapDefaults.setDefaults(scope); - - // Set width and height if they are defined - if (isDefined(attrs.width)) { - if (isNaN(attrs.width)) { - element.css('width', attrs.width); - } else { - element.css('width', attrs.width + 'px'); - } - } - - if (isDefined(attrs.height)) { - if (isNaN(attrs.height)) { - element.css('height', attrs.height); - } else { - element.css('height', attrs.height + 'px'); - } - } - - if (isDefined(attrs.lat)) { - defaults.center.lat = parseFloat(attrs.lat); - } - - if (isDefined(attrs.lon)) { - defaults.center.lon = parseFloat(attrs.lon); - } - - if (isDefined(attrs.zoom)) { - defaults.center.zoom = parseFloat(attrs.zoom); - } - - var controls = ol.control.defaults(defaults.controls); - var interactions = ol.interaction.defaults(defaults.interactions); - var view = createView(defaults.view); - - // Create the Openlayers Map Object with the options - var map = new ol.Map({ - target: element[0], - controls: controls, - interactions: interactions, - renderer: defaults.renderer, - view: view - }); - - // If no layer is defined, set the default tileLayer - if (!attrs.customLayers) { - var l = { - type: 'Tile', - source: { - type: 'OSM' - } - }; - var layer = createLayer(l, view.getProjection(), 'default'); - map.addLayer(layer); - map.set('default', true); - } - - if (!isDefined(attrs.olCenter)) { - var c = ol.proj.transform([defaults.center.lon, - defaults.center.lat - ], - defaults.center.projection, view.getProjection() - ); - view.setCenter(c); - view.setZoom(defaults.center.zoom); - } - - // Set the Default events for the map - setMapEvents(defaults.events, map, scope); - - //Set the Default events for the map view - setViewEvents(defaults.events, map, scope); - - // Resolve the map object to the promises - scope.setMap(map); - olData.setMap(map, attrs.id); - - } - }; - }]); - -angular.module('openlayers-directive').directive('olCenter', ["$log", "$location", "olMapDefaults", "olHelpers", function($log, $location, olMapDefaults, olHelpers) { - - return { - restrict: 'A', - scope: false, - replace: false, - require: 'openlayers', - - link: function(scope, element, attrs, controller) { - var safeApply = olHelpers.safeApply; - var isValidCenter = olHelpers.isValidCenter; - var isDefined = olHelpers.isDefined; - var isArray = olHelpers.isArray; - var isNumber = olHelpers.isNumber; - var isSameCenterOnMap = olHelpers.isSameCenterOnMap; - var setCenter = olHelpers.setCenter; - var setZoom = olHelpers.setZoom; - var olScope = controller.getOpenlayersScope(); - - olScope.getMap().then(function(map) { - var defaults = olMapDefaults.getDefaults(olScope); - var view = map.getView(); - var center = olScope.center; - - if (attrs.olCenter.search('-') !== -1) { - $log.error('[AngularJS - Openlayers] The "center" variable can\'t use ' + - 'a "-" on his key name: "' + attrs.center + '".'); - setCenter(view, defaults.view.projection, defaults.center, map); - return; - } - - if (!isDefined(center)) { - center = {}; - } - - if (!isValidCenter(center)) { - $log.warn('[AngularJS - Openlayers] invalid \'center\''); - center.lat = defaults.center.lat; - center.lon = defaults.center.lon; - center.zoom = defaults.center.zoom; - center.projection = defaults.center.projection; - } - - if (!center.projection) { - if (defaults.view.projection !== 'pixel') { - center.projection = defaults.center.projection; - } else { - center.projection = 'pixel'; - } - } - - if (!isNumber(center.zoom)) { - center.zoom = 1; - } - - setCenter(view, defaults.view.projection, center, map); - view.setZoom(center.zoom); - - var centerUrlHash; - if (center.centerUrlHash === true) { - var extractCenterFromUrl = function() { - var search = $location.search(); - var centerParam; - if (isDefined(search.c)) { - var cParam = search.c.split(':'); - if (cParam.length === 3) { - centerParam = { - lat: parseFloat(cParam[0]), - lon: parseFloat(cParam[1]), - zoom: parseInt(cParam[2], 10) - }; - } - } - return centerParam; - }; - centerUrlHash = extractCenterFromUrl(); - - olScope.$on('$locationChangeSuccess', function() { - var urlCenter = extractCenterFromUrl(); - if (urlCenter && !isSameCenterOnMap(urlCenter, map)) { - safeApply(olScope, function(scope) { - scope.center.lat = urlCenter.lat; - scope.center.lon = urlCenter.lon; - scope.center.zoom = urlCenter.zoom; - }); - } - }); - } - - var geolocation; - olScope.$watchCollection('center', function(center) { - - if (!center) { - return; - } - - if (!center.projection) { - center.projection = defaults.center.projection; - } - - if (center.autodiscover) { - if (!geolocation) { - geolocation = new ol.Geolocation({ - projection: ol.proj.get(center.projection) - }); - - geolocation.on('change', function() { - if (center.autodiscover) { - var location = geolocation.getPosition(); - safeApply(olScope, function(scope) { - scope.center.lat = location[1]; - scope.center.lon = location[0]; - scope.center.zoom = 12; - scope.center.autodiscover = false; - geolocation.setTracking(false); - }); - } - }); - } - geolocation.setTracking(true); - return; - } - - if (!isValidCenter(center)) { - $log.warn('[AngularJS - Openlayers] invalid \'center\''); - center = defaults.center; - } - - var viewCenter = view.getCenter(); - if (viewCenter) { - if (defaults.view.projection === 'pixel') { - view.setCenter(center.coord); - return; - } - var actualCenter = ol.proj.transform(viewCenter, defaults.view.projection, center.projection); - if (!(actualCenter[1] === center.lat && actualCenter[0] === center.lon)) { - setCenter(view, defaults.view.projection, center, map); - } - } - - if (view.getZoom() !== center.zoom) { - setZoom(view, center.zoom, map); - } - }); - - map.on('moveend', function() { - safeApply(olScope, function(scope) { - - if (!isDefined(scope.center)) { - return; - } - - var center = map.getView().getCenter(); - scope.center.zoom = view.getZoom(); - - if (defaults.view.projection === 'pixel') { - scope.center.coord = center; - return; - } - - if (scope.center) { - var proj = ol.proj.transform(center, defaults.view.projection, scope.center.projection); - scope.center.lat = proj[1]; - scope.center.lon = proj[0]; - - // Notify the controller about a change in the center position - olHelpers.notifyCenterUrlHashChanged(olScope, scope.center, $location.search()); - - // Calculate the bounds if needed - if (isArray(scope.center.bounds)) { - var extent = view.calculateExtent(map.getSize()); - var centerProjection = scope.center.projection; - var viewProjection = defaults.view.projection; - scope.center.bounds = ol.proj.transformExtent(extent, viewProjection, centerProjection); - } - } - }); - }); - - }); - } - }; -}]); - -angular.module('openlayers-directive').directive('olLayer', ["$log", "$q", "olMapDefaults", "olHelpers", function($log, $q, olMapDefaults, olHelpers) { - - return { - restrict: 'E', - scope: { - properties: '=olLayerProperties' - }, - replace: false, - require: '^openlayers', - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var equals = olHelpers.equals; - var olScope = controller.getOpenlayersScope(); - var createLayer = olHelpers.createLayer; - var setVectorLayerEvents = olHelpers.setVectorLayerEvents; - var detectLayerType = olHelpers.detectLayerType; - var createStyle = olHelpers.createStyle; - var isBoolean = olHelpers.isBoolean; - var addLayerBeforeMarkers = olHelpers.addLayerBeforeMarkers; - var isNumber = olHelpers.isNumber; - var insertLayer = olHelpers.insertLayer; - var removeLayer = olHelpers.removeLayer; - var addLayerToGroup = olHelpers.addLayerToGroup; - var removeLayerFromGroup = olHelpers.removeLayerFromGroup; - var getGroup = olHelpers.getGroup; - - olScope.getMap().then(function(map) { - var projection = map.getView().getProjection(); - var defaults = olMapDefaults.setDefaults(olScope); - var layerCollection = map.getLayers(); - var olLayer; - - scope.$on('$destroy', function() { - if (scope.properties.group) { - removeLayerFromGroup(layerCollection, olLayer, scope.properties.group); - } else { - removeLayer(layerCollection, olLayer.index); - } - - map.removeLayer(olLayer); - }); - - if (!isDefined(scope.properties)) { - if (isDefined(attrs.sourceType) && isDefined(attrs.sourceUrl)) { - var l = { - source: { - url: attrs.sourceUrl, - type: attrs.sourceType - } - }; - - olLayer = createLayer(l, projection, attrs.layerName); - if (detectLayerType(l) === 'Vector') { - setVectorLayerEvents(defaults.events, map, scope, attrs.name); - } - addLayerBeforeMarkers(layerCollection, olLayer); - } - return; - } - - scope.$watch('properties', function(properties, oldProperties) { - if (!isDefined(properties.source) || !isDefined(properties.source.type)) { - return; - } - - if (!isDefined(properties.visible)) { - properties.visible = true; - return; - } - - if (!isDefined(properties.opacity)) { - properties.opacity = 1; - return; - } - - var style; - var group; - var collection; - if (!isDefined(olLayer)) { - olLayer = createLayer(properties, projection); - if (isDefined(properties.group)) { - addLayerToGroup(layerCollection, olLayer, properties.group); - } else if (isDefined(properties.index)) { - insertLayer(layerCollection, properties.index, olLayer); - } else { - addLayerBeforeMarkers(layerCollection, olLayer); - } - - if (detectLayerType(properties) === 'Vector') { - setVectorLayerEvents(defaults.events, map, scope, properties.name); - } - - if (isBoolean(properties.visible)) { - olLayer.setVisible(properties.visible); - } - - if (properties.opacity) { - olLayer.setOpacity(properties.opacity); - } - - if (angular.isArray(properties.extent)) { - olLayer.setExtent(properties.extent); - } - - if (properties.style) { - if (!angular.isFunction(properties.style)) { - style = createStyle(properties.style); - } else { - style = properties.style; - } - // not every layer has a setStyle method - if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { - olLayer.setStyle(style); - } - } - - } else { - var isNewLayer = (function(olLayer) { - // this function can be used to verify whether a new layer instance has - // been created. This is needed in order to re-assign styles, opacity - // etc... - return function(layer) { - return layer !== olLayer; - }; - })(olLayer); - - // set source properties - if (isDefined(oldProperties) && !equals(properties.source, oldProperties.source)) { - var idx = olLayer.index; - collection = layerCollection; - group = olLayer.get('group'); - - if (group) { - collection = getGroup(layerCollection, group).getLayers(); - } - - collection.removeAt(idx); - - olLayer = createLayer(properties, projection); - olLayer.set('group', group); - - if (isDefined(olLayer)) { - insertLayer(collection, idx, olLayer); - - if (detectLayerType(properties) === 'Vector') { - setVectorLayerEvents(defaults.events, map, scope, properties.name); - } - } - } - - // set opacity - if (isDefined(oldProperties) && - properties.opacity !== oldProperties.opacity || isNewLayer(olLayer)) { - if (isNumber(properties.opacity) || isNumber(parseFloat(properties.opacity))) { - olLayer.setOpacity(properties.opacity); - } - } - - // set index - if (isDefined(properties.index) && properties.index !== olLayer.index) { - collection = layerCollection; - group = olLayer.get('group'); - - if (group) { - collection = getGroup(layerCollection, group).getLayers(); - } - - removeLayer(collection, olLayer.index); - insertLayer(collection, properties.index, olLayer); - } - - // set group - if (isDefined(properties.group) && properties.group !== oldProperties.group) { - removeLayerFromGroup(layerCollection, olLayer, oldProperties.group); - addLayerToGroup(layerCollection, olLayer, properties.group); - } - - // set visibility - if (isDefined(oldProperties) && - isBoolean(properties.visible) && - properties.visible !== oldProperties.visible || isNewLayer(olLayer)) { - olLayer.setVisible(properties.visible); - } - - // set style - if (isDefined(properties.style) && - !equals(properties.style, oldProperties.style) || isNewLayer(olLayer)) { - if (!angular.isFunction(properties.style)) { - style = createStyle(properties.style); - } else { - style = properties.style; - } - // not every layer has a setStyle method - if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { - olLayer.setStyle(style); - } - } - } - }, true); - }); - } - }; -}]); - -angular.module('openlayers-directive').directive('olPath', ["$log", "$q", "olMapDefaults", "olHelpers", function($log, $q, olMapDefaults, olHelpers) { - - return { - restrict: 'E', - scope: { - properties: '=olGeomProperties' - }, - require: '^openlayers', - replace: true, - template: '', - - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var createFeature = olHelpers.createFeature; - var createOverlay = olHelpers.createOverlay; - var createVectorLayer = olHelpers.createVectorLayer; - var insertLayer = olHelpers.insertLayer; - var removeLayer = olHelpers.removeLayer; - var olScope = controller.getOpenlayersScope(); - - olScope.getMap().then(function(map) { - var mapDefaults = olMapDefaults.getDefaults(olScope); - var viewProjection = mapDefaults.view.projection; - - var layer = createVectorLayer(); - var layerCollection = map.getLayers(); - - insertLayer(layerCollection, layerCollection.getLength(), layer); - - scope.$on('$destroy', function() { - removeLayer(layerCollection, layer.index); - }); - - if (isDefined(attrs.coords)) { - var proj = attrs.proj || 'EPSG:4326'; - var coords = JSON.parse(attrs.coords); - var data = { - type: 'Polygon', - coords: coords, - projection: proj, - style: mapDefaults.styles.path - }; - var feature = createFeature(data, viewProjection); - layer.getSource().addFeature(feature); - - if (attrs.message) { - scope.message = attrs.message; - var extent = feature.getGeometry().getExtent(); - var label = createOverlay(element, extent); - map.addOverlay(label); - } - return; - } - }); - } - }; -}]); - -angular.module('openlayers-directive').directive('olView', ["$log", "$q", "olData", "olMapDefaults", "olHelpers", function($log, $q, olData, olMapDefaults, olHelpers) { - return { - restrict: 'A', - scope: false, - replace: false, - require: 'openlayers', - link: function(scope, element, attrs, controller) { - var olScope = controller.getOpenlayersScope(); - var isNumber = olHelpers.isNumber; - var safeApply = olHelpers.safeApply; - var createView = olHelpers.createView; - - olScope.getMap().then(function(map) { - var defaults = olMapDefaults.getDefaults(olScope); - var view = olScope.view; - - if (!view.projection) { - view.projection = defaults.view.projection; - } - - if (!view.maxZoom) { - view.maxZoom = defaults.view.maxZoom; - } - - if (!view.minZoom) { - view.minZoom = defaults.view.minZoom; - } - - if (!view.rotation) { - view.rotation = defaults.view.rotation; - } - - var mapView = createView(view); - map.setView(mapView); - - olScope.$watchCollection('view', function(view) { - if (isNumber(view.rotation)) { - mapView.setRotation(view.rotation); - } - }); - - mapView.on('change:rotation', function() { - safeApply(olScope, function(scope) { - scope.view.rotation = map.getView().getRotation(); - }); - }); - - }); - } - }; -}]); - -angular.module('openlayers-directive').directive('olControl', ["$log", "$q", "olData", "olMapDefaults", "olHelpers", function($log, $q, olData, olMapDefaults, olHelpers) { - - return { - restrict: 'E', - scope: { - properties: '=olControlProperties' - }, - replace: false, - require: '^openlayers', - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var olScope = controller.getOpenlayersScope(); - var olControl; - var olControlOps; - - olScope.getMap().then(function(map) { - var getControlClasses = olHelpers.getControlClasses; - var controlClasses = getControlClasses(); - - scope.$on('$destroy', function() { - map.removeControl(olControl); - }); - - if (!isDefined(scope.properties) || !isDefined(scope.properties.control)) { - if (attrs.name) { - if (isDefined(scope.properties)) { - olControlOps = scope.properties; - } - olControl = new controlClasses[attrs.name](olControlOps); - map.addControl(olControl); - } - return; - } - - olControl = scope.properties.control; - map.addControl(olControl); - }); - } - }; -}]); - -angular.module('openlayers-directive').directive('olMarker', ["$log", "$q", "olMapDefaults", "olHelpers", function($log, $q, olMapDefaults, olHelpers) { - - var getMarkerDefaults = function() { - return { - projection: 'EPSG:4326', - lat: 0, - lon: 0, - coord: [], - show: true, - showOnMouseOver: false, - showOnMouseClick: false, - keepOneOverlayVisible: false - }; - }; - - var markerLayerManager = (function() { - var mapDict = []; - - function getMapIndex(map) { - return mapDict.map(function(record) { - return record.map; - }).indexOf(map); - } - - return { - getInst: function getMarkerLayerInst(scope, map) { - var mapIndex = getMapIndex(map); - - if (mapIndex === -1) { - var markerLayer = olHelpers.createVectorLayer(); - markerLayer.set('markers', true); - map.addLayer(markerLayer); - mapDict.push({ - map: map, - markerLayer: markerLayer, - instScopes: [] - }); - mapIndex = mapDict.length - 1; - } - - mapDict[mapIndex].instScopes.push(scope); - - return mapDict[mapIndex].markerLayer; - }, - deregisterScope: function deregisterScope(scope, map) { - var mapIndex = getMapIndex(map); - if (mapIndex === -1) { - throw Error('This map has no markers'); - } - - var scopes = mapDict[mapIndex].instScopes; - var scopeIndex = scopes.indexOf(scope); - if (scopeIndex === -1) { - throw Error('Scope wan\'t registered'); - } - - scopes.splice(scopeIndex, 1); - - if (!scopes.length) { - map.removeLayer(mapDict[mapIndex].markerLayer); - delete mapDict[mapIndex]; - } - } - }; - })(); - return { - restrict: 'E', - scope: { - lat: '=lat', - lon: '=lon', - label: '=label', - properties: '=olMarkerProperties', - style: '=olStyle' - }, - transclude: true, - require: '^openlayers', - replace: true, - template: - '', - - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var olScope = controller.getOpenlayersScope(); - var createFeature = olHelpers.createFeature; - var createOverlay = olHelpers.createOverlay; - - var hasTranscluded = element.find('ng-transclude').children().length > 0; - - olScope.getMap().then(function(map) { - var markerLayer = markerLayerManager.getInst(scope, map); - var data = getMarkerDefaults(); - - var mapDefaults = olMapDefaults.getDefaults(olScope); - var viewProjection = mapDefaults.view.projection; - var label; - var pos; - var marker; - - // This function handles dragging a marker - var pickOffset = null; - var pickProperties = null; - function handleDrag(evt) { - var coord = evt.coordinate; - var proj = map.getView().getProjection().getCode(); - if (proj === 'pixel') { - coord = coord.map(function(v) { - return parseInt(v, 10); - }); - } else { - coord = ol.proj.transform(coord, proj, 'EPSG:4326'); - } - - if (evt.type === 'pointerdown') { - // Get feature under mouse if any - var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { - return feature; - }); - // Get associated marker properties - pickProperties = (feature ? feature.get('marker') : null); - if (!pickProperties || !pickProperties.draggable) { - pickProperties = null; - return; - } - map.getTarget().style.cursor = 'pointer'; - if (proj === 'pixel') { - pickOffset = [coord[0] - pickProperties.coord[0], coord[1] - pickProperties.coord[1]]; - } else { - pickOffset = [coord[0] - pickProperties.lon, coord[1] - pickProperties.lat]; - } - evt.preventDefault(); - } else if (pickOffset && pickProperties) { - if (evt.type === 'pointerup') { - map.getTarget().style.cursor = ''; - pickOffset = null; - pickProperties = null; - evt.preventDefault(); - } else if (evt.type === 'pointerdrag') { - evt.preventDefault(); - scope.$apply(function() { - // Add current delta to marker initial position - if (proj === 'pixel') { - pickProperties.coord[0] = coord[0] - pickOffset[0]; - pickProperties.coord[1] = coord[1] - pickOffset[1]; - } else { - pickProperties.lon = coord[0] - pickOffset[0]; - pickProperties.lat = coord[1] - pickOffset[1]; - } - }); - } - } - } - - // Setup generic handlers for marker drag - map.on('pointerdown', handleDrag); - map.on('pointerup', handleDrag); - map.on('pointerdrag', handleDrag); - - scope.$on('$destroy', function() { - markerLayer.getSource().removeFeature(marker); - if (isDefined(label)) { - map.removeOverlay(label); - } - markerLayerManager.deregisterScope(scope, map); - }); - - if (!isDefined(scope.properties)) { - data.lat = scope.lat ? scope.lat : data.lat; - data.lon = scope.lon ? scope.lon : data.lon; - data.message = attrs.message; - data.style = scope.style ? scope.style : mapDefaults.styles.marker; - - marker = createFeature(data, viewProjection); - if (!isDefined(marker)) { - $log.error('[AngularJS - Openlayers] Received invalid data on ' + - 'the marker.'); - } - // Add a link between the feature and the marker properties - marker.set('marker', scope); - markerLayer.getSource().addFeature(marker); - - if (data.message || hasTranscluded) { - scope.message = attrs.message; - pos = ol.proj.transform([data.lon, data.lat], data.projection, - viewProjection); - label = createOverlay(element, pos); - map.addOverlay(label); - } - return; - } - - scope.$watch('properties', function(properties) { - - // Remove previous listeners if any - map.getViewport().removeEventListener('mousemove', properties.handleInteraction); - map.getViewport().removeEventListener('click', properties.handleTapInteraction); - map.getViewport().querySelector('canvas.ol-unselectable').removeEventListener( - 'touchend', properties.handleTapInteraction); - map.getViewport().removeEventListener('mousemove', properties.showAtLeastOneOverlay); - map.getViewport().removeEventListener('click', properties.removeAllOverlays); - - // This function handles popup on mouse over/click - properties.handleInteraction = function(evt) { - if (properties.label.show) { - return; - } - var found = false; - var pixel = map.getEventPixel(evt); - var feature = map.forEachFeatureAtPixel(pixel, function(feature) { - return feature; - }); - - var actionTaken = false; - if (feature === marker) { - actionTaken = true; - found = true; - if (!isDefined(label)) { - if (data.projection === 'pixel') { - pos = properties.coord; - } else { - pos = ol.proj.transform([properties.lon, properties.lat], - data.projection, viewProjection); - } - label = createOverlay(element, pos); - map.addOverlay(label); - } - - if (properties.onClick && (evt.type === 'click' || evt.type === 'touchend')) { - scope.$apply(function() { - properties.onClick.call(marker, evt, properties); - }); - } - map.getTarget().style.cursor = 'pointer'; - } - - if (!found && label) { - actionTaken = true; - map.removeOverlay(label); - label = undefined; - map.getTarget().style.cursor = ''; - } - - if (actionTaken) { - evt.preventDefault(); - } - }; - - // Made to filter out click/tap events if both are being triggered on this platform - properties.handleTapInteraction = (function() { - var cooldownActive = false; - var prevTimeout; - - // Sets the cooldown flag to filter out any subsequent events within 500 ms - function activateCooldown() { - cooldownActive = true; - if (prevTimeout) { - clearTimeout(prevTimeout); - } - prevTimeout = setTimeout(function() { - cooldownActive = false; - prevTimeout = null; - }, 500); - } - - // Preventing from 'touchend' to be considered a tap, if fired immediately after 'touchmove' - map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( - 'touchmove', activateCooldown); - - return function() { - if (!cooldownActive) { - properties.handleInteraction.apply(null, arguments); - activateCooldown(); - } - }; - })(); - - properties.showAtLeastOneOverlay = function(evt) { - if (properties.label.show) { - return; - } - var found = false; - var pixel = map.getEventPixel(evt); - var feature = map.forEachFeatureAtPixel(pixel, function(feature) { - return feature; - }); - - var actionTaken = false; - if (feature === marker) { - actionTaken = true; - found = true; - if (!isDefined(label)) { - if (data.projection === 'pixel') { - pos = data.coord; - } else { - pos = ol.proj.transform([data.lon, data.lat], - data.projection, viewProjection); - } - label = createOverlay(element, pos); - angular.forEach(map.getOverlays(), function(value) { - map.removeOverlay(value); - }); - map.addOverlay(label); - } - map.getTarget().style.cursor = 'pointer'; - } - - if (!found && label) { - actionTaken = true; - label = undefined; - map.getTarget().style.cursor = ''; - } - - if (actionTaken) { - evt.preventDefault(); - } - }; - - properties.removeAllOverlays = function(evt) { - angular.forEach(map.getOverlays(), function(value) { - map.removeOverlay(value); - }); - evt.preventDefault(); - }; - - if (!isDefined(marker)) { - data.projection = properties.projection ? properties.projection : - data.projection; - data.coord = properties.coord ? properties.coord : data.coord; - data.lat = properties.lat ? properties.lat : data.lat; - data.lon = properties.lon ? properties.lon : data.lon; - - if (isDefined(properties.style)) { - data.style = properties.style; - } else { - data.style = mapDefaults.styles.marker; - } - - marker = createFeature(data, viewProjection); - if (!isDefined(marker)) { - $log.error('[AngularJS - Openlayers] Received invalid data on ' + - 'the marker.'); - } - // Add a link between the feature and the marker properties - marker.set('marker', properties); - markerLayer.getSource().addFeature(marker); - } else { - var requestedPosition; - if (properties.projection === 'pixel') { - requestedPosition = properties.coord; - } else { - requestedPosition = ol.proj.transform([properties.lon, properties.lat], data.projection, - map.getView().getProjection()); - } - - if (!angular.equals(marker.getGeometry().getCoordinates(), requestedPosition)) { - var geometry = new ol.geom.Point(requestedPosition); - marker.setGeometry(geometry); - } - } - - if (isDefined(label)) { - map.removeOverlay(label); - } - - if (!isDefined(properties.label)) { - return; - } - - scope.message = properties.label.message; - if (!hasTranscluded && (!isDefined(scope.message) || scope.message.length === 0)) { - return; - } - - if (properties.label && properties.label.show === true) { - if (data.projection === 'pixel') { - pos = data.coord; - } else { - pos = ol.proj.transform([properties.lon, properties.lat], data.projection, - viewProjection); - } - label = createOverlay(element, pos); - map.addOverlay(label); - } - - if (label && properties.label && properties.label.show === false) { - map.removeOverlay(label); - label = undefined; - } - - // Then setup new ones according to properties - if (properties.label && properties.label.show === false && - properties.label.showOnMouseOver) { - map.getViewport().addEventListener('mousemove', properties.handleInteraction); - } - - if ((properties.label && properties.label.show === false && - properties.label.showOnMouseClick) || - properties.onClick) { - map.getViewport().addEventListener('click', properties.handleTapInteraction); - map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( - 'touchend', properties.handleTapInteraction); - } - - if ((properties.label && properties.label.show === false && - properties.label.keepOneOverlayVisible)) { - map.getViewport().addEventListener('mousemove', properties.showAtLeastOneOverlay); - map.getViewport().addEventListener('click', properties.removeAllOverlays); - } - }, true); - }); - } - }; -}]); - -angular.module('openlayers-directive').service('olData', ["$log", "$q", "olHelpers", function($log, $q, olHelpers) { - - var obtainEffectiveMapId = olHelpers.obtainEffectiveMapId; - - var maps = {}; - - var setResolvedDefer = function(d, mapId) { - var id = obtainEffectiveMapId(d, mapId); - d[id].resolvedDefer = true; - }; - - var getUnresolvedDefer = function(d, mapId) { - var id = obtainEffectiveMapId(d, mapId); - var defer; - - if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) { - defer = $q.defer(); - d[id] = { - defer: defer, - resolvedDefer: false - }; - } else { - defer = d[id].defer; - } - return defer; - }; - - var getDefer = function(d, mapId) { - var id = obtainEffectiveMapId(d, mapId); - var defer; - - if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) { - defer = getUnresolvedDefer(d, mapId); - } else { - defer = d[id].defer; - } - return defer; - }; - - this.setMap = function(olMap, scopeId) { - var defer = getUnresolvedDefer(maps, scopeId); - defer.resolve(olMap); - setResolvedDefer(maps, scopeId); - }; - - this.getMap = function(scopeId) { - var defer = getDefer(maps, scopeId); - return defer.promise; - }; - -}]); - -angular.module('openlayers-directive').factory('olHelpers', ["$q", "$log", "$http", function($q, $log, $http) { - - var isDefined = function(value) { - return angular.isDefined(value); - }; - - var isDefinedAndNotNull = function(value) { - return angular.isDefined(value) && value !== null; - }; - - var setEvent = function(map, eventType, scope) { - map.on(eventType, function(event) { - var coord = event.coordinate; - var proj = map.getView().getProjection().getCode(); - if (proj === 'pixel') { - coord = coord.map(function(v) { - return parseInt(v, 10); - }); - } - scope.$emit('openlayers.map.' + eventType, { - 'coord': coord, - 'projection': proj, - 'event': event - }); - }); - }; - - var bingImagerySets = [ - 'Road', - 'Aerial', - 'AerialWithLabels', - 'collinsBart', - 'ordnanceSurvey' - ]; - - var getControlClasses = function() { - return { - attribution: ol.control.Attribution, - fullscreen: ol.control.FullScreen, - mouseposition: ol.control.MousePosition, - rotate: ol.control.Rotate, - scaleline: ol.control.ScaleLine, - zoom: ol.control.Zoom, - zoomslider: ol.control.ZoomSlider, - zoomtoextent: ol.control.ZoomToExtent - }; - }; - - var mapQuestLayers = ['osm', 'sat', 'hyb']; - - var esriBaseLayers = ['World_Imagery', 'World_Street_Map', 'World_Topo_Map', - 'World_Physical_Map', 'World_Terrain_Base', - 'Ocean_Basemap', 'NatGeo_World_Map']; - - var styleMap = { - 'style': ol.style.Style, - 'fill': ol.style.Fill, - 'stroke': ol.style.Stroke, - 'circle': ol.style.Circle, - 'icon': ol.style.Icon, - 'image': ol.style.Image, - 'regularshape': ol.style.RegularShape, - 'text': ol.style.Text - }; - - var optionalFactory = function(style, Constructor) { - if (Constructor && style instanceof Constructor) { - return style; - } else if (Constructor) { - return new Constructor(style); - } else { - return style; - } - }; - - //Parse the style tree calling the appropriate constructors. - //The keys in styleMap can be used and the OpenLayers constructors can be - //used directly. - var createStyle = function recursiveStyle(data, styleName) { - var style; - if (!styleName) { - styleName = 'style'; - style = data; - } else { - style = data[styleName]; - } - //Instead of defining one style for the layer, we've been given a style function - //to apply to each feature. - if (styleName === 'style' && data instanceof Function) { - return data; - } - - if (!(style instanceof Object)) { - return style; - } - - var styleObject; - if (Object.prototype.toString.call(style) === '[object Object]') { - styleObject = {}; - var styleConstructor = styleMap[styleName]; - if (styleConstructor && style instanceof styleConstructor) { - return style; - } - Object.getOwnPropertyNames(style).forEach(function(val, idx, array) { - //Consider the case - //image: { - // circle: { - // fill: { - // color: 'red' - // } - // } - // - //An ol.style.Circle is an instance of ol.style.Image, so we do not want to construct - //an Image and then construct a Circle. We assume that if we have an instanceof - //relationship, that the JSON parent has exactly one child. - //We check to see if an inheritance relationship exists. - //If it does, then for the parent we create an instance of the child. - var valConstructor = styleMap[val]; - if (styleConstructor && valConstructor && - valConstructor.prototype instanceof styleMap[styleName]) { - console.assert(array.length === 1, 'Extra parameters for ' + styleName); - styleObject = recursiveStyle(style, val); - return optionalFactory(styleObject, valConstructor); - } else { - styleObject[val] = recursiveStyle(style, val); - - // if the value is 'text' and it contains a String, then it should be interpreted - // as such, 'cause the text style might effectively contain a text to display - if (val !== 'text' && typeof styleObject[val] !== 'string') { - styleObject[val] = optionalFactory(styleObject[val], styleMap[val]); - } - } - }); - } else { - styleObject = style; - } - return optionalFactory(styleObject, styleMap[styleName]); - }; - - var detectLayerType = function(layer) { - if (layer.type) { - return layer.type; - } else { - switch (layer.source.type) { - case 'ImageWMS': - return 'Image'; - case 'ImageStatic': - return 'Image'; - case 'GeoJSON': - case 'JSONP': - case 'TopoJSON': - case 'KML': - case 'TileVector': - return 'Vector'; - default: - return 'Tile'; - } - } - }; - - var createProjection = function(view) { - var oProjection; - - switch (view.projection) { - case 'pixel': - if (!isDefined(view.extent)) { - $log.error('[AngularJS - Openlayers] - You must provide the extent of the image ' + - 'if using pixel projection'); - return; - } - oProjection = new ol.proj.Projection({ - code: 'pixel', - units: 'pixels', - extent: view.extent - }); - break; - default: - oProjection = new ol.proj.get(view.projection); - break; - } - - return oProjection; - }; - - var isValidStamenLayer = function(layer) { - return ['watercolor', 'terrain', 'toner'].indexOf(layer) !== -1; - }; - - var createSource = function(source, projection) { - var oSource; - - switch (source.type) { - case 'MapBox': - if (!source.mapId || !source.accessToken) { - $log.error('[AngularJS - Openlayers] - MapBox layer requires the map id and the access token'); - return; - } - var url = 'http://api.tiles.mapbox.com/v4/' + source.mapId + '/{z}/{x}/{y}.png?access_token=' + - source.accessToken; - - var pixelRatio = window.devicePixelRatio; - - if (pixelRatio > 1) { - url = url.replace('.png', '@2x.png'); - } - - oSource = new ol.source.XYZ({ - url: url, - attributions: createAttribution(source), - tilePixelRatio: pixelRatio > 1 ? 2 : 1, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'ImageWMS': - if (!source.url || !source.params) { - $log.error('[AngularJS - Openlayers] - ImageWMS Layer needs ' + - 'valid server url and params properties'); - } - oSource = new ol.source.ImageWMS({ - url: source.url, - attributions: createAttribution(source), - crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, - params: source.params, - wrapX: source.wrapX ? 0 : 1 - }); - break; - - case 'TileWMS': - if ((!source.url && !source.urls) || !source.params) { - $log.error('[AngularJS - Openlayers] - TileWMS Layer needs ' + - 'valid url (or urls) and params properties'); - } - - var wmsConfiguration = { - crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, - params: source.params, - attributions: createAttribution(source), - wrapX: source.wrapX ? 0 : 1 - }; - - if (source.url) { - wmsConfiguration.url = source.url; - } - - if (source.urls) { - wmsConfiguration.urls = source.urls; - } - - oSource = new ol.source.TileWMS(wmsConfiguration); - break; - - case 'WMTS': - if ((!source.url && !source.urls) || !source.tileGrid) { - $log.error('[AngularJS - Openlayers] - WMTS Layer needs valid url ' + - '(or urls) and tileGrid properties'); - } - - var wmtsConfiguration = { - projection: projection, - layer: source.layer, - attributions: createAttribution(source), - matrixSet: (source.matrixSet === 'undefined') ? projection : source.matrixSet, - format: (source.format === 'undefined') ? 'image/jpeg' : source.format, - requestEncoding: (source.requestEncoding === 'undefined') ? - 'KVP' : source.requestEncoding, - tileGrid: new ol.tilegrid.WMTS({ - origin: source.tileGrid.origin, - resolutions: source.tileGrid.resolutions, - matrixIds: source.tileGrid.matrixIds - }), - wrapX: source.wrapX ? 0 : 1 - }; - - if (isDefined(source.url)) { - wmtsConfiguration.url = source.url; - } - - if (isDefined(source.urls)) { - wmtsConfiguration.urls = source.urls; - } - - oSource = new ol.source.WMTS(wmtsConfiguration); - break; - - case 'OSM': - oSource = new ol.source.OSM({ - attributions: createAttribution(source), - wrapX: (source.wrapX === true) ? 1 : 0 - }); - - if (source.url) { - oSource.setUrl(source.url); - } - - break; - case 'BingMaps': - if (!source.key) { - $log.error('[AngularJS - Openlayers] - You need an API key to show the Bing Maps.'); - return; - } - - var bingConfiguration = { - key: source.key, - attributions: createAttribution(source), - imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], - culture: source.culture, - wrapX: (source.wrapX === true) ? 1 : 0 - }; - - if (source.maxZoom) { - bingConfiguration.maxZoom = source.maxZoom; - } - - oSource = new ol.source.BingMaps(bingConfiguration); - break; - - case 'MapQuest': - if (!source.layer || mapQuestLayers.indexOf(source.layer) === -1) { - $log.error('[AngularJS - Openlayers] - MapQuest layers needs a valid \'layer\' property.'); - return; - } - - oSource = new ol.source.MapQuest({ - attributions: createAttribution(source), - layer: source.layer, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - - break; - - case 'EsriBaseMaps': - if (!source.layer || esriBaseLayers.indexOf(source.layer) === -1) { - $log.error('[AngularJS - Openlayers] - ESRI layers needs a valid \'layer\' property.'); - return; - } - - var _urlBase = 'http://services.arcgisonline.com/ArcGIS/rest/services/'; - var _url = _urlBase + source.layer + '/MapServer/tile/{z}/{y}/{x}'; - - oSource = new ol.source.XYZ({ - attributions: createAttribution(source), - url: _url, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - - break; - - case 'GeoJSON': - if (!(source.geojson || source.url)) { - $log.error('[AngularJS - Openlayers] - You need a geojson ' + - 'property to add a GeoJSON layer.'); - return; - } - - if (isDefined(source.url)) { - oSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - url: source.url, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - } else { - oSource = new ol.source.Vector(); - - var projectionToUse = projection; - if (isDefined(source.geojson.projection)) { - projectionToUse = source.geojson.projection; - } - - var geojsonFormat = new ol.format.GeoJSON(); - var features = geojsonFormat.readFeatures( - source.geojson.object, { featureProjection: projectionToUse }); - - oSource.addFeatures(features); - } - - break; - case 'JSONP': - if (!(source.url)) { - $log.error('[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.'); - return; - } - - if (isDefined(source.url)) { - oSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - loader: function(/*extent, resolution, projection*/) { - var url = source.url + - '&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK'; - $http.jsonp(url, { cache: source.cache}).success(function(response) { - oSource.addFeatures(oSource.readFeatures(response)); - }).error(function(response) { - $log(response); - }); - }, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - } - break; - case 'TopoJSON': - if (!(source.topojson || source.url)) { - $log.error('[AngularJS - Openlayers] - You need a topojson ' + - 'property to add a TopoJSON layer.'); - return; - } - - if (source.url) { - oSource = new ol.source.Vector({ - format: new ol.format.TopoJSON(), - url: source.url, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - } else { - oSource = new ol.source.Vector(angular.extend(source.topojson, { - format: new ol.format.TopoJSON(), - wrapX: (source.wrapX === true) ? 1 : 0 - })); - } - break; - case 'TileJSON': - oSource = new ol.source.TileJSON({ - url: source.url, - attributions: createAttribution(source), - crossOrigin: 'anonymous', - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - - case 'TileVector': - if (!source.url || !source.format) { - $log.error('[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties'); - } - oSource = new ol.source.TileVector({ - url: source.url, - projection: projection, - attributions: createAttribution(source), - format: source.format, - tileGrid: new ol.tilegrid.createXYZ({ - maxZoom: source.maxZoom || 19 - }), - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - - case 'TileTMS': - if (!source.url || !source.tileGrid) { - $log.error('[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties'); - } - oSource = new ol.source.TileImage({ - url: source.url, - maxExtent: source.maxExtent, - attributions: createAttribution(source), - tileGrid: new ol.tilegrid.TileGrid({ - origin: source.tileGrid.origin, - resolutions: source.tileGrid.resolutions - }), - tileUrlFunction: function(tileCoord) { - - var z = tileCoord[0]; - var x = tileCoord[1]; - var y = tileCoord[2]; //(1 << z) - tileCoord[2] - 1; - - if (x < 0 || y < 0) { - return ''; - } - - var url = source.url + z + '/' + x + '/' + y + '.png'; - - return url; - }, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'TileImage': - oSource = new ol.source.TileImage({ - url: source.url, - attributions: createAttribution(source), - tileGrid: new ol.tilegrid.TileGrid({ - origin: source.tileGrid.origin, // top left corner of the pixel projection's extent - resolutions: source.tileGrid.resolutions - }), - tileUrlFunction: function(tileCoord/*, pixelRatio, projection*/) { - var z = tileCoord[0]; - var x = tileCoord[1]; - var y = -tileCoord[2] - 1; - var url = source.url - .replace('{z}', z.toString()) - .replace('{x}', x.toString()) - .replace('{y}', y.toString()); - return url; - }, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'KML': - var extractStyles = source.extractStyles || false; - oSource = new ol.source.Vector({ - url: source.url, - format: new ol.format.KML(), - radius: source.radius, - extractStyles: extractStyles, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'Stamen': - if (!source.layer || !isValidStamenLayer(source.layer)) { - $log.error('[AngularJS - Openlayers] - You need a valid Stamen layer.'); - return; - } - oSource = new ol.source.Stamen({ - layer: source.layer, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'ImageStatic': - if (!source.url || !angular.isArray(source.imageSize) || source.imageSize.length !== 2) { - $log.error('[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.'); - return; - } - - oSource = new ol.source.ImageStatic({ - url: source.url, - attributions: createAttribution(source), - imageSize: source.imageSize, - projection: projection, - imageExtent: projection.getExtent(), - imageLoadFunction: source.imageLoadFunction, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'XYZ': - if (!source.url) { - $log.error('[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties'); - } - oSource = new ol.source.XYZ({ - url: source.url, - attributions: createAttribution(source), - minZoom: source.minZoom, - maxZoom: source.maxZoom, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - } - - // log a warning when no source could be created for the given type - if (!oSource) { - $log.warn('[AngularJS - Openlayers] - No source could be found for type "' + source.type + '"'); - } - - return oSource; - }; - - var createAttribution = function(source) { - var attributions = []; - if (isDefined(source.attribution)) { - attributions.unshift(new ol.Attribution({html: source.attribution})); - } - return attributions; - }; - - var createGroup = function(name) { - var olGroup = new ol.layer.Group(); - olGroup.set('name', name); - - return olGroup; - }; - - var getGroup = function(layers, name) { - var layer; - - angular.forEach(layers, function(l) { - if (l instanceof ol.layer.Group && l.get('name') === name) { - layer = l; - return; - } - }); - - return layer; - }; - - var addLayerBeforeMarkers = function(layers, layer) { - var markersIndex; - for (var i = 0; i < layers.getLength(); i++) { - var l = layers.item(i); - - if (l.get('markers')) { - markersIndex = i; - break; - } - } - - if (isDefined(markersIndex)) { - var markers = layers.item(markersIndex); - layer.index = markersIndex; - layers.setAt(markersIndex, layer); - markers.index = layers.getLength(); - layers.push(markers); - } else { - layer.index = layers.getLength(); - layers.push(layer); - } - - }; - - var removeLayer = function(layers, index) { - layers.removeAt(index); - for (var i = index; i < layers.getLength(); i++) { - var l = layers.item(i); - if (l === null) { - layers.insertAt(i, null); - break; - } else { - l.index = i; - } - } - }; - - return { - // Determine if a reference is defined - isDefined: isDefined, - - // Determine if a reference is a number - isNumber: function(value) { - return angular.isNumber(value); - }, - - createView: function(view) { - var projection = createProjection(view); - - return new ol.View({ - projection: projection, - maxZoom: view.maxZoom, - minZoom: view.minZoom, - extent: view.extent - }); - }, - - // Determine if a reference is defined and not null - isDefinedAndNotNull: isDefinedAndNotNull, - - // Determine if a reference is a string - isString: function(value) { - return angular.isString(value); - }, - - // Determine if a reference is an array - isArray: function(value) { - return angular.isArray(value); - }, - - // Determine if a reference is an object - isObject: function(value) { - return angular.isObject(value); - }, - - // Determine if two objects have the same properties - equals: function(o1, o2) { - return angular.equals(o1, o2); - }, - - isValidCenter: function(center) { - return angular.isDefined(center) && - (typeof center.autodiscover === 'boolean' || - angular.isNumber(center.lat) && angular.isNumber(center.lon) || - (angular.isArray(center.coord) && center.coord.length === 2 && - angular.isNumber(center.coord[0]) && angular.isNumber(center.coord[1])) || - (angular.isArray(center.bounds) && center.bounds.length === 4 && - angular.isNumber(center.bounds[0]) && angular.isNumber(center.bounds[1]) && - angular.isNumber(center.bounds[1]) && angular.isNumber(center.bounds[2]))); - }, - - safeApply: function($scope, fn) { - var phase = $scope.$root.$$phase; - if (phase === '$apply' || phase === '$digest') { - $scope.$eval(fn); - } else { - $scope.$apply(fn); - } - }, - - isSameCenterOnMap: function(center, map) { - var urlProj = center.projection || 'EPSG:4326'; - var urlCenter = [center.lon, center.lat]; - var mapProj = map.getView().getProjection(); - var mapCenter = ol.proj.transform(map.getView().getCenter(), mapProj, urlProj); - var zoom = map.getView().getZoom(); - if (mapCenter[1].toFixed(4) === urlCenter[1].toFixed(4) && - mapCenter[0].toFixed(4) === urlCenter[0].toFixed(4) && - zoom === center.zoom) { - return true; - } - return false; - }, - - setCenter: function(view, projection, newCenter, map) { - - if (map && view.getCenter()) { - var pan = ol.animation.pan({ - duration: 150, - source: (view.getCenter()) - }); - map.beforeRender(pan); - } - - if (newCenter.projection === projection) { - view.setCenter([newCenter.lon, newCenter.lat]); - } else { - var coord = [newCenter.lon, newCenter.lat]; - view.setCenter(ol.proj.transform(coord, newCenter.projection, projection)); - } - }, - - setZoom: function(view, zoom, map) { - var z = ol.animation.zoom({ - duration: 150, - resolution: map.getView().getResolution() - }); - map.beforeRender(z); - view.setZoom(zoom); - }, - - isBoolean: function(value) { - return typeof value === 'boolean'; - }, - - obtainEffectiveMapId: function(d, mapId) { - var id; - var i; - if (!angular.isDefined(mapId)) { - if (Object.keys(d).length === 1) { - for (i in d) { - if (d.hasOwnProperty(i)) { - id = i; - } - } - } else if (Object.keys(d).length === 0) { - id = 'main'; - } else { - $log.error('[AngularJS - Openlayers] - You have more than 1 map on the DOM, ' + - 'you must provide the map ID to the olData.getXXX call'); - } - } else { - id = mapId; - } - return id; - }, - - createStyle: createStyle, - - setMapEvents: function(events, map, scope) { - if (isDefined(events) && angular.isArray(events.map)) { - for (var i in events.map) { - var event = events.map[i]; - setEvent(map, event, scope); - } - } - }, - - setVectorLayerEvents: function(events, map, scope, layerName) { - if (isDefined(events) && angular.isArray(events.layers)) { - angular.forEach(events.layers, function(eventType) { - angular.element(map.getViewport()).on(eventType, function(evt) { - var pixel = map.getEventPixel(evt); - var feature = map.forEachFeatureAtPixel(pixel, function(feature, olLayer) { - // only return the feature if it is in this layer (based on the name) - return (isDefinedAndNotNull(olLayer) && olLayer.get('name') === layerName) ? feature : null; - }); - if (isDefinedAndNotNull(feature)) { - scope.$emit('openlayers.layers.' + layerName + '.' + eventType, feature, evt); - } - }); - }); - } - }, - - setViewEvents: function(events, map, scope) { - if (isDefined(events) && angular.isArray(events.view)) { - var view = map.getView(); - angular.forEach(events.view, function(eventType) { - view.on(eventType, function(event) { - scope.$emit('openlayers.view.' + eventType, view, event); - }); - }); - } - }, - - detectLayerType: detectLayerType, - - createLayer: function(layer, projection, name) { - var oLayer; - var type = detectLayerType(layer); - var oSource = createSource(layer.source, projection); - if (!oSource) { - return; - } - - // Manage clustering - if ((type === 'Vector') && layer.clustering) { - oSource = new ol.source.Cluster({ - source: oSource, - distance: layer.clusteringDistance, - }); - } - - switch (type) { - case 'Image': - oLayer = new ol.layer.Image({ source: oSource }); - break; - case 'Tile': - oLayer = new ol.layer.Tile({ source: oSource }); - break; - case 'Heatmap': - oLayer = new ol.layer.Heatmap({ source: oSource }); - break; - case 'Vector': - oLayer = new ol.layer.Vector({ source: oSource }); - break; - } - - // set a layer name if given - if (isDefined(name)) { - oLayer.set('name', name); - } else if (isDefined(layer.name)) { - oLayer.set('name', layer.name); - } - - return oLayer; - }, - - createVectorLayer: function() { - return new ol.layer.Vector({ - source: new ol.source.Vector() - }); - }, - - notifyCenterUrlHashChanged: function(scope, center, search) { - if (center.centerUrlHash) { - var centerUrlHash = center.lat.toFixed(4) + ':' + center.lon.toFixed(4) + ':' + center.zoom; - if (!isDefined(search.c) || search.c !== centerUrlHash) { - scope.$emit('centerUrlHash', centerUrlHash); - } - } - }, - - getControlClasses: getControlClasses, - - detectControls: function(controls) { - var actualControls = {}; - var controlClasses = getControlClasses(); - - controls.forEach(function(control) { - for (var i in controlClasses) { - if (control instanceof controlClasses[i]) { - actualControls[i] = control; - } - } - }); - - return actualControls; - }, - - createFeature: function(data, viewProjection) { - var geometry; - - switch (data.type) { - case 'Polygon': - geometry = new ol.geom.Polygon(data.coords); - break; - default: - if (isDefined(data.coord) && data.projection === 'pixel') { - geometry = new ol.geom.Point(data.coord); - } else { - geometry = new ol.geom.Point([data.lon, data.lat]); - } - break; - } - - if (isDefined(data.projection) && data.projection !== 'pixel') { - geometry = geometry.transform(data.projection, viewProjection); - } - - var feature = new ol.Feature({ - geometry: geometry - }); - - if (isDefined(data.style)) { - var style = createStyle(data.style); - feature.setStyle(style); - } - return feature; - }, - - addLayerBeforeMarkers: addLayerBeforeMarkers, - - getGroup: getGroup, - - addLayerToGroup: function(layers, layer, name) { - var groupLayer = getGroup(layers, name); - - if (!isDefined(groupLayer)) { - groupLayer = createGroup(name); - addLayerBeforeMarkers(layers,groupLayer); - } - - layer.set('group', name); - addLayerBeforeMarkers(groupLayer.getLayers(), layer); - }, - - removeLayerFromGroup: function(layers, layer, name) { - var groupLayer = getGroup(layers, name); - layer.set('group'); - removeLayer(groupLayer.getLayers(), layer.index); - }, - - removeLayer: removeLayer, - - insertLayer: function(layers, index, layer) { - if (layers.getLength() < index) { - while (layers.getLength() < index) { - layers.push(null); - } - layer.index = index; - layers.push(layer); - } else { - layer.index = index; - layers.insertAt(layer.index, layer); - for (var i = index + 1; i < layers.getLength(); i++) { - var l = layers.item(i); - if (l === null) { - layers.removeAt(i); - break; - } else { - l.index = i; - } - } - } - }, - - createOverlay: function(element, pos) { - element.css('display', 'block'); - var ov = new ol.Overlay({ - position: pos, - element: element, - positioning: 'center-left' - }); - - return ov; - } - }; -}]); - -angular.module('openlayers-directive').factory('olMapDefaults', ["$q", "olHelpers", function($q, olHelpers) { - - var base64icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw' + - '7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGq' + - 'KII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR' + - '6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWV' + - 'MqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23' + - 'h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o' + - '+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzq' + - 'Bk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0g' + - 'pBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF' + - '3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAw' + - 'AhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5W' + - 'YnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRcha' + - 'h8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1E' + - 'IlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk' + - '4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/' + - 'tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdW' + - 'r7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0' + - 'ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIP' + - 'hP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmql' + - 'yvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsY' + - 'J7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/' + - 'WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIa' + - 'vznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV' + - '3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R' + - '3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDl' + - 'lwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQ' + - 'SCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92' + - 'H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GC' + - 'LVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjN' + - 'cNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg=='; - - var _getDefaults = function() { - return { - view: { - projection: 'EPSG:3857', - minZoom: undefined, - maxZoom: undefined, - rotation: 0, - extent: undefined - }, - center: { - lat: 0, - lon: 0, - zoom: 1, - autodiscover: false, - bounds: [], - centerUrlHash: false, - projection: 'EPSG:4326' - }, - styles: { - path: { - stroke: { - color: 'blue', - width: 8 - } - }, - marker: { - image: new ol.style.Icon({ - anchor: [0.5, 1], - anchorXUnits: 'fraction', - anchorYUnits: 'fraction', - opacity: 0.90, - src: base64icon - }) - } - }, - events: { - map: [], - markers: [], - layers: [] - }, - controls: { - attribution: true, - rotate: false, - zoom: true - }, - interactions: { - mouseWheelZoom: false - }, - renderer: 'canvas' - }; - }; - - var isDefined = olHelpers.isDefined; - var defaults = {}; - - // Get the _defaults dictionary, and override the properties defined by the user - return { - getDefaults: function(scope) { - if (!isDefined(scope)) { - for (var i in defaults) { - return defaults[i]; - } - } - return defaults[scope.$id]; - }, - - setDefaults: function(scope) { - var userDefaults = scope.defaults; - var scopeId = scope.$id; - var newDefaults = _getDefaults(); - - if (isDefined(userDefaults)) { - - if (isDefined(userDefaults.layers)) { - newDefaults.layers = angular.copy(userDefaults.layers); - } - - if (isDefined(userDefaults.controls)) { - newDefaults.controls = angular.copy(userDefaults.controls); - } - - if (isDefined(userDefaults.events)) { - newDefaults.events = angular.copy(userDefaults.events); - } - - if (isDefined(userDefaults.interactions)) { - newDefaults.interactions = angular.copy(userDefaults.interactions); - } - - if (isDefined(userDefaults.renderer)) { - newDefaults.renderer = userDefaults.renderer; - } - - if (isDefined(userDefaults.view)) { - newDefaults.view.maxZoom = userDefaults.view.maxZoom || newDefaults.view.maxZoom; - newDefaults.view.minZoom = userDefaults.view.minZoom || newDefaults.view.minZoom; - newDefaults.view.projection = userDefaults.view.projection || newDefaults.view.projection; - newDefaults.view.extent = userDefaults.view.extent || newDefaults.view.extent; - } - - if (isDefined(userDefaults.styles)) { - newDefaults.styles = angular.extend(newDefaults.styles, userDefaults.styles); - } - - } - - defaults[scopeId] = newDefaults; - return newDefaults; - } - }; -}]); - -})); \ No newline at end of file diff --git a/dist/angular-openlayers-directive.min.js b/dist/angular-openlayers-directive.min.js deleted file mode 100644 index 925988a4..00000000 --- a/dist/angular-openlayers-directive.min.js +++ /dev/null @@ -1,31 +0,0 @@ -/**! - * The MIT License - * - * Copyright (c) 2013 the angular-openlayers-directive Team, http://tombatossals.github.io/angular-openlayers-directive - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * angular-google-maps - * https://github.com/tombatossals/angular-openlayers-directive - * - * @authors https://github.com/tombatossals/angular-openlayers-directive/graphs/contributors - */ - -/*! angular-openlayers-directive 06-11-2015 */ -!function(a,b){"function"==typeof define&&define.amd?define(["ol"],function(c){return a.angularOpenlayersDirective=b(c)}):a.angularOpenlayersDirective=b(a.ol)}(this,function(a){angular.module("openlayers-directive",["ngSanitize"]).directive("openlayers",["$log","$q","$compile","olHelpers","olMapDefaults","olData",function(b,c,d,e,f,g){return{restrict:"EA",transclude:!0,replace:!0,scope:{center:"=olCenter",defaults:"=olDefaults",view:"=olView",events:"=olEvents"},template:'
',controller:["$scope",function(a){var b=c.defer();a.getMap=function(){return b.promise},a.setMap=function(a){b.resolve(a)},this.getOpenlayersScope=function(){return a}}],link:function(b,c,d){var h=e.isDefined,i=e.createLayer,j=e.setMapEvents,k=e.setViewEvents,l=e.createView,m=f.setDefaults(b);h(d.width)&&(isNaN(d.width)?c.css("width",d.width):c.css("width",d.width+"px")),h(d.height)&&(isNaN(d.height)?c.css("height",d.height):c.css("height",d.height+"px")),h(d.lat)&&(m.center.lat=parseFloat(d.lat)),h(d.lon)&&(m.center.lon=parseFloat(d.lon)),h(d.zoom)&&(m.center.zoom=parseFloat(d.zoom));var n=a.control.defaults(m.controls),o=a.interaction.defaults(m.interactions),p=l(m.view),q=new a.Map({target:c[0],controls:n,interactions:o,renderer:m.renderer,view:p});if(!d.customLayers){var r={type:"Tile",source:{type:"OSM"}},s=i(r,p.getProjection(),"default");q.addLayer(s),q.set("default",!0)}if(!h(d.olCenter)){var t=a.proj.transform([m.center.lon,m.center.lat],m.center.projection,p.getProjection());p.setCenter(t),p.setZoom(m.center.zoom)}j(m.events,q,b),k(m.events,q,b),b.setMap(q),g.setMap(q,d.id)}}}]),angular.module("openlayers-directive").directive("olCenter",["$log","$location","olMapDefaults","olHelpers",function(b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(f,g,h,i){var j=e.safeApply,k=e.isValidCenter,l=e.isDefined,m=e.isArray,n=e.isNumber,o=e.isSameCenterOnMap,p=e.setCenter,q=e.setZoom,r=i.getOpenlayersScope();r.getMap().then(function(f){var g=d.getDefaults(r),i=f.getView(),s=r.center;if(-1!==h.olCenter.search("-"))return b.error('[AngularJS - Openlayers] The "center" variable can\'t use a "-" on his key name: "'+h.center+'".'),void p(i,g.view.projection,g.center,f);l(s)||(s={}),k(s)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),s.lat=g.center.lat,s.lon=g.center.lon,s.zoom=g.center.zoom,s.projection=g.center.projection),s.projection||("pixel"!==g.view.projection?s.projection=g.center.projection:s.projection="pixel"),n(s.zoom)||(s.zoom=1),p(i,g.view.projection,s,f),i.setZoom(s.zoom);var t;if(s.centerUrlHash===!0){var u=function(){var a,b=c.search();if(l(b.c)){var d=b.c.split(":");3===d.length&&(a={lat:parseFloat(d[0]),lon:parseFloat(d[1]),zoom:parseInt(d[2],10)})}return a};t=u(),r.$on("$locationChangeSuccess",function(){var a=u();a&&!o(a,f)&&j(r,function(b){b.center.lat=a.lat,b.center.lon=a.lon,b.center.zoom=a.zoom})})}var v;r.$watchCollection("center",function(c){if(c){if(c.projection||(c.projection=g.center.projection),c.autodiscover)return v||(v=new a.Geolocation({projection:a.proj.get(c.projection)}),v.on("change",function(){if(c.autodiscover){var a=v.getPosition();j(r,function(b){b.center.lat=a[1],b.center.lon=a[0],b.center.zoom=12,b.center.autodiscover=!1,v.setTracking(!1)})}})),void v.setTracking(!0);k(c)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),c=g.center);var d=i.getCenter();if(d){if("pixel"===g.view.projection)return void i.setCenter(c.coord);var e=a.proj.transform(d,g.view.projection,c.projection);(e[1]!==c.lat||e[0]!==c.lon)&&p(i,g.view.projection,c,f)}i.getZoom()!==c.zoom&&q(i,c.zoom,f)}}),f.on("moveend",function(){j(r,function(b){if(l(b.center)){var d=f.getView().getCenter();if(b.center.zoom=i.getZoom(),"pixel"===g.view.projection)return void(b.center.coord=d);if(b.center){var h=a.proj.transform(d,g.view.projection,b.center.projection);if(b.center.lat=h[1],b.center.lon=h[0],e.notifyCenterUrlHashChanged(r,b.center,c.search()),m(b.center.bounds)){var j=i.calculateExtent(f.getSize()),k=b.center.projection,n=g.view.projection;b.center.bounds=a.proj.transformExtent(j,n,k)}}}})})})}}}]),angular.module("openlayers-directive").directive("olLayer",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olLayerProperties"},replace:!1,require:"^openlayers",link:function(a,b,e,f){var g=d.isDefined,h=d.equals,i=f.getOpenlayersScope(),j=d.createLayer,k=d.setVectorLayerEvents,l=d.detectLayerType,m=d.createStyle,n=d.isBoolean,o=d.addLayerBeforeMarkers,p=d.isNumber,q=d.insertLayer,r=d.removeLayer,s=d.addLayerToGroup,t=d.removeLayerFromGroup,u=d.getGroup;i.getMap().then(function(b){var d,f=b.getView().getProjection(),v=c.setDefaults(i),w=b.getLayers();if(a.$on("$destroy",function(){a.properties.group?t(w,d,a.properties.group):r(w,d.index),b.removeLayer(d)}),g(a.properties))a.$watch("properties",function(c,e){if(g(c.source)&&g(c.source.type)){if(!g(c.visible))return void(c.visible=!0);if(!g(c.opacity))return void(c.opacity=1);var i,x,y;if(g(d)){var z=function(a){return function(b){return b!==a}}(d);if(g(e)&&!h(c.source,e.source)){var A=d.index;y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),y.removeAt(A),d=j(c,f),d.set("group",x),g(d)&&(q(y,A,d),"Vector"===l(c)&&k(v.events,b,a,c.name))}(g(e)&&c.opacity!==e.opacity||z(d))&&(p(c.opacity)||p(parseFloat(c.opacity)))&&d.setOpacity(c.opacity),g(c.index)&&c.index!==d.index&&(y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),r(y,d.index),q(y,c.index,d)),g(c.group)&&c.group!==e.group&&(t(w,d,e.group),s(w,d,c.group)),(g(e)&&n(c.visible)&&c.visible!==e.visible||z(d))&&d.setVisible(c.visible),(g(c.style)&&!h(c.style,e.style)||z(d))&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}else d=j(c,f),g(c.group)?s(w,d,c.group):g(c.index)?q(w,c.index,d):o(w,d),"Vector"===l(c)&&k(v.events,b,a,c.name),n(c.visible)&&d.setVisible(c.visible),c.opacity&&d.setOpacity(c.opacity),angular.isArray(c.extent)&&d.setExtent(c.extent),c.style&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}},!0);else if(g(e.sourceType)&&g(e.sourceUrl)){var x={source:{url:e.sourceUrl,type:e.sourceType}};d=j(x,f,e.layerName),"Vector"===l(x)&&k(v.events,b,a,e.name),o(w,d)}})}}}]),angular.module("openlayers-directive").directive("olPath",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olGeomProperties"},require:"^openlayers",replace:!0,template:'',link:function(a,b,e,f){var g=d.isDefined,h=d.createFeature,i=d.createOverlay,j=d.createVectorLayer,k=d.insertLayer,l=d.removeLayer,m=f.getOpenlayersScope();m.getMap().then(function(d){var f=c.getDefaults(m),n=f.view.projection,o=j(),p=d.getLayers();if(k(p,p.getLength(),o),a.$on("$destroy",function(){l(p,o.index)}),g(e.coords)){var q=e.proj||"EPSG:4326",r=JSON.parse(e.coords),s={type:"Polygon",coords:r,projection:q,style:f.styles.path},t=h(s,n);if(o.getSource().addFeature(t),e.message){a.message=e.message;var u=t.getGeometry().getExtent(),v=i(b,u);d.addOverlay(v)}}else;})}}}]),angular.module("openlayers-directive").directive("olView",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(a,b,c,f){var g=f.getOpenlayersScope(),h=e.isNumber,i=e.safeApply,j=e.createView;g.getMap().then(function(a){var b=d.getDefaults(g),c=g.view;c.projection||(c.projection=b.view.projection),c.maxZoom||(c.maxZoom=b.view.maxZoom),c.minZoom||(c.minZoom=b.view.minZoom),c.rotation||(c.rotation=b.view.rotation);var e=j(c);a.setView(e),g.$watchCollection("view",function(a){h(a.rotation)&&e.setRotation(a.rotation)}),e.on("change:rotation",function(){i(g,function(b){b.view.rotation=a.getView().getRotation()})})})}}}]),angular.module("openlayers-directive").directive("olControl",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"E",scope:{properties:"=olControlProperties"},replace:!1,require:"^openlayers",link:function(a,b,c,d){var f,g,h=e.isDefined,i=d.getOpenlayersScope();i.getMap().then(function(b){var d=e.getControlClasses,i=d();return a.$on("$destroy",function(){b.removeControl(f)}),h(a.properties)&&h(a.properties.control)?(f=a.properties.control,void b.addControl(f)):void(c.name&&(h(a.properties)&&(g=a.properties),f=new i[c.name](g),b.addControl(f)))})}}}]),angular.module("openlayers-directive").directive("olMarker",["$log","$q","olMapDefaults","olHelpers",function(b,c,d,e){var f=function(){return{projection:"EPSG:4326",lat:0,lon:0,coord:[],show:!0,showOnMouseOver:!1,showOnMouseClick:!1,keepOneOverlayVisible:!1}},g=function(){function a(a){return b.map(function(a){return a.map}).indexOf(a)}var b=[];return{getInst:function(c,d){var f=a(d);if(-1===f){var g=e.createVectorLayer();g.set("markers",!0),d.addLayer(g),b.push({map:d,markerLayer:g,instScopes:[]}),f=b.length-1}return b[f].instScopes.push(c),b[f].markerLayer},deregisterScope:function(c,d){var e=a(d);if(-1===e)throw Error("This map has no markers");var f=b[e].instScopes,g=f.indexOf(c);if(-1===g)throw Error("Scope wan't registered");f.splice(g,1),f.length||(d.removeLayer(b[e].markerLayer),delete b[e])}}}();return{restrict:"E",scope:{lat:"=lat",lon:"=lon",label:"=label",properties:"=olMarkerProperties",style:"=olStyle"},transclude:!0,require:"^openlayers",replace:!0,template:'',link:function(c,h,i,j){var k=e.isDefined,l=j.getOpenlayersScope(),m=e.createFeature,n=e.createOverlay,o=h.find("ng-transclude").children().length>0;l.getMap().then(function(e){function j(b){var d=b.coordinate,f=e.getView().getProjection().getCode();if(d="pixel"===f?d.map(function(a){return parseInt(a,10)}):a.proj.transform(d,f,"EPSG:4326"),"pointerdown"===b.type){var g=e.forEachFeatureAtPixel(b.pixel,function(a){return a});if(x=g?g.get("marker"):null,!x||!x.draggable)return void(x=null);e.getTarget().style.cursor="pointer",w="pixel"===f?[d[0]-x.coord[0],d[1]-x.coord[1]]:[d[0]-x.lon,d[1]-x.lat],b.preventDefault()}else w&&x&&("pointerup"===b.type?(e.getTarget().style.cursor="",w=null,x=null,b.preventDefault()):"pointerdrag"===b.type&&(b.preventDefault(),c.$apply(function(){"pixel"===f?(x.coord[0]=d[0]-w[0],x.coord[1]=d[1]-w[1]):(x.lon=d[0]-w[0],x.lat=d[1]-w[1])})))}var p,q,r,s=g.getInst(c,e),t=f(),u=d.getDefaults(l),v=u.view.projection,w=null,x=null;return e.on("pointerdown",j),e.on("pointerup",j),e.on("pointerdrag",j),c.$on("$destroy",function(){s.getSource().removeFeature(r),k(p)&&e.removeOverlay(p),g.deregisterScope(c,e)}),k(c.properties)?void c.$watch("properties",function(d){if(e.getViewport().removeEventListener("mousemove",d.handleInteraction),e.getViewport().removeEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").removeEventListener("touchend",d.handleTapInteraction),e.getViewport().removeEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().removeEventListener("click",d.removeAllOverlays),d.handleInteraction=function(b){if(!d.label.show){var f=!1,g=e.getEventPixel(b),i=e.forEachFeatureAtPixel(g,function(a){return a}),j=!1;i===r&&(j=!0,f=!0,k(p)||(q="pixel"===t.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),!d.onClick||"click"!==b.type&&"touchend"!==b.type||c.$apply(function(){d.onClick.call(r,b,d)}),e.getTarget().style.cursor="pointer"),!f&&p&&(j=!0,e.removeOverlay(p),p=void 0,e.getTarget().style.cursor=""),j&&b.preventDefault()}},d.handleTapInteraction=function(){function a(){c=!0,b&&clearTimeout(b),b=setTimeout(function(){c=!1,b=null},500)}var b,c=!1;return e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchmove",a),function(){c||(d.handleInteraction.apply(null,arguments),a())}}(),d.showAtLeastOneOverlay=function(b){if(!d.label.show){var c=!1,f=e.getEventPixel(b),g=e.forEachFeatureAtPixel(f,function(a){return a}),i=!1;g===r&&(i=!0,c=!0,k(p)||(q="pixel"===t.projection?t.coord:a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),e.addOverlay(p)),e.getTarget().style.cursor="pointer"),!c&&p&&(i=!0,p=void 0,e.getTarget().style.cursor=""),i&&b.preventDefault()}},d.removeAllOverlays=function(a){angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),a.preventDefault()},k(r)){var f;if(f="pixel"===d.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,e.getView().getProjection()),!angular.equals(r.getGeometry().getCoordinates(),f)){var g=new a.geom.Point(f);r.setGeometry(g)}}else t.projection=d.projection?d.projection:t.projection,t.coord=d.coord?d.coord:t.coord,t.lat=d.lat?d.lat:t.lat,t.lon=d.lon?d.lon:t.lon,k(d.style)?t.style=d.style:t.style=u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",d),s.getSource().addFeature(r);k(p)&&e.removeOverlay(p),k(d.label)&&(c.message=d.label.message,(o||k(c.message)&&0!==c.message.length)&&(d.label&&d.label.show===!0&&(q="pixel"===t.projection?t.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),p&&d.label&&d.label.show===!1&&(e.removeOverlay(p),p=void 0),d.label&&d.label.show===!1&&d.label.showOnMouseOver&&e.getViewport().addEventListener("mousemove",d.handleInteraction),(d.label&&d.label.show===!1&&d.label.showOnMouseClick||d.onClick)&&(e.getViewport().addEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchend",d.handleTapInteraction)),d.label&&d.label.show===!1&&d.label.keepOneOverlayVisible&&(e.getViewport().addEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().addEventListener("click",d.removeAllOverlays))))},!0):(t.lat=c.lat?c.lat:t.lat,t.lon=c.lon?c.lon:t.lon,t.message=i.message,t.style=c.style?c.style:u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",c),s.getSource().addFeature(r),void((t.message||o)&&(c.message=i.message,q=a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),e.addOverlay(p))))})}}}]),angular.module("openlayers-directive").service("olData",["$log","$q","olHelpers",function(a,b,c){var d=c.obtainEffectiveMapId,e={},f=function(a,b){var c=d(a,b);a[c].resolvedDefer=!0},g=function(a,c){var e,f=d(a,c);return angular.isDefined(a[f])&&a[f].resolvedDefer!==!0?e=a[f].defer:(e=b.defer(),a[f]={defer:e,resolvedDefer:!1}),e},h=function(a,b){var c,e=d(a,b);return c=angular.isDefined(a[e])&&a[e].resolvedDefer!==!1?a[e].defer:g(a,b)};this.setMap=function(a,b){var c=g(e,b);c.resolve(a),f(e,b)},this.getMap=function(a){var b=h(e,a);return b.promise}}]),angular.module("openlayers-directive").factory("olHelpers",["$q","$log","$http",function(b,c,d){var e=function(a){return angular.isDefined(a)},f=function(a){return angular.isDefined(a)&&null!==a},g=function(a,b,c){a.on(b,function(d){var e=d.coordinate,f=a.getView().getProjection().getCode();"pixel"===f&&(e=e.map(function(a){return parseInt(a,10)})),c.$emit("openlayers.map."+b,{coord:e,projection:f,event:d})})},h=["Road","Aerial","AerialWithLabels","collinsBart","ordnanceSurvey"],i=function(){return{attribution:a.control.Attribution,fullscreen:a.control.FullScreen,mouseposition:a.control.MousePosition,rotate:a.control.Rotate,scaleline:a.control.ScaleLine,zoom:a.control.Zoom,zoomslider:a.control.ZoomSlider,zoomtoextent:a.control.ZoomToExtent}},j=["osm","sat","hyb"],k=["World_Imagery","World_Street_Map","World_Topo_Map","World_Physical_Map","World_Terrain_Base","Ocean_Basemap","NatGeo_World_Map"],l={style:a.style.Style,fill:a.style.Fill,stroke:a.style.Stroke,circle:a.style.Circle,icon:a.style.Icon,image:a.style.Image,regularshape:a.style.RegularShape,text:a.style.Text},m=function(a,b){return b&&a instanceof b?a:b?new b(a):a},n=function x(a,b){var c;if(b?c=a[b]:(b="style",c=a),"style"===b&&a instanceof Function)return a;if(!(c instanceof Object))return c;var d;if("[object Object]"===Object.prototype.toString.call(c)){d={};var e=l[b];if(e&&c instanceof e)return c;Object.getOwnPropertyNames(c).forEach(function(a,f,g){var h=l[a];return e&&h&&h.prototype instanceof l[b]?(console.assert(1===g.length,"Extra parameters for "+b),d=x(c,a),m(d,h)):(d[a]=x(c,a),void("text"!==a&&"string"!=typeof d[a]&&(d[a]=m(d[a],l[a]))))})}else d=c;return m(d,l[b])},o=function(a){if(a.type)return a.type;switch(a.source.type){case"ImageWMS":return"Image";case"ImageStatic":return"Image";case"GeoJSON":case"JSONP":case"TopoJSON":case"KML":case"TileVector":return"Vector";default:return"Tile"}},p=function(b){var d;switch(b.projection){case"pixel":if(!e(b.extent))return void c.error("[AngularJS - Openlayers] - You must provide the extent of the image if using pixel projection");d=new a.proj.Projection({code:"pixel",units:"pixels",extent:b.extent});break;default:d=new a.proj.get(b.projection)}return d},q=function(a){return-1!==["watercolor","terrain","toner"].indexOf(a)},r=function(b,f){var g;switch(b.type){case"MapBox":if(!b.mapId||!b.accessToken)return void c.error("[AngularJS - Openlayers] - MapBox layer requires the map id and the access token");var i="http://api.tiles.mapbox.com/v4/"+b.mapId+"/{z}/{x}/{y}.png?access_token="+b.accessToken,l=window.devicePixelRatio;l>1&&(i=i.replace(".png","@2x.png")),g=new a.source.XYZ({url:i,attributions:s(b),tilePixelRatio:l>1?2:1,wrapX:b.wrapX===!0?1:0});break;case"ImageWMS":b.url&&b.params||c.error("[AngularJS - Openlayers] - ImageWMS Layer needs valid server url and params properties"),g=new a.source.ImageWMS({url:b.url,attributions:s(b),crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,wrapX:b.wrapX?0:1});break;case"TileWMS":(b.url||b.urls)&&b.params||c.error("[AngularJS - Openlayers] - TileWMS Layer needs valid url (or urls) and params properties");var m={crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,attributions:s(b),wrapX:b.wrapX?0:1};b.url&&(m.url=b.url),b.urls&&(m.urls=b.urls),g=new a.source.TileWMS(m);break;case"WMTS":(b.url||b.urls)&&b.tileGrid||c.error("[AngularJS - Openlayers] - WMTS Layer needs valid url (or urls) and tileGrid properties");var n={projection:f,layer:b.layer,attributions:s(b),matrixSet:"undefined"===b.matrixSet?f:b.matrixSet,format:"undefined"===b.format?"image/jpeg":b.format,requestEncoding:"undefined"===b.requestEncoding?"KVP":b.requestEncoding,tileGrid:new a.tilegrid.WMTS({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions,matrixIds:b.tileGrid.matrixIds}),wrapX:b.wrapX?0:1};e(b.url)&&(n.url=b.url),e(b.urls)&&(n.urls=b.urls),g=new a.source.WMTS(n);break;case"OSM":g=new a.source.OSM({attributions:s(b),wrapX:b.wrapX===!0?1:0}),b.url&&g.setUrl(b.url);break;case"BingMaps":if(!b.key)return void c.error("[AngularJS - Openlayers] - You need an API key to show the Bing Maps.");var o={key:b.key,attributions:s(b),imagerySet:b.imagerySet?b.imagerySet:h[0],culture:b.culture,wrapX:b.wrapX===!0?1:0};b.maxZoom&&(o.maxZoom=b.maxZoom),g=new a.source.BingMaps(o);break;case"MapQuest":if(!b.layer||-1===j.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - MapQuest layers needs a valid 'layer' property.");g=new a.source.MapQuest({attributions:s(b),layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"EsriBaseMaps":if(!b.layer||-1===k.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - ESRI layers needs a valid 'layer' property.");var p="http://services.arcgisonline.com/ArcGIS/rest/services/",r=p+b.layer+"/MapServer/tile/{z}/{y}/{x}";g=new a.source.XYZ({attributions:s(b),url:r,wrapX:b.wrapX===!0?1:0});break;case"GeoJSON":if(!b.geojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a geojson property to add a GeoJSON layer.");if(e(b.url))g=new a.source.Vector({format:new a.format.GeoJSON,url:b.url,wrapX:b.wrapX===!0?1:0});else{g=new a.source.Vector;var t=f;e(b.geojson.projection)&&(t=b.geojson.projection);var u=new a.format.GeoJSON,v=u.readFeatures(b.geojson.object,{featureProjection:t});g.addFeatures(v)}break;case"JSONP":if(!b.url)return void c.error("[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.");e(b.url)&&(g=new a.source.Vector({format:new a.format.GeoJSON,loader:function(){var a=b.url+"&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK";d.jsonp(a,{cache:b.cache}).success(function(a){g.addFeatures(g.readFeatures(a))}).error(function(a){c(a)})},wrapX:b.wrapX===!0?1:0}));break;case"TopoJSON":if(!b.topojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a topojson property to add a TopoJSON layer.");g=b.url?new a.source.Vector({format:new a.format.TopoJSON,url:b.url,wrapX:b.wrapX===!0?1:0}):new a.source.Vector(angular.extend(b.topojson,{format:new a.format.TopoJSON,wrapX:b.wrapX===!0?1:0}));break;case"TileJSON":g=new a.source.TileJSON({url:b.url,attributions:s(b),crossOrigin:"anonymous",wrapX:b.wrapX===!0?1:0});break;case"TileVector":b.url&&b.format||c.error("[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties"),g=new a.source.TileVector({url:b.url,projection:f,attributions:s(b),format:b.format,tileGrid:new a.tilegrid.createXYZ({maxZoom:b.maxZoom||19}),wrapX:b.wrapX===!0?1:0});break;case"TileTMS":b.url&&b.tileGrid||c.error("[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties"),g=new a.source.TileImage({url:b.url,maxExtent:b.maxExtent,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=a[2];if(0>d||0>e)return"";var f=b.url+c+"/"+d+"/"+e+".png";return f},wrapX:b.wrapX===!0?1:0});break;case"TileImage":g=new a.source.TileImage({url:b.url,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=-a[2]-1,f=b.url.replace("{z}",c.toString()).replace("{x}",d.toString()).replace("{y}",e.toString());return f},wrapX:b.wrapX===!0?1:0});break;case"KML":var w=b.extractStyles||!1;g=new a.source.Vector({url:b.url,format:new a.format.KML,radius:b.radius,extractStyles:w,wrapX:b.wrapX===!0?1:0});break;case"Stamen":if(!b.layer||!q(b.layer))return void c.error("[AngularJS - Openlayers] - You need a valid Stamen layer.");g=new a.source.Stamen({layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"ImageStatic":if(!b.url||!angular.isArray(b.imageSize)||2!==b.imageSize.length)return void c.error("[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.");g=new a.source.ImageStatic({url:b.url,attributions:s(b),imageSize:b.imageSize,projection:f,imageExtent:f.getExtent(),imageLoadFunction:b.imageLoadFunction,wrapX:b.wrapX===!0?1:0});break;case"XYZ":b.url||c.error("[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties"),g=new a.source.XYZ({url:b.url,attributions:s(b),minZoom:b.minZoom,maxZoom:b.maxZoom,wrapX:b.wrapX===!0?1:0})}return g||c.warn('[AngularJS - Openlayers] - No source could be found for type "'+b.type+'"'),g},s=function(b){var c=[];return e(b.attribution)&&c.unshift(new a.Attribution({html:b.attribution})),c},t=function(b){var c=new a.layer.Group;return c.set("name",b),c},u=function(b,c){var d;return angular.forEach(b,function(b){return b instanceof a.layer.Group&&b.get("name")===c?void(d=b):void 0}),d},v=function(a,b){for(var c,d=0;d',controller:["$scope",function(a){var b=c.defer();a.getMap=function(){return b.promise},a.setMap=function(a){b.resolve(a)},this.getOpenlayersScope=function(){return a}}],link:function(b,c,d){var h=e.isDefined,i=e.createLayer,j=e.setMapEvents,k=e.setViewEvents,l=e.createView,m=f.setDefaults(b);h(d.width)&&(isNaN(d.width)?c.css("width",d.width):c.css("width",d.width+"px")),h(d.height)&&(isNaN(d.height)?c.css("height",d.height):c.css("height",d.height+"px")),h(d.lat)&&(m.center.lat=parseFloat(d.lat)),h(d.lon)&&(m.center.lon=parseFloat(d.lon)),h(d.zoom)&&(m.center.zoom=parseFloat(d.zoom));var n=a.control.defaults(m.controls),o=a.interaction.defaults(m.interactions),p=l(m.view),q=new a.Map({target:c[0],controls:n,interactions:o,renderer:m.renderer,view:p});if(!d.customLayers){var r={type:"Tile",source:{type:"OSM"}},s=i(r,p.getProjection(),"default");q.addLayer(s),q.set("default",!0)}if(!h(d.olCenter)){var t=a.proj.transform([m.center.lon,m.center.lat],m.center.projection,p.getProjection());p.setCenter(t),p.setZoom(m.center.zoom)}j(m.events,q,b),k(m.events,q,b),b.setMap(q),g.setMap(q,d.id)}}}]),angular.module("openlayers-directive").directive("olCenter",["$log","$location","olMapDefaults","olHelpers",function(b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(f,g,h,i){var j=e.safeApply,k=e.isValidCenter,l=e.isDefined,m=e.isArray,n=e.isNumber,o=e.isSameCenterOnMap,p=e.setCenter,q=e.setZoom,r=i.getOpenlayersScope();r.getMap().then(function(f){var g=d.getDefaults(r),i=f.getView(),s=r.center;if(-1!==h.olCenter.search("-"))return b.error('[AngularJS - Openlayers] The "center" variable can\'t use a "-" on his key name: "'+h.center+'".'),void p(i,g.view.projection,g.center,f);l(s)||(s={}),k(s)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),s.lat=g.center.lat,s.lon=g.center.lon,s.zoom=g.center.zoom,s.projection=g.center.projection),s.projection||("pixel"!==g.view.projection?s.projection=g.center.projection:s.projection="pixel"),n(s.zoom)||(s.zoom=1),p(i,g.view.projection,s,f),i.setZoom(s.zoom);var t;if(s.centerUrlHash===!0){var u=function(){var a,b=c.search();if(l(b.c)){var d=b.c.split(":");3===d.length&&(a={lat:parseFloat(d[0]),lon:parseFloat(d[1]),zoom:parseInt(d[2],10)})}return a};t=u(),r.$on("$locationChangeSuccess",function(){var a=u();a&&!o(a,f)&&j(r,function(b){b.center.lat=a.lat,b.center.lon=a.lon,b.center.zoom=a.zoom})})}var v;r.$watchCollection("center",function(c){if(c){if(c.projection||(c.projection=g.center.projection),c.autodiscover)return v||(v=new a.Geolocation({projection:a.proj.get(c.projection)}),v.on("change",function(){if(c.autodiscover){var a=v.getPosition();j(r,function(b){b.center.lat=a[1],b.center.lon=a[0],b.center.zoom=12,b.center.autodiscover=!1,v.setTracking(!1)})}})),void v.setTracking(!0);k(c)||(b.warn("[AngularJS - Openlayers] invalid 'center'"),c=g.center);var d=i.getCenter();if(d){if("pixel"===g.view.projection)return void i.setCenter(c.coord);var e=a.proj.transform(d,g.view.projection,c.projection);(e[1]!==c.lat||e[0]!==c.lon)&&p(i,g.view.projection,c,f)}i.getZoom()!==c.zoom&&q(i,c.zoom,f)}}),f.on("moveend",function(){j(r,function(b){if(l(b.center)){var d=f.getView().getCenter();if(b.center.zoom=i.getZoom(),"pixel"===g.view.projection)return void(b.center.coord=d);if(b.center){var h=a.proj.transform(d,g.view.projection,b.center.projection);if(b.center.lat=h[1],b.center.lon=h[0],e.notifyCenterUrlHashChanged(r,b.center,c.search()),m(b.center.bounds)){var j=i.calculateExtent(f.getSize()),k=b.center.projection,n=g.view.projection;b.center.bounds=a.proj.transformExtent(j,n,k)}}}})})})}}}]),angular.module("openlayers-directive").directive("olLayer",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olLayerProperties"},replace:!1,require:"^openlayers",link:function(a,b,e,f){var g=d.isDefined,h=d.equals,i=f.getOpenlayersScope(),j=d.createLayer,k=d.setVectorLayerEvents,l=d.detectLayerType,m=d.createStyle,n=d.isBoolean,o=d.addLayerBeforeMarkers,p=d.isNumber,q=d.insertLayer,r=d.removeLayer,s=d.addLayerToGroup,t=d.removeLayerFromGroup,u=d.getGroup;i.getMap().then(function(b){var d,f=b.getView().getProjection(),v=c.setDefaults(i),w=b.getLayers();if(a.$on("$destroy",function(){a.properties.group?t(w,d,a.properties.group):r(w,d.index),b.removeLayer(d)}),g(a.properties))a.$watch("properties",function(c,e){if(g(c.source)&&g(c.source.type)){if(!g(c.visible))return void(c.visible=!0);if(!g(c.opacity))return void(c.opacity=1);var i,x,y;if(g(d)){var z=function(a){return function(b){return b!==a}}(d);if(g(e)&&!h(c.source,e.source)){var A=d.index;y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),y.removeAt(A),d=j(c,f),d.set("group",x),g(d)&&(q(y,A,d),"Vector"===l(c)&&k(v.events,b,a,c.name))}(g(e)&&c.opacity!==e.opacity||z(d))&&(p(c.opacity)||p(parseFloat(c.opacity)))&&d.setOpacity(c.opacity),g(c.index)&&c.index!==d.index&&(y=w,x=d.get("group"),x&&(y=u(w,x).getLayers()),r(y,d.index),q(y,c.index,d)),g(c.group)&&c.group!==e.group&&(t(w,d,e.group),s(w,d,c.group)),(g(e)&&n(c.visible)&&c.visible!==e.visible||z(d))&&d.setVisible(c.visible),(g(c.style)&&!h(c.style,e.style)||z(d))&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}else d=j(c,f),g(c.group)?s(w,d,c.group):g(c.index)?q(w,c.index,d):o(w,d),"Vector"===l(c)&&k(v.events,b,a,c.name),n(c.visible)&&d.setVisible(c.visible),c.opacity&&d.setOpacity(c.opacity),angular.isArray(c.extent)&&d.setExtent(c.extent),c.style&&(i=angular.isFunction(c.style)?c.style:m(c.style),d.setStyle&&angular.isFunction(d.setStyle)&&d.setStyle(i))}},!0);else if(g(e.sourceType)&&g(e.sourceUrl)){var x={source:{url:e.sourceUrl,type:e.sourceType}};d=j(x,f,e.layerName),"Vector"===l(x)&&k(v.events,b,a,e.name),o(w,d)}})}}}]),angular.module("openlayers-directive").directive("olPath",["$log","$q","olMapDefaults","olHelpers",function(a,b,c,d){return{restrict:"E",scope:{properties:"=olGeomProperties"},require:"^openlayers",replace:!0,template:'',link:function(a,b,e,f){var g=d.isDefined,h=d.createFeature,i=d.createOverlay,j=d.createVectorLayer,k=d.insertLayer,l=d.removeLayer,m=f.getOpenlayersScope();m.getMap().then(function(d){var f=c.getDefaults(m),n=f.view.projection,o=j(),p=d.getLayers();if(k(p,p.getLength(),o),a.$on("$destroy",function(){l(p,o.index)}),g(e.coords)){var q=e.proj||"EPSG:4326",r=JSON.parse(e.coords),s={type:"Polygon",coords:r,projection:q,style:f.styles.path},t=h(s,n);if(o.getSource().addFeature(t),e.message){a.message=e.message;var u=t.getGeometry().getExtent(),v=i(b,u);d.addOverlay(v)}}else;})}}}]),angular.module("openlayers-directive").directive("olView",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"A",scope:!1,replace:!1,require:"openlayers",link:function(a,b,c,f){var g=f.getOpenlayersScope(),h=e.isNumber,i=e.safeApply,j=e.createView;g.getMap().then(function(a){var b=d.getDefaults(g),c=g.view;c.projection||(c.projection=b.view.projection),c.maxZoom||(c.maxZoom=b.view.maxZoom),c.minZoom||(c.minZoom=b.view.minZoom),c.rotation||(c.rotation=b.view.rotation);var e=j(c);a.setView(e),g.$watchCollection("view",function(a){h(a.rotation)&&e.setRotation(a.rotation)}),e.on("change:rotation",function(){i(g,function(b){b.view.rotation=a.getView().getRotation()})})})}}}]),angular.module("openlayers-directive").directive("olControl",["$log","$q","olData","olMapDefaults","olHelpers",function(a,b,c,d,e){return{restrict:"E",scope:{properties:"=olControlProperties"},replace:!1,require:"^openlayers",link:function(a,b,c,d){var f,g,h=e.isDefined,i=d.getOpenlayersScope();i.getMap().then(function(b){var d=e.getControlClasses,i=d();return a.$on("$destroy",function(){b.removeControl(f)}),h(a.properties)&&h(a.properties.control)?(f=a.properties.control,void b.addControl(f)):void(c.name&&(h(a.properties)&&(g=a.properties),f=new i[c.name](g),b.addControl(f)))})}}}]),angular.module("openlayers-directive").directive("olMarker",["$log","$q","olMapDefaults","olHelpers",function(b,c,d,e){var f=function(){return{projection:"EPSG:4326",lat:0,lon:0,coord:[],show:!0,showOnMouseOver:!1,showOnMouseClick:!1,keepOneOverlayVisible:!1}},g=function(){function a(a){return b.map(function(a){return a.map}).indexOf(a)}var b=[];return{getInst:function(c,d){var f=a(d);if(-1===f){var g=e.createVectorLayer();g.set("markers",!0),d.addLayer(g),b.push({map:d,markerLayer:g,instScopes:[]}),f=b.length-1}return b[f].instScopes.push(c),b[f].markerLayer},deregisterScope:function(c,d){var e=a(d);if(-1===e)throw Error("This map has no markers");var f=b[e].instScopes,g=f.indexOf(c);if(-1===g)throw Error("Scope wan't registered");f.splice(g,1),f.length||(d.removeLayer(b[e].markerLayer),delete b[e])}}}();return{restrict:"E",scope:{lat:"=lat",lon:"=lon",label:"=label",properties:"=olMarkerProperties",style:"=olStyle"},transclude:!0,require:"^openlayers",replace:!0,template:'',link:function(c,h,i,j){var k=e.isDefined,l=j.getOpenlayersScope(),m=e.createFeature,n=e.createOverlay,o=h.find("ng-transclude").children().length>0;l.getMap().then(function(e){function j(b){var d=b.coordinate,f=e.getView().getProjection().getCode();if(d="pixel"===f?d.map(function(a){return parseInt(a,10)}):a.proj.transform(d,f,"EPSG:4326"),"pointerdown"===b.type){var g=e.forEachFeatureAtPixel(b.pixel,function(a){return a});if(x=g?g.get("marker"):null,!x||!x.draggable)return void(x=null);e.getTarget().style.cursor="pointer",w="pixel"===f?[d[0]-x.coord[0],d[1]-x.coord[1]]:[d[0]-x.lon,d[1]-x.lat],b.preventDefault()}else w&&x&&("pointerup"===b.type?(e.getTarget().style.cursor="",w=null,x=null,b.preventDefault()):"pointerdrag"===b.type&&(b.preventDefault(),c.$apply(function(){"pixel"===f?(x.coord[0]=d[0]-w[0],x.coord[1]=d[1]-w[1]):(x.lon=d[0]-w[0],x.lat=d[1]-w[1])})))}var p,q,r,s=g.getInst(c,e),t=f(),u=d.getDefaults(l),v=u.view.projection,w=null,x=null;return e.on("pointerdown",j),e.on("pointerup",j),e.on("pointerdrag",j),c.$on("$destroy",function(){s.getSource().removeFeature(r),k(p)&&e.removeOverlay(p),g.deregisterScope(c,e)}),k(c.properties)?void c.$watch("properties",function(d){if(e.getViewport().removeEventListener("mousemove",d.handleInteraction),e.getViewport().removeEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").removeEventListener("touchend",d.handleTapInteraction),e.getViewport().removeEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().removeEventListener("click",d.removeAllOverlays),d.handleInteraction=function(b){if(!d.label.show){var f=!1,g=e.getEventPixel(b),i=e.forEachFeatureAtPixel(g,function(a){return a}),j=!1;i===r&&(j=!0,f=!0,k(p)||(q="pixel"===t.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),!d.onClick||"click"!==b.type&&"touchend"!==b.type||c.$apply(function(){d.onClick.call(r,b,d)}),e.getTarget().style.cursor="pointer"),!f&&p&&(j=!0,e.removeOverlay(p),p=void 0,e.getTarget().style.cursor=""),j&&b.preventDefault()}},d.handleTapInteraction=function(){function a(){c=!0,b&&clearTimeout(b),b=setTimeout(function(){c=!1,b=null},500)}var b,c=!1;return e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchmove",a),function(){c||(d.handleInteraction.apply(null,arguments),a())}}(),d.showAtLeastOneOverlay=function(b){if(!d.label.show){var c=!1,f=e.getEventPixel(b),g=e.forEachFeatureAtPixel(f,function(a){return a}),i=!1;g===r&&(i=!0,c=!0,k(p)||(q="pixel"===t.projection?t.coord:a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),e.addOverlay(p)),e.getTarget().style.cursor="pointer"),!c&&p&&(i=!0,p=void 0,e.getTarget().style.cursor=""),i&&b.preventDefault()}},d.removeAllOverlays=function(a){angular.forEach(e.getOverlays(),function(a){e.removeOverlay(a)}),a.preventDefault()},k(r)){var f;if(f="pixel"===d.projection?d.coord:a.proj.transform([d.lon,d.lat],t.projection,e.getView().getProjection()),!angular.equals(r.getGeometry().getCoordinates(),f)){var g=new a.geom.Point(f);r.setGeometry(g)}}else t.projection=d.projection?d.projection:t.projection,t.coord=d.coord?d.coord:t.coord,t.lat=d.lat?d.lat:t.lat,t.lon=d.lon?d.lon:t.lon,k(d.style)?t.style=d.style:t.style=u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",d),s.getSource().addFeature(r);k(p)&&e.removeOverlay(p),k(d.label)&&(c.message=d.label.message,(o||k(c.message)&&0!==c.message.length)&&(d.label&&d.label.show===!0&&(q="pixel"===t.projection?t.coord:a.proj.transform([d.lon,d.lat],t.projection,v),p=n(h,q),e.addOverlay(p)),p&&d.label&&d.label.show===!1&&(e.removeOverlay(p),p=void 0),d.label&&d.label.show===!1&&d.label.showOnMouseOver&&e.getViewport().addEventListener("mousemove",d.handleInteraction),(d.label&&d.label.show===!1&&d.label.showOnMouseClick||d.onClick)&&(e.getViewport().addEventListener("click",d.handleTapInteraction),e.getViewport().querySelector("canvas.ol-unselectable").addEventListener("touchend",d.handleTapInteraction)),d.label&&d.label.show===!1&&d.label.keepOneOverlayVisible&&(e.getViewport().addEventListener("mousemove",d.showAtLeastOneOverlay),e.getViewport().addEventListener("click",d.removeAllOverlays))))},!0):(t.lat=c.lat?c.lat:t.lat,t.lon=c.lon?c.lon:t.lon,t.message=i.message,t.style=c.style?c.style:u.styles.marker,r=m(t,v),k(r)||b.error("[AngularJS - Openlayers] Received invalid data on the marker."),r.set("marker",c),s.getSource().addFeature(r),void((t.message||o)&&(c.message=i.message,q=a.proj.transform([t.lon,t.lat],t.projection,v),p=n(h,q),e.addOverlay(p))))})}}}]),angular.module("openlayers-directive").service("olData",["$log","$q","olHelpers",function(a,b,c){var d=c.obtainEffectiveMapId,e={},f=function(a,b){var c=d(a,b);a[c].resolvedDefer=!0},g=function(a,c){var e,f=d(a,c);return angular.isDefined(a[f])&&a[f].resolvedDefer!==!0?e=a[f].defer:(e=b.defer(),a[f]={defer:e,resolvedDefer:!1}),e},h=function(a,b){var c,e=d(a,b);return c=angular.isDefined(a[e])&&a[e].resolvedDefer!==!1?a[e].defer:g(a,b)};this.setMap=function(a,b){var c=g(e,b);c.resolve(a),f(e,b)},this.getMap=function(a){var b=h(e,a);return b.promise}}]),angular.module("openlayers-directive").factory("olHelpers",["$q","$log","$http",function(b,c,d){var e=function(a){return angular.isDefined(a)},f=function(a){return angular.isDefined(a)&&null!==a},g=function(a,b,c){a.on(b,function(d){var e=d.coordinate,f=a.getView().getProjection().getCode();"pixel"===f&&(e=e.map(function(a){return parseInt(a,10)})),c.$emit("openlayers.map."+b,{coord:e,projection:f,event:d})})},h=["Road","Aerial","AerialWithLabels","collinsBart","ordnanceSurvey"],i=function(){return{attribution:a.control.Attribution,fullscreen:a.control.FullScreen,mouseposition:a.control.MousePosition,rotate:a.control.Rotate,scaleline:a.control.ScaleLine,zoom:a.control.Zoom,zoomslider:a.control.ZoomSlider,zoomtoextent:a.control.ZoomToExtent}},j=["osm","sat","hyb"],k=["World_Imagery","World_Street_Map","World_Topo_Map","World_Physical_Map","World_Terrain_Base","Ocean_Basemap","NatGeo_World_Map"],l={style:a.style.Style,fill:a.style.Fill,stroke:a.style.Stroke,circle:a.style.Circle,icon:a.style.Icon,image:a.style.Image,regularshape:a.style.RegularShape,text:a.style.Text},m=function(a,b){return b&&a instanceof b?a:b?new b(a):a},n=function x(a,b){var c;if(b?c=a[b]:(b="style",c=a),"style"===b&&a instanceof Function)return a;if(!(c instanceof Object))return c;var d;if("[object Object]"===Object.prototype.toString.call(c)){d={};var e=l[b];if(e&&c instanceof e)return c;Object.getOwnPropertyNames(c).forEach(function(a,f,g){var h=l[a];return e&&h&&h.prototype instanceof l[b]?(console.assert(1===g.length,"Extra parameters for "+b),d=x(c,a),m(d,h)):(d[a]=x(c,a),void("text"!==a&&"string"!=typeof d[a]&&(d[a]=m(d[a],l[a]))))})}else d=c;return m(d,l[b])},o=function(a){if(a.type)return a.type;switch(a.source.type){case"ImageWMS":return"Image";case"ImageStatic":return"Image";case"GeoJSON":case"JSONP":case"TopoJSON":case"KML":case"TileVector":return"Vector";default:return"Tile"}},p=function(b){var d;switch(b.projection){case"pixel":if(!e(b.extent))return void c.error("[AngularJS - Openlayers] - You must provide the extent of the image if using pixel projection");d=new a.proj.Projection({code:"pixel",units:"pixels",extent:b.extent});break;default:d=new a.proj.get(b.projection)}return d},q=function(a){return-1!==["watercolor","terrain","toner"].indexOf(a)},r=function(b,f){var g;switch(b.type){case"MapBox":if(!b.mapId||!b.accessToken)return void c.error("[AngularJS - Openlayers] - MapBox layer requires the map id and the access token");var i="http://api.tiles.mapbox.com/v4/"+b.mapId+"/{z}/{x}/{y}.png?access_token="+b.accessToken,l=window.devicePixelRatio;l>1&&(i=i.replace(".png","@2x.png")),g=new a.source.XYZ({url:i,attributions:s(b),tilePixelRatio:l>1?2:1,wrapX:b.wrapX===!0?1:0});break;case"ImageWMS":b.url&&b.params||c.error("[AngularJS - Openlayers] - ImageWMS Layer needs valid server url and params properties"),g=new a.source.ImageWMS({url:b.url,attributions:s(b),crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,wrapX:b.wrapX?0:1});break;case"TileWMS":(b.url||b.urls)&&b.params||c.error("[AngularJS - Openlayers] - TileWMS Layer needs valid url (or urls) and params properties");var m={crossOrigin:"undefined"==typeof b.crossOrigin?"anonymous":b.crossOrigin,params:b.params,attributions:s(b),wrapX:b.wrapX?0:1};b.url&&(m.url=b.url),b.urls&&(m.urls=b.urls),g=new a.source.TileWMS(m);break;case"WMTS":(b.url||b.urls)&&b.tileGrid||c.error("[AngularJS - Openlayers] - WMTS Layer needs valid url (or urls) and tileGrid properties");var n={projection:f,layer:b.layer,attributions:s(b),matrixSet:"undefined"===b.matrixSet?f:b.matrixSet,format:"undefined"===b.format?"image/jpeg":b.format,requestEncoding:"undefined"===b.requestEncoding?"KVP":b.requestEncoding,tileGrid:new a.tilegrid.WMTS({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions,matrixIds:b.tileGrid.matrixIds}),wrapX:b.wrapX?0:1};e(b.url)&&(n.url=b.url),e(b.urls)&&(n.urls=b.urls),g=new a.source.WMTS(n);break;case"OSM":g=new a.source.OSM({attributions:s(b),wrapX:b.wrapX===!0?1:0}),b.url&&g.setUrl(b.url);break;case"BingMaps":if(!b.key)return void c.error("[AngularJS - Openlayers] - You need an API key to show the Bing Maps.");var o={key:b.key,attributions:s(b),imagerySet:b.imagerySet?b.imagerySet:h[0],culture:b.culture,wrapX:b.wrapX===!0?1:0};b.maxZoom&&(o.maxZoom=b.maxZoom),g=new a.source.BingMaps(o);break;case"MapQuest":if(!b.layer||-1===j.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - MapQuest layers needs a valid 'layer' property.");g=new a.source.MapQuest({attributions:s(b),layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"EsriBaseMaps":if(!b.layer||-1===k.indexOf(b.layer))return void c.error("[AngularJS - Openlayers] - ESRI layers needs a valid 'layer' property.");var p="http://services.arcgisonline.com/ArcGIS/rest/services/",r=p+b.layer+"/MapServer/tile/{z}/{y}/{x}";g=new a.source.XYZ({attributions:s(b),url:r,wrapX:b.wrapX===!0?1:0});break;case"GeoJSON":if(!b.geojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a geojson property to add a GeoJSON layer.");if(e(b.url))g=new a.source.Vector({format:new a.format.GeoJSON,url:b.url,wrapX:b.wrapX===!0?1:0});else{g=new a.source.Vector;var t=f;e(b.geojson.projection)&&(t=b.geojson.projection);var u=new a.format.GeoJSON,v=u.readFeatures(b.geojson.object,{featureProjection:t});g.addFeatures(v)}break;case"JSONP":if(!b.url)return void c.error("[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.");e(b.url)&&(g=new a.source.Vector({format:new a.format.GeoJSON,loader:function(){var a=b.url+"&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK";d.jsonp(a,{cache:b.cache}).success(function(a){g.addFeatures(g.readFeatures(a))}).error(function(a){c(a)})},wrapX:b.wrapX===!0?1:0}));break;case"TopoJSON":if(!b.topojson&&!b.url)return void c.error("[AngularJS - Openlayers] - You need a topojson property to add a TopoJSON layer.");g=b.url?new a.source.Vector({format:new a.format.TopoJSON,url:b.url,wrapX:b.wrapX===!0?1:0}):new a.source.Vector(angular.extend(b.topojson,{format:new a.format.TopoJSON,wrapX:b.wrapX===!0?1:0}));break;case"TileJSON":g=new a.source.TileJSON({url:b.url,attributions:s(b),crossOrigin:"anonymous",wrapX:b.wrapX===!0?1:0});break;case"TileVector":b.url&&b.format||c.error("[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties"),g=new a.source.TileVector({url:b.url,projection:f,attributions:s(b),format:b.format,tileGrid:new a.tilegrid.createXYZ({maxZoom:b.maxZoom||19}),wrapX:b.wrapX===!0?1:0});break;case"TileTMS":b.url&&b.tileGrid||c.error("[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties"),g=new a.source.TileImage({url:b.url,maxExtent:b.maxExtent,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=a[2];if(0>d||0>e)return"";var f=b.url+c+"/"+d+"/"+e+".png";return f},wrapX:b.wrapX===!0?1:0});break;case"TileImage":g=new a.source.TileImage({url:b.url,attributions:s(b),tileGrid:new a.tilegrid.TileGrid({origin:b.tileGrid.origin,resolutions:b.tileGrid.resolutions}),tileUrlFunction:function(a){var c=a[0],d=a[1],e=-a[2]-1,f=b.url.replace("{z}",c.toString()).replace("{x}",d.toString()).replace("{y}",e.toString());return f},wrapX:b.wrapX===!0?1:0});break;case"KML":var w=b.extractStyles||!1;g=new a.source.Vector({url:b.url,format:new a.format.KML,radius:b.radius,extractStyles:w,wrapX:b.wrapX===!0?1:0});break;case"Stamen":if(!b.layer||!q(b.layer))return void c.error("[AngularJS - Openlayers] - You need a valid Stamen layer.");g=new a.source.Stamen({layer:b.layer,wrapX:b.wrapX===!0?1:0});break;case"ImageStatic":if(!b.url||!angular.isArray(b.imageSize)||2!==b.imageSize.length)return void c.error("[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.");g=new a.source.ImageStatic({url:b.url,attributions:s(b),imageSize:b.imageSize,projection:f,imageExtent:f.getExtent(),imageLoadFunction:b.imageLoadFunction,wrapX:b.wrapX===!0?1:0});break;case"XYZ":b.url||c.error("[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties"),g=new a.source.XYZ({url:b.url,attributions:s(b),minZoom:b.minZoom,maxZoom:b.maxZoom,wrapX:b.wrapX===!0?1:0})}return g||c.warn('[AngularJS - Openlayers] - No source could be found for type "'+b.type+'"'),g},s=function(b){var c=[];return e(b.attribution)&&c.unshift(new a.Attribution({html:b.attribution})),c},t=function(b){var c=new a.layer.Group;return c.set("name",b),c},u=function(b,c){var d;return angular.forEach(b,function(b){return b instanceof a.layer.Group&&b.get("name")===c?void(d=b):void 0}),d},v=function(a,b){for(var c,d=0;d', - controller: function($scope) { - var _map = $q.defer(); - $scope.getMap = function() { - return _map.promise; - }; - - $scope.setMap = function(map) { - _map.resolve(map); - }; - - this.getOpenlayersScope = function() { - return $scope; - }; - }, - link: function(scope, element, attrs) { - var isDefined = olHelpers.isDefined; - var createLayer = olHelpers.createLayer; - var setMapEvents = olHelpers.setMapEvents; - var setViewEvents = olHelpers.setViewEvents; - var createView = olHelpers.createView; - var defaults = olMapDefaults.setDefaults(scope); - - // Set width and height if they are defined - if (isDefined(attrs.width)) { - if (isNaN(attrs.width)) { - element.css('width', attrs.width); - } else { - element.css('width', attrs.width + 'px'); - } - } - - if (isDefined(attrs.height)) { - if (isNaN(attrs.height)) { - element.css('height', attrs.height); - } else { - element.css('height', attrs.height + 'px'); - } - } - - if (isDefined(attrs.lat)) { - defaults.center.lat = parseFloat(attrs.lat); - } - - if (isDefined(attrs.lon)) { - defaults.center.lon = parseFloat(attrs.lon); - } - - if (isDefined(attrs.zoom)) { - defaults.center.zoom = parseFloat(attrs.zoom); - } - - var controls = ol.control.defaults(defaults.controls); - var interactions = ol.interaction.defaults(defaults.interactions); - var view = createView(defaults.view); - - // Create the Openlayers Map Object with the options - var map = new ol.Map({ - target: element[0], - controls: controls, - interactions: interactions, - renderer: defaults.renderer, - view: view - }); - - // If no layer is defined, set the default tileLayer - if (!attrs.customLayers) { - var l = { - type: 'Tile', - source: { - type: 'OSM' - } - }; - var layer = createLayer(l, view.getProjection(), 'default'); - map.addLayer(layer); - map.set('default', true); - } - - if (!isDefined(attrs.olCenter)) { - var c = ol.proj.transform([defaults.center.lon, - defaults.center.lat - ], - defaults.center.projection, view.getProjection() - ); - view.setCenter(c); - view.setZoom(defaults.center.zoom); - } - - // Set the Default events for the map - setMapEvents(defaults.events, map, scope); - - //Set the Default events for the map view - setViewEvents(defaults.events, map, scope); - - // Resolve the map object to the promises - scope.setMap(map); - olData.setMap(map, attrs.id); - - } - }; - }); - -angular.module('openlayers-directive').directive('olCenter', function($log, $location, olMapDefaults, olHelpers) { - - return { - restrict: 'A', - scope: false, - replace: false, - require: 'openlayers', - - link: function(scope, element, attrs, controller) { - var safeApply = olHelpers.safeApply; - var isValidCenter = olHelpers.isValidCenter; - var isDefined = olHelpers.isDefined; - var isArray = olHelpers.isArray; - var isNumber = olHelpers.isNumber; - var isSameCenterOnMap = olHelpers.isSameCenterOnMap; - var setCenter = olHelpers.setCenter; - var setZoom = olHelpers.setZoom; - var olScope = controller.getOpenlayersScope(); - - olScope.getMap().then(function(map) { - var defaults = olMapDefaults.getDefaults(olScope); - var view = map.getView(); - var center = olScope.center; - - if (attrs.olCenter.search('-') !== -1) { - $log.error('[AngularJS - Openlayers] The "center" variable can\'t use ' + - 'a "-" on his key name: "' + attrs.center + '".'); - setCenter(view, defaults.view.projection, defaults.center, map); - return; - } - - if (!isDefined(center)) { - center = {}; - } - - if (!isValidCenter(center)) { - $log.warn('[AngularJS - Openlayers] invalid \'center\''); - center.lat = defaults.center.lat; - center.lon = defaults.center.lon; - center.zoom = defaults.center.zoom; - center.projection = defaults.center.projection; - } - - if (!center.projection) { - if (defaults.view.projection !== 'pixel') { - center.projection = defaults.center.projection; - } else { - center.projection = 'pixel'; - } - } - - if (!isNumber(center.zoom)) { - center.zoom = 1; - } - - setCenter(view, defaults.view.projection, center, map); - view.setZoom(center.zoom); - - var centerUrlHash; - if (center.centerUrlHash === true) { - var extractCenterFromUrl = function() { - var search = $location.search(); - var centerParam; - if (isDefined(search.c)) { - var cParam = search.c.split(':'); - if (cParam.length === 3) { - centerParam = { - lat: parseFloat(cParam[0]), - lon: parseFloat(cParam[1]), - zoom: parseInt(cParam[2], 10) - }; - } - } - return centerParam; - }; - centerUrlHash = extractCenterFromUrl(); - - olScope.$on('$locationChangeSuccess', function() { - var urlCenter = extractCenterFromUrl(); - if (urlCenter && !isSameCenterOnMap(urlCenter, map)) { - safeApply(olScope, function(scope) { - scope.center.lat = urlCenter.lat; - scope.center.lon = urlCenter.lon; - scope.center.zoom = urlCenter.zoom; - }); - } - }); - } - - var geolocation; - olScope.$watchCollection('center', function(center) { - - if (!center) { - return; - } - - if (!center.projection) { - center.projection = defaults.center.projection; - } - - if (center.autodiscover) { - if (!geolocation) { - geolocation = new ol.Geolocation({ - projection: ol.proj.get(center.projection) - }); - - geolocation.on('change', function() { - if (center.autodiscover) { - var location = geolocation.getPosition(); - safeApply(olScope, function(scope) { - scope.center.lat = location[1]; - scope.center.lon = location[0]; - scope.center.zoom = 12; - scope.center.autodiscover = false; - geolocation.setTracking(false); - }); - } - }); - } - geolocation.setTracking(true); - return; - } - - if (!isValidCenter(center)) { - $log.warn('[AngularJS - Openlayers] invalid \'center\''); - center = defaults.center; - } - - var viewCenter = view.getCenter(); - if (viewCenter) { - if (defaults.view.projection === 'pixel') { - view.setCenter(center.coord); - return; - } - var actualCenter = ol.proj.transform(viewCenter, defaults.view.projection, center.projection); - if (!(actualCenter[1] === center.lat && actualCenter[0] === center.lon)) { - setCenter(view, defaults.view.projection, center, map); - } - } - - if (view.getZoom() !== center.zoom) { - setZoom(view, center.zoom, map); - } - }); - - map.on('moveend', function() { - safeApply(olScope, function(scope) { - - if (!isDefined(scope.center)) { - return; - } - - var center = map.getView().getCenter(); - scope.center.zoom = view.getZoom(); - - if (defaults.view.projection === 'pixel') { - scope.center.coord = center; - return; - } - - if (scope.center) { - var proj = ol.proj.transform(center, defaults.view.projection, scope.center.projection); - scope.center.lat = proj[1]; - scope.center.lon = proj[0]; - - // Notify the controller about a change in the center position - olHelpers.notifyCenterUrlHashChanged(olScope, scope.center, $location.search()); - - // Calculate the bounds if needed - if (isArray(scope.center.bounds)) { - var extent = view.calculateExtent(map.getSize()); - var centerProjection = scope.center.projection; - var viewProjection = defaults.view.projection; - scope.center.bounds = ol.proj.transformExtent(extent, viewProjection, centerProjection); - } - } - }); - }); - - }); - } - }; -}); - -angular.module('openlayers-directive').directive('olLayer', function($log, $q, olMapDefaults, olHelpers) { - - return { - restrict: 'E', - scope: { - properties: '=olLayerProperties' - }, - replace: false, - require: '^openlayers', - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var equals = olHelpers.equals; - var olScope = controller.getOpenlayersScope(); - var createLayer = olHelpers.createLayer; - var setVectorLayerEvents = olHelpers.setVectorLayerEvents; - var detectLayerType = olHelpers.detectLayerType; - var createStyle = olHelpers.createStyle; - var isBoolean = olHelpers.isBoolean; - var addLayerBeforeMarkers = olHelpers.addLayerBeforeMarkers; - var isNumber = olHelpers.isNumber; - var insertLayer = olHelpers.insertLayer; - var removeLayer = olHelpers.removeLayer; - var addLayerToGroup = olHelpers.addLayerToGroup; - var removeLayerFromGroup = olHelpers.removeLayerFromGroup; - var getGroup = olHelpers.getGroup; - - olScope.getMap().then(function(map) { - var projection = map.getView().getProjection(); - var defaults = olMapDefaults.setDefaults(olScope); - var layerCollection = map.getLayers(); - var olLayer; - - scope.$on('$destroy', function() { - if (scope.properties.group) { - removeLayerFromGroup(layerCollection, olLayer, scope.properties.group); - } else { - removeLayer(layerCollection, olLayer.index); - } - - map.removeLayer(olLayer); - }); - - if (!isDefined(scope.properties)) { - if (isDefined(attrs.sourceType) && isDefined(attrs.sourceUrl)) { - var l = { - source: { - url: attrs.sourceUrl, - type: attrs.sourceType - } - }; - - olLayer = createLayer(l, projection, attrs.layerName); - if (detectLayerType(l) === 'Vector') { - setVectorLayerEvents(defaults.events, map, scope, attrs.name); - } - addLayerBeforeMarkers(layerCollection, olLayer); - } - return; - } - - scope.$watch('properties', function(properties, oldProperties) { - if (!isDefined(properties.source) || !isDefined(properties.source.type)) { - return; - } - - if (!isDefined(properties.visible)) { - properties.visible = true; - return; - } - - if (!isDefined(properties.opacity)) { - properties.opacity = 1; - return; - } - - var style; - var group; - var collection; - if (!isDefined(olLayer)) { - olLayer = createLayer(properties, projection); - if (isDefined(properties.group)) { - addLayerToGroup(layerCollection, olLayer, properties.group); - } else if (isDefined(properties.index)) { - insertLayer(layerCollection, properties.index, olLayer); - } else { - addLayerBeforeMarkers(layerCollection, olLayer); - } - - if (detectLayerType(properties) === 'Vector') { - setVectorLayerEvents(defaults.events, map, scope, properties.name); - } - - if (isBoolean(properties.visible)) { - olLayer.setVisible(properties.visible); - } - - if (properties.opacity) { - olLayer.setOpacity(properties.opacity); - } - - if (angular.isArray(properties.extent)) { - olLayer.setExtent(properties.extent); - } - - if (properties.style) { - if (!angular.isFunction(properties.style)) { - style = createStyle(properties.style); - } else { - style = properties.style; - } - // not every layer has a setStyle method - if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { - olLayer.setStyle(style); - } - } - - } else { - var isNewLayer = (function(olLayer) { - // this function can be used to verify whether a new layer instance has - // been created. This is needed in order to re-assign styles, opacity - // etc... - return function(layer) { - return layer !== olLayer; - }; - })(olLayer); - - // set source properties - if (isDefined(oldProperties) && !equals(properties.source, oldProperties.source)) { - var idx = olLayer.index; - collection = layerCollection; - group = olLayer.get('group'); - - if (group) { - collection = getGroup(layerCollection, group).getLayers(); - } - - collection.removeAt(idx); - - olLayer = createLayer(properties, projection); - olLayer.set('group', group); - - if (isDefined(olLayer)) { - insertLayer(collection, idx, olLayer); - - if (detectLayerType(properties) === 'Vector') { - setVectorLayerEvents(defaults.events, map, scope, properties.name); - } - } - } - - // set opacity - if (isDefined(oldProperties) && - properties.opacity !== oldProperties.opacity || isNewLayer(olLayer)) { - if (isNumber(properties.opacity) || isNumber(parseFloat(properties.opacity))) { - olLayer.setOpacity(properties.opacity); - } - } - - // set index - if (isDefined(properties.index) && properties.index !== olLayer.index) { - collection = layerCollection; - group = olLayer.get('group'); - - if (group) { - collection = getGroup(layerCollection, group).getLayers(); - } - - removeLayer(collection, olLayer.index); - insertLayer(collection, properties.index, olLayer); - } - - // set group - if (isDefined(properties.group) && properties.group !== oldProperties.group) { - removeLayerFromGroup(layerCollection, olLayer, oldProperties.group); - addLayerToGroup(layerCollection, olLayer, properties.group); - } - - // set visibility - if (isDefined(oldProperties) && - isBoolean(properties.visible) && - properties.visible !== oldProperties.visible || isNewLayer(olLayer)) { - olLayer.setVisible(properties.visible); - } - - // set style - if (isDefined(properties.style) && - !equals(properties.style, oldProperties.style) || isNewLayer(olLayer)) { - if (!angular.isFunction(properties.style)) { - style = createStyle(properties.style); - } else { - style = properties.style; - } - // not every layer has a setStyle method - if (olLayer.setStyle && angular.isFunction(olLayer.setStyle)) { - olLayer.setStyle(style); - } - } - } - }, true); - }); - } - }; -}); - -angular.module('openlayers-directive').directive('olPath', function($log, $q, olMapDefaults, olHelpers) { - - return { - restrict: 'E', - scope: { - properties: '=olGeomProperties' - }, - require: '^openlayers', - replace: true, - template: '', - - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var createFeature = olHelpers.createFeature; - var createOverlay = olHelpers.createOverlay; - var createVectorLayer = olHelpers.createVectorLayer; - var insertLayer = olHelpers.insertLayer; - var removeLayer = olHelpers.removeLayer; - var olScope = controller.getOpenlayersScope(); - - olScope.getMap().then(function(map) { - var mapDefaults = olMapDefaults.getDefaults(olScope); - var viewProjection = mapDefaults.view.projection; - - var layer = createVectorLayer(); - var layerCollection = map.getLayers(); - - insertLayer(layerCollection, layerCollection.getLength(), layer); - - scope.$on('$destroy', function() { - removeLayer(layerCollection, layer.index); - }); - - if (isDefined(attrs.coords)) { - var proj = attrs.proj || 'EPSG:4326'; - var coords = JSON.parse(attrs.coords); - var data = { - type: 'Polygon', - coords: coords, - projection: proj, - style: mapDefaults.styles.path - }; - var feature = createFeature(data, viewProjection); - layer.getSource().addFeature(feature); - - if (attrs.message) { - scope.message = attrs.message; - var extent = feature.getGeometry().getExtent(); - var label = createOverlay(element, extent); - map.addOverlay(label); - } - return; - } - }); - } - }; -}); - -angular.module('openlayers-directive').directive('olView', function($log, $q, olData, olMapDefaults, olHelpers) { - return { - restrict: 'A', - scope: false, - replace: false, - require: 'openlayers', - link: function(scope, element, attrs, controller) { - var olScope = controller.getOpenlayersScope(); - var isNumber = olHelpers.isNumber; - var safeApply = olHelpers.safeApply; - var createView = olHelpers.createView; - - olScope.getMap().then(function(map) { - var defaults = olMapDefaults.getDefaults(olScope); - var view = olScope.view; - - if (!view.projection) { - view.projection = defaults.view.projection; - } - - if (!view.maxZoom) { - view.maxZoom = defaults.view.maxZoom; - } - - if (!view.minZoom) { - view.minZoom = defaults.view.minZoom; - } - - if (!view.rotation) { - view.rotation = defaults.view.rotation; - } - - var mapView = createView(view); - map.setView(mapView); - - olScope.$watchCollection('view', function(view) { - if (isNumber(view.rotation)) { - mapView.setRotation(view.rotation); - } - }); - - mapView.on('change:rotation', function() { - safeApply(olScope, function(scope) { - scope.view.rotation = map.getView().getRotation(); - }); - }); - - }); - } - }; -}); - -angular.module('openlayers-directive').directive('olControl', function($log, $q, olData, olMapDefaults, olHelpers) { - - return { - restrict: 'E', - scope: { - properties: '=olControlProperties' - }, - replace: false, - require: '^openlayers', - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var olScope = controller.getOpenlayersScope(); - var olControl; - var olControlOps; - - olScope.getMap().then(function(map) { - var getControlClasses = olHelpers.getControlClasses; - var controlClasses = getControlClasses(); - - scope.$on('$destroy', function() { - map.removeControl(olControl); - }); - - if (!isDefined(scope.properties) || !isDefined(scope.properties.control)) { - if (attrs.name) { - if (isDefined(scope.properties)) { - olControlOps = scope.properties; - } - olControl = new controlClasses[attrs.name](olControlOps); - map.addControl(olControl); - } - return; - } - - olControl = scope.properties.control; - map.addControl(olControl); - }); - } - }; -}); - -angular.module('openlayers-directive').directive('olMarker', function($log, $q, olMapDefaults, olHelpers) { - - var getMarkerDefaults = function() { - return { - projection: 'EPSG:4326', - lat: 0, - lon: 0, - coord: [], - show: true, - showOnMouseOver: false, - showOnMouseClick: false, - keepOneOverlayVisible: false - }; - }; - - var markerLayerManager = (function() { - var mapDict = []; - - function getMapIndex(map) { - return mapDict.map(function(record) { - return record.map; - }).indexOf(map); - } - - return { - getInst: function getMarkerLayerInst(scope, map) { - var mapIndex = getMapIndex(map); - - if (mapIndex === -1) { - var markerLayer = olHelpers.createVectorLayer(); - markerLayer.set('markers', true); - map.addLayer(markerLayer); - mapDict.push({ - map: map, - markerLayer: markerLayer, - instScopes: [] - }); - mapIndex = mapDict.length - 1; - } - - mapDict[mapIndex].instScopes.push(scope); - - return mapDict[mapIndex].markerLayer; - }, - deregisterScope: function deregisterScope(scope, map) { - var mapIndex = getMapIndex(map); - if (mapIndex === -1) { - throw Error('This map has no markers'); - } - - var scopes = mapDict[mapIndex].instScopes; - var scopeIndex = scopes.indexOf(scope); - if (scopeIndex === -1) { - throw Error('Scope wan\'t registered'); - } - - scopes.splice(scopeIndex, 1); - - if (!scopes.length) { - map.removeLayer(mapDict[mapIndex].markerLayer); - delete mapDict[mapIndex]; - } - } - }; - })(); - return { - restrict: 'E', - scope: { - lat: '=lat', - lon: '=lon', - label: '=label', - properties: '=olMarkerProperties', - style: '=olStyle' - }, - transclude: true, - require: '^openlayers', - replace: true, - template: - '', - - link: function(scope, element, attrs, controller) { - var isDefined = olHelpers.isDefined; - var olScope = controller.getOpenlayersScope(); - var createFeature = olHelpers.createFeature; - var createOverlay = olHelpers.createOverlay; - - var hasTranscluded = element.find('ng-transclude').children().length > 0; - - olScope.getMap().then(function(map) { - var markerLayer = markerLayerManager.getInst(scope, map); - var data = getMarkerDefaults(); - - var mapDefaults = olMapDefaults.getDefaults(olScope); - var viewProjection = mapDefaults.view.projection; - var label; - var pos; - var marker; - - // This function handles dragging a marker - var pickOffset = null; - var pickProperties = null; - function handleDrag(evt) { - var coord = evt.coordinate; - var proj = map.getView().getProjection().getCode(); - if (proj === 'pixel') { - coord = coord.map(function(v) { - return parseInt(v, 10); - }); - } else { - coord = ol.proj.transform(coord, proj, 'EPSG:4326'); - } - - if (evt.type === 'pointerdown') { - // Get feature under mouse if any - var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { - return feature; - }); - // Get associated marker properties - pickProperties = (feature ? feature.get('marker') : null); - if (!pickProperties || !pickProperties.draggable) { - pickProperties = null; - return; - } - map.getTarget().style.cursor = 'pointer'; - if (proj === 'pixel') { - pickOffset = [coord[0] - pickProperties.coord[0], coord[1] - pickProperties.coord[1]]; - } else { - pickOffset = [coord[0] - pickProperties.lon, coord[1] - pickProperties.lat]; - } - evt.preventDefault(); - } else if (pickOffset && pickProperties) { - if (evt.type === 'pointerup') { - map.getTarget().style.cursor = ''; - pickOffset = null; - pickProperties = null; - evt.preventDefault(); - } else if (evt.type === 'pointerdrag') { - evt.preventDefault(); - scope.$apply(function() { - // Add current delta to marker initial position - if (proj === 'pixel') { - pickProperties.coord[0] = coord[0] - pickOffset[0]; - pickProperties.coord[1] = coord[1] - pickOffset[1]; - } else { - pickProperties.lon = coord[0] - pickOffset[0]; - pickProperties.lat = coord[1] - pickOffset[1]; - } - }); - } - } - } - - // Setup generic handlers for marker drag - map.on('pointerdown', handleDrag); - map.on('pointerup', handleDrag); - map.on('pointerdrag', handleDrag); - - scope.$on('$destroy', function() { - markerLayer.getSource().removeFeature(marker); - if (isDefined(label)) { - map.removeOverlay(label); - } - markerLayerManager.deregisterScope(scope, map); - }); - - if (!isDefined(scope.properties)) { - data.lat = scope.lat ? scope.lat : data.lat; - data.lon = scope.lon ? scope.lon : data.lon; - data.message = attrs.message; - data.style = scope.style ? scope.style : mapDefaults.styles.marker; - - marker = createFeature(data, viewProjection); - if (!isDefined(marker)) { - $log.error('[AngularJS - Openlayers] Received invalid data on ' + - 'the marker.'); - } - // Add a link between the feature and the marker properties - marker.set('marker', scope); - markerLayer.getSource().addFeature(marker); - - if (data.message || hasTranscluded) { - scope.message = attrs.message; - pos = ol.proj.transform([data.lon, data.lat], data.projection, - viewProjection); - label = createOverlay(element, pos); - map.addOverlay(label); - } - return; - } - - scope.$watch('properties', function(properties) { - - // Remove previous listeners if any - map.getViewport().removeEventListener('mousemove', properties.handleInteraction); - map.getViewport().removeEventListener('click', properties.handleTapInteraction); - map.getViewport().querySelector('canvas.ol-unselectable').removeEventListener( - 'touchend', properties.handleTapInteraction); - map.getViewport().removeEventListener('mousemove', properties.showAtLeastOneOverlay); - map.getViewport().removeEventListener('click', properties.removeAllOverlays); - - // This function handles popup on mouse over/click - properties.handleInteraction = function(evt) { - if (properties.label.show) { - return; - } - var found = false; - var pixel = map.getEventPixel(evt); - var feature = map.forEachFeatureAtPixel(pixel, function(feature) { - return feature; - }); - - var actionTaken = false; - if (feature === marker) { - actionTaken = true; - found = true; - if (!isDefined(label)) { - if (data.projection === 'pixel') { - pos = properties.coord; - } else { - pos = ol.proj.transform([properties.lon, properties.lat], - data.projection, viewProjection); - } - label = createOverlay(element, pos); - map.addOverlay(label); - } - - if (properties.onClick && (evt.type === 'click' || evt.type === 'touchend')) { - scope.$apply(function() { - properties.onClick.call(marker, evt, properties); - }); - } - map.getTarget().style.cursor = 'pointer'; - } - - if (!found && label) { - actionTaken = true; - map.removeOverlay(label); - label = undefined; - map.getTarget().style.cursor = ''; - } - - if (actionTaken) { - evt.preventDefault(); - } - }; - - // Made to filter out click/tap events if both are being triggered on this platform - properties.handleTapInteraction = (function() { - var cooldownActive = false; - var prevTimeout; - - // Sets the cooldown flag to filter out any subsequent events within 500 ms - function activateCooldown() { - cooldownActive = true; - if (prevTimeout) { - clearTimeout(prevTimeout); - } - prevTimeout = setTimeout(function() { - cooldownActive = false; - prevTimeout = null; - }, 500); - } - - // Preventing from 'touchend' to be considered a tap, if fired immediately after 'touchmove' - map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( - 'touchmove', activateCooldown); - - return function() { - if (!cooldownActive) { - properties.handleInteraction.apply(null, arguments); - activateCooldown(); - } - }; - })(); - - properties.showAtLeastOneOverlay = function(evt) { - if (properties.label.show) { - return; - } - var found = false; - var pixel = map.getEventPixel(evt); - var feature = map.forEachFeatureAtPixel(pixel, function(feature) { - return feature; - }); - - var actionTaken = false; - if (feature === marker) { - actionTaken = true; - found = true; - if (!isDefined(label)) { - if (data.projection === 'pixel') { - pos = data.coord; - } else { - pos = ol.proj.transform([data.lon, data.lat], - data.projection, viewProjection); - } - label = createOverlay(element, pos); - angular.forEach(map.getOverlays(), function(value) { - map.removeOverlay(value); - }); - map.addOverlay(label); - } - map.getTarget().style.cursor = 'pointer'; - } - - if (!found && label) { - actionTaken = true; - label = undefined; - map.getTarget().style.cursor = ''; - } - - if (actionTaken) { - evt.preventDefault(); - } - }; - - properties.removeAllOverlays = function(evt) { - angular.forEach(map.getOverlays(), function(value) { - map.removeOverlay(value); - }); - evt.preventDefault(); - }; - - if (!isDefined(marker)) { - data.projection = properties.projection ? properties.projection : - data.projection; - data.coord = properties.coord ? properties.coord : data.coord; - data.lat = properties.lat ? properties.lat : data.lat; - data.lon = properties.lon ? properties.lon : data.lon; - - if (isDefined(properties.style)) { - data.style = properties.style; - } else { - data.style = mapDefaults.styles.marker; - } - - marker = createFeature(data, viewProjection); - if (!isDefined(marker)) { - $log.error('[AngularJS - Openlayers] Received invalid data on ' + - 'the marker.'); - } - // Add a link between the feature and the marker properties - marker.set('marker', properties); - markerLayer.getSource().addFeature(marker); - } else { - var requestedPosition; - if (properties.projection === 'pixel') { - requestedPosition = properties.coord; - } else { - requestedPosition = ol.proj.transform([properties.lon, properties.lat], data.projection, - map.getView().getProjection()); - } - - if (!angular.equals(marker.getGeometry().getCoordinates(), requestedPosition)) { - var geometry = new ol.geom.Point(requestedPosition); - marker.setGeometry(geometry); - } - } - - if (isDefined(label)) { - map.removeOverlay(label); - } - - if (!isDefined(properties.label)) { - return; - } - - scope.message = properties.label.message; - if (!hasTranscluded && (!isDefined(scope.message) || scope.message.length === 0)) { - return; - } - - if (properties.label && properties.label.show === true) { - if (data.projection === 'pixel') { - pos = data.coord; - } else { - pos = ol.proj.transform([properties.lon, properties.lat], data.projection, - viewProjection); - } - label = createOverlay(element, pos); - map.addOverlay(label); - } - - if (label && properties.label && properties.label.show === false) { - map.removeOverlay(label); - label = undefined; - } - - // Then setup new ones according to properties - if (properties.label && properties.label.show === false && - properties.label.showOnMouseOver) { - map.getViewport().addEventListener('mousemove', properties.handleInteraction); - } - - if ((properties.label && properties.label.show === false && - properties.label.showOnMouseClick) || - properties.onClick) { - map.getViewport().addEventListener('click', properties.handleTapInteraction); - map.getViewport().querySelector('canvas.ol-unselectable').addEventListener( - 'touchend', properties.handleTapInteraction); - } - - if ((properties.label && properties.label.show === false && - properties.label.keepOneOverlayVisible)) { - map.getViewport().addEventListener('mousemove', properties.showAtLeastOneOverlay); - map.getViewport().addEventListener('click', properties.removeAllOverlays); - } - }, true); - }); - } - }; -}); - -angular.module('openlayers-directive').service('olData', function($log, $q, olHelpers) { - - var obtainEffectiveMapId = olHelpers.obtainEffectiveMapId; - - var maps = {}; - - var setResolvedDefer = function(d, mapId) { - var id = obtainEffectiveMapId(d, mapId); - d[id].resolvedDefer = true; - }; - - var getUnresolvedDefer = function(d, mapId) { - var id = obtainEffectiveMapId(d, mapId); - var defer; - - if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) { - defer = $q.defer(); - d[id] = { - defer: defer, - resolvedDefer: false - }; - } else { - defer = d[id].defer; - } - return defer; - }; - - var getDefer = function(d, mapId) { - var id = obtainEffectiveMapId(d, mapId); - var defer; - - if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) { - defer = getUnresolvedDefer(d, mapId); - } else { - defer = d[id].defer; - } - return defer; - }; - - this.setMap = function(olMap, scopeId) { - var defer = getUnresolvedDefer(maps, scopeId); - defer.resolve(olMap); - setResolvedDefer(maps, scopeId); - }; - - this.getMap = function(scopeId) { - var defer = getDefer(maps, scopeId); - return defer.promise; - }; - -}); - -angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $http) { - - var isDefined = function(value) { - return angular.isDefined(value); - }; - - var isDefinedAndNotNull = function(value) { - return angular.isDefined(value) && value !== null; - }; - - var setEvent = function(map, eventType, scope) { - map.on(eventType, function(event) { - var coord = event.coordinate; - var proj = map.getView().getProjection().getCode(); - if (proj === 'pixel') { - coord = coord.map(function(v) { - return parseInt(v, 10); - }); - } - scope.$emit('openlayers.map.' + eventType, { - 'coord': coord, - 'projection': proj, - 'event': event - }); - }); - }; - - var bingImagerySets = [ - 'Road', - 'Aerial', - 'AerialWithLabels', - 'collinsBart', - 'ordnanceSurvey' - ]; - - var getControlClasses = function() { - return { - attribution: ol.control.Attribution, - fullscreen: ol.control.FullScreen, - mouseposition: ol.control.MousePosition, - rotate: ol.control.Rotate, - scaleline: ol.control.ScaleLine, - zoom: ol.control.Zoom, - zoomslider: ol.control.ZoomSlider, - zoomtoextent: ol.control.ZoomToExtent - }; - }; - - var mapQuestLayers = ['osm', 'sat', 'hyb']; - - var esriBaseLayers = ['World_Imagery', 'World_Street_Map', 'World_Topo_Map', - 'World_Physical_Map', 'World_Terrain_Base', - 'Ocean_Basemap', 'NatGeo_World_Map']; - - var styleMap = { - 'style': ol.style.Style, - 'fill': ol.style.Fill, - 'stroke': ol.style.Stroke, - 'circle': ol.style.Circle, - 'icon': ol.style.Icon, - 'image': ol.style.Image, - 'regularshape': ol.style.RegularShape, - 'text': ol.style.Text - }; - - var optionalFactory = function(style, Constructor) { - if (Constructor && style instanceof Constructor) { - return style; - } else if (Constructor) { - return new Constructor(style); - } else { - return style; - } - }; - - //Parse the style tree calling the appropriate constructors. - //The keys in styleMap can be used and the OpenLayers constructors can be - //used directly. - var createStyle = function recursiveStyle(data, styleName) { - var style; - if (!styleName) { - styleName = 'style'; - style = data; - } else { - style = data[styleName]; - } - //Instead of defining one style for the layer, we've been given a style function - //to apply to each feature. - if (styleName === 'style' && data instanceof Function) { - return data; - } - - if (!(style instanceof Object)) { - return style; - } - - var styleObject; - if (Object.prototype.toString.call(style) === '[object Object]') { - styleObject = {}; - var styleConstructor = styleMap[styleName]; - if (styleConstructor && style instanceof styleConstructor) { - return style; - } - Object.getOwnPropertyNames(style).forEach(function(val, idx, array) { - //Consider the case - //image: { - // circle: { - // fill: { - // color: 'red' - // } - // } - // - //An ol.style.Circle is an instance of ol.style.Image, so we do not want to construct - //an Image and then construct a Circle. We assume that if we have an instanceof - //relationship, that the JSON parent has exactly one child. - //We check to see if an inheritance relationship exists. - //If it does, then for the parent we create an instance of the child. - var valConstructor = styleMap[val]; - if (styleConstructor && valConstructor && - valConstructor.prototype instanceof styleMap[styleName]) { - console.assert(array.length === 1, 'Extra parameters for ' + styleName); - styleObject = recursiveStyle(style, val); - return optionalFactory(styleObject, valConstructor); - } else { - styleObject[val] = recursiveStyle(style, val); - - // if the value is 'text' and it contains a String, then it should be interpreted - // as such, 'cause the text style might effectively contain a text to display - if (val !== 'text' && typeof styleObject[val] !== 'string') { - styleObject[val] = optionalFactory(styleObject[val], styleMap[val]); - } - } - }); - } else { - styleObject = style; - } - return optionalFactory(styleObject, styleMap[styleName]); - }; - - var detectLayerType = function(layer) { - if (layer.type) { - return layer.type; - } else { - switch (layer.source.type) { - case 'ImageWMS': - return 'Image'; - case 'ImageStatic': - return 'Image'; - case 'GeoJSON': - case 'JSONP': - case 'TopoJSON': - case 'KML': - case 'TileVector': - return 'Vector'; - default: - return 'Tile'; - } - } - }; - - var createProjection = function(view) { - var oProjection; - - switch (view.projection) { - case 'pixel': - if (!isDefined(view.extent)) { - $log.error('[AngularJS - Openlayers] - You must provide the extent of the image ' + - 'if using pixel projection'); - return; - } - oProjection = new ol.proj.Projection({ - code: 'pixel', - units: 'pixels', - extent: view.extent - }); - break; - default: - oProjection = new ol.proj.get(view.projection); - break; - } - - return oProjection; - }; - - var isValidStamenLayer = function(layer) { - return ['watercolor', 'terrain', 'toner'].indexOf(layer) !== -1; - }; - - var createSource = function(source, projection) { - var oSource; - - switch (source.type) { - case 'MapBox': - if (!source.mapId || !source.accessToken) { - $log.error('[AngularJS - Openlayers] - MapBox layer requires the map id and the access token'); - return; - } - var url = 'http://api.tiles.mapbox.com/v4/' + source.mapId + '/{z}/{x}/{y}.png?access_token=' + - source.accessToken; - - var pixelRatio = window.devicePixelRatio; - - if (pixelRatio > 1) { - url = url.replace('.png', '@2x.png'); - } - - oSource = new ol.source.XYZ({ - url: url, - attributions: createAttribution(source), - tilePixelRatio: pixelRatio > 1 ? 2 : 1, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'ImageWMS': - if (!source.url || !source.params) { - $log.error('[AngularJS - Openlayers] - ImageWMS Layer needs ' + - 'valid server url and params properties'); - } - oSource = new ol.source.ImageWMS({ - url: source.url, - attributions: createAttribution(source), - crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, - params: source.params, - wrapX: source.wrapX ? 0 : 1 - }); - break; - - case 'TileWMS': - if ((!source.url && !source.urls) || !source.params) { - $log.error('[AngularJS - Openlayers] - TileWMS Layer needs ' + - 'valid url (or urls) and params properties'); - } - - var wmsConfiguration = { - crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, - params: source.params, - attributions: createAttribution(source), - wrapX: source.wrapX ? 0 : 1 - }; - - if (source.url) { - wmsConfiguration.url = source.url; - } - - if (source.urls) { - wmsConfiguration.urls = source.urls; - } - - oSource = new ol.source.TileWMS(wmsConfiguration); - break; - - case 'WMTS': - if ((!source.url && !source.urls) || !source.tileGrid) { - $log.error('[AngularJS - Openlayers] - WMTS Layer needs valid url ' + - '(or urls) and tileGrid properties'); - } - - var wmtsConfiguration = { - projection: projection, - layer: source.layer, - attributions: createAttribution(source), - matrixSet: (source.matrixSet === 'undefined') ? projection : source.matrixSet, - format: (source.format === 'undefined') ? 'image/jpeg' : source.format, - requestEncoding: (source.requestEncoding === 'undefined') ? - 'KVP' : source.requestEncoding, - tileGrid: new ol.tilegrid.WMTS({ - origin: source.tileGrid.origin, - resolutions: source.tileGrid.resolutions, - matrixIds: source.tileGrid.matrixIds - }), - wrapX: source.wrapX ? 0 : 1 - }; - - if (isDefined(source.url)) { - wmtsConfiguration.url = source.url; - } - - if (isDefined(source.urls)) { - wmtsConfiguration.urls = source.urls; - } - - oSource = new ol.source.WMTS(wmtsConfiguration); - break; - - case 'OSM': - oSource = new ol.source.OSM({ - attributions: createAttribution(source), - wrapX: (source.wrapX === true) ? 1 : 0 - }); - - if (source.url) { - oSource.setUrl(source.url); - } - - break; - case 'BingMaps': - if (!source.key) { - $log.error('[AngularJS - Openlayers] - You need an API key to show the Bing Maps.'); - return; - } - - var bingConfiguration = { - key: source.key, - attributions: createAttribution(source), - imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], - culture: source.culture, - wrapX: (source.wrapX === true) ? 1 : 0 - }; - - if (source.maxZoom) { - bingConfiguration.maxZoom = source.maxZoom; - } - - oSource = new ol.source.BingMaps(bingConfiguration); - break; - - case 'MapQuest': - if (!source.layer || mapQuestLayers.indexOf(source.layer) === -1) { - $log.error('[AngularJS - Openlayers] - MapQuest layers needs a valid \'layer\' property.'); - return; - } - - oSource = new ol.source.MapQuest({ - attributions: createAttribution(source), - layer: source.layer, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - - break; - - case 'EsriBaseMaps': - if (!source.layer || esriBaseLayers.indexOf(source.layer) === -1) { - $log.error('[AngularJS - Openlayers] - ESRI layers needs a valid \'layer\' property.'); - return; - } - - var _urlBase = 'http://services.arcgisonline.com/ArcGIS/rest/services/'; - var _url = _urlBase + source.layer + '/MapServer/tile/{z}/{y}/{x}'; - - oSource = new ol.source.XYZ({ - attributions: createAttribution(source), - url: _url, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - - break; - - case 'GeoJSON': - if (!(source.geojson || source.url)) { - $log.error('[AngularJS - Openlayers] - You need a geojson ' + - 'property to add a GeoJSON layer.'); - return; - } - - if (isDefined(source.url)) { - oSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - url: source.url, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - } else { - oSource = new ol.source.Vector(); - - var projectionToUse = projection; - if (isDefined(source.geojson.projection)) { - projectionToUse = source.geojson.projection; - } - - var geojsonFormat = new ol.format.GeoJSON(); - var features = geojsonFormat.readFeatures( - source.geojson.object, { featureProjection: projectionToUse }); - - oSource.addFeatures(features); - } - - break; - case 'JSONP': - if (!(source.url)) { - $log.error('[AngularJS - Openlayers] - You need an url properly configured to add a JSONP layer.'); - return; - } - - if (isDefined(source.url)) { - oSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - loader: function(/*extent, resolution, projection*/) { - var url = source.url + - '&outputFormat=text/javascript&format_options=callback:JSON_CALLBACK'; - $http.jsonp(url, { cache: source.cache}).success(function(response) { - oSource.addFeatures(oSource.readFeatures(response)); - }).error(function(response) { - $log(response); - }); - }, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - } - break; - case 'TopoJSON': - if (!(source.topojson || source.url)) { - $log.error('[AngularJS - Openlayers] - You need a topojson ' + - 'property to add a TopoJSON layer.'); - return; - } - - if (source.url) { - oSource = new ol.source.Vector({ - format: new ol.format.TopoJSON(), - url: source.url, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - } else { - oSource = new ol.source.Vector(angular.extend(source.topojson, { - format: new ol.format.TopoJSON(), - wrapX: (source.wrapX === true) ? 1 : 0 - })); - } - break; - case 'TileJSON': - oSource = new ol.source.TileJSON({ - url: source.url, - attributions: createAttribution(source), - crossOrigin: 'anonymous', - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - - case 'TileVector': - if (!source.url || !source.format) { - $log.error('[AngularJS - Openlayers] - TileVector Layer needs valid url and format properties'); - } - oSource = new ol.source.TileVector({ - url: source.url, - projection: projection, - attributions: createAttribution(source), - format: source.format, - tileGrid: new ol.tilegrid.createXYZ({ - maxZoom: source.maxZoom || 19 - }), - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - - case 'TileTMS': - if (!source.url || !source.tileGrid) { - $log.error('[AngularJS - Openlayers] - TileTMS Layer needs valid url and tileGrid properties'); - } - oSource = new ol.source.TileImage({ - url: source.url, - maxExtent: source.maxExtent, - attributions: createAttribution(source), - tileGrid: new ol.tilegrid.TileGrid({ - origin: source.tileGrid.origin, - resolutions: source.tileGrid.resolutions - }), - tileUrlFunction: function(tileCoord) { - - var z = tileCoord[0]; - var x = tileCoord[1]; - var y = tileCoord[2]; //(1 << z) - tileCoord[2] - 1; - - if (x < 0 || y < 0) { - return ''; - } - - var url = source.url + z + '/' + x + '/' + y + '.png'; - - return url; - }, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'TileImage': - oSource = new ol.source.TileImage({ - url: source.url, - attributions: createAttribution(source), - tileGrid: new ol.tilegrid.TileGrid({ - origin: source.tileGrid.origin, // top left corner of the pixel projection's extent - resolutions: source.tileGrid.resolutions - }), - tileUrlFunction: function(tileCoord/*, pixelRatio, projection*/) { - var z = tileCoord[0]; - var x = tileCoord[1]; - var y = -tileCoord[2] - 1; - var url = source.url - .replace('{z}', z.toString()) - .replace('{x}', x.toString()) - .replace('{y}', y.toString()); - return url; - }, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'KML': - var extractStyles = source.extractStyles || false; - oSource = new ol.source.Vector({ - url: source.url, - format: new ol.format.KML(), - radius: source.radius, - extractStyles: extractStyles, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'Stamen': - if (!source.layer || !isValidStamenLayer(source.layer)) { - $log.error('[AngularJS - Openlayers] - You need a valid Stamen layer.'); - return; - } - oSource = new ol.source.Stamen({ - layer: source.layer, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'ImageStatic': - if (!source.url || !angular.isArray(source.imageSize) || source.imageSize.length !== 2) { - $log.error('[AngularJS - Openlayers] - You need a image URL to create a ImageStatic layer.'); - return; - } - - oSource = new ol.source.ImageStatic({ - url: source.url, - attributions: createAttribution(source), - imageSize: source.imageSize, - projection: projection, - imageExtent: projection.getExtent(), - imageLoadFunction: source.imageLoadFunction, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - case 'XYZ': - if (!source.url) { - $log.error('[AngularJS - Openlayers] - XYZ Layer needs valid url and params properties'); - } - oSource = new ol.source.XYZ({ - url: source.url, - attributions: createAttribution(source), - minZoom: source.minZoom, - maxZoom: source.maxZoom, - wrapX: (source.wrapX === true) ? 1 : 0 - }); - break; - } - - // log a warning when no source could be created for the given type - if (!oSource) { - $log.warn('[AngularJS - Openlayers] - No source could be found for type "' + source.type + '"'); - } - - return oSource; - }; - - var createAttribution = function(source) { - var attributions = []; - if (isDefined(source.attribution)) { - attributions.unshift(new ol.Attribution({html: source.attribution})); - } - return attributions; - }; - - var createGroup = function(name) { - var olGroup = new ol.layer.Group(); - olGroup.set('name', name); - - return olGroup; - }; - - var getGroup = function(layers, name) { - var layer; - - angular.forEach(layers, function(l) { - if (l instanceof ol.layer.Group && l.get('name') === name) { - layer = l; - return; - } - }); - - return layer; - }; - - var addLayerBeforeMarkers = function(layers, layer) { - var markersIndex; - for (var i = 0; i < layers.getLength(); i++) { - var l = layers.item(i); - - if (l.get('markers')) { - markersIndex = i; - break; - } - } - - if (isDefined(markersIndex)) { - var markers = layers.item(markersIndex); - layer.index = markersIndex; - layers.setAt(markersIndex, layer); - markers.index = layers.getLength(); - layers.push(markers); - } else { - layer.index = layers.getLength(); - layers.push(layer); - } - - }; - - var removeLayer = function(layers, index) { - layers.removeAt(index); - for (var i = index; i < layers.getLength(); i++) { - var l = layers.item(i); - if (l === null) { - layers.insertAt(i, null); - break; - } else { - l.index = i; - } - } - }; - - return { - // Determine if a reference is defined - isDefined: isDefined, - - // Determine if a reference is a number - isNumber: function(value) { - return angular.isNumber(value); - }, - - createView: function(view) { - var projection = createProjection(view); - - return new ol.View({ - projection: projection, - maxZoom: view.maxZoom, - minZoom: view.minZoom, - extent: view.extent - }); - }, - - // Determine if a reference is defined and not null - isDefinedAndNotNull: isDefinedAndNotNull, - - // Determine if a reference is a string - isString: function(value) { - return angular.isString(value); - }, - - // Determine if a reference is an array - isArray: function(value) { - return angular.isArray(value); - }, - - // Determine if a reference is an object - isObject: function(value) { - return angular.isObject(value); - }, - - // Determine if two objects have the same properties - equals: function(o1, o2) { - return angular.equals(o1, o2); - }, - - isValidCenter: function(center) { - return angular.isDefined(center) && - (typeof center.autodiscover === 'boolean' || - angular.isNumber(center.lat) && angular.isNumber(center.lon) || - (angular.isArray(center.coord) && center.coord.length === 2 && - angular.isNumber(center.coord[0]) && angular.isNumber(center.coord[1])) || - (angular.isArray(center.bounds) && center.bounds.length === 4 && - angular.isNumber(center.bounds[0]) && angular.isNumber(center.bounds[1]) && - angular.isNumber(center.bounds[1]) && angular.isNumber(center.bounds[2]))); - }, - - safeApply: function($scope, fn) { - var phase = $scope.$root.$$phase; - if (phase === '$apply' || phase === '$digest') { - $scope.$eval(fn); - } else { - $scope.$apply(fn); - } - }, - - isSameCenterOnMap: function(center, map) { - var urlProj = center.projection || 'EPSG:4326'; - var urlCenter = [center.lon, center.lat]; - var mapProj = map.getView().getProjection(); - var mapCenter = ol.proj.transform(map.getView().getCenter(), mapProj, urlProj); - var zoom = map.getView().getZoom(); - if (mapCenter[1].toFixed(4) === urlCenter[1].toFixed(4) && - mapCenter[0].toFixed(4) === urlCenter[0].toFixed(4) && - zoom === center.zoom) { - return true; - } - return false; - }, - - setCenter: function(view, projection, newCenter, map) { - - if (map && view.getCenter()) { - var pan = ol.animation.pan({ - duration: 150, - source: (view.getCenter()) - }); - map.beforeRender(pan); - } - - if (newCenter.projection === projection) { - view.setCenter([newCenter.lon, newCenter.lat]); - } else { - var coord = [newCenter.lon, newCenter.lat]; - view.setCenter(ol.proj.transform(coord, newCenter.projection, projection)); - } - }, - - setZoom: function(view, zoom, map) { - var z = ol.animation.zoom({ - duration: 150, - resolution: map.getView().getResolution() - }); - map.beforeRender(z); - view.setZoom(zoom); - }, - - isBoolean: function(value) { - return typeof value === 'boolean'; - }, - - obtainEffectiveMapId: function(d, mapId) { - var id; - var i; - if (!angular.isDefined(mapId)) { - if (Object.keys(d).length === 1) { - for (i in d) { - if (d.hasOwnProperty(i)) { - id = i; - } - } - } else if (Object.keys(d).length === 0) { - id = 'main'; - } else { - $log.error('[AngularJS - Openlayers] - You have more than 1 map on the DOM, ' + - 'you must provide the map ID to the olData.getXXX call'); - } - } else { - id = mapId; - } - return id; - }, - - createStyle: createStyle, - - setMapEvents: function(events, map, scope) { - if (isDefined(events) && angular.isArray(events.map)) { - for (var i in events.map) { - var event = events.map[i]; - setEvent(map, event, scope); - } - } - }, - - setVectorLayerEvents: function(events, map, scope, layerName) { - if (isDefined(events) && angular.isArray(events.layers)) { - angular.forEach(events.layers, function(eventType) { - angular.element(map.getViewport()).on(eventType, function(evt) { - var pixel = map.getEventPixel(evt); - var feature = map.forEachFeatureAtPixel(pixel, function(feature, olLayer) { - // only return the feature if it is in this layer (based on the name) - return (isDefinedAndNotNull(olLayer) && olLayer.get('name') === layerName) ? feature : null; - }); - if (isDefinedAndNotNull(feature)) { - scope.$emit('openlayers.layers.' + layerName + '.' + eventType, feature, evt); - } - }); - }); - } - }, - - setViewEvents: function(events, map, scope) { - if (isDefined(events) && angular.isArray(events.view)) { - var view = map.getView(); - angular.forEach(events.view, function(eventType) { - view.on(eventType, function(event) { - scope.$emit('openlayers.view.' + eventType, view, event); - }); - }); - } - }, - - detectLayerType: detectLayerType, - - createLayer: function(layer, projection, name) { - var oLayer; - var type = detectLayerType(layer); - var oSource = createSource(layer.source, projection); - if (!oSource) { - return; - } - - // Manage clustering - if ((type === 'Vector') && layer.clustering) { - oSource = new ol.source.Cluster({ - source: oSource, - distance: layer.clusteringDistance, - }); - } - - switch (type) { - case 'Image': - oLayer = new ol.layer.Image({ source: oSource }); - break; - case 'Tile': - oLayer = new ol.layer.Tile({ source: oSource }); - break; - case 'Heatmap': - oLayer = new ol.layer.Heatmap({ source: oSource }); - break; - case 'Vector': - oLayer = new ol.layer.Vector({ source: oSource }); - break; - } - - // set a layer name if given - if (isDefined(name)) { - oLayer.set('name', name); - } else if (isDefined(layer.name)) { - oLayer.set('name', layer.name); - } - - return oLayer; - }, - - createVectorLayer: function() { - return new ol.layer.Vector({ - source: new ol.source.Vector() - }); - }, - - notifyCenterUrlHashChanged: function(scope, center, search) { - if (center.centerUrlHash) { - var centerUrlHash = center.lat.toFixed(4) + ':' + center.lon.toFixed(4) + ':' + center.zoom; - if (!isDefined(search.c) || search.c !== centerUrlHash) { - scope.$emit('centerUrlHash', centerUrlHash); - } - } - }, - - getControlClasses: getControlClasses, - - detectControls: function(controls) { - var actualControls = {}; - var controlClasses = getControlClasses(); - - controls.forEach(function(control) { - for (var i in controlClasses) { - if (control instanceof controlClasses[i]) { - actualControls[i] = control; - } - } - }); - - return actualControls; - }, - - createFeature: function(data, viewProjection) { - var geometry; - - switch (data.type) { - case 'Polygon': - geometry = new ol.geom.Polygon(data.coords); - break; - default: - if (isDefined(data.coord) && data.projection === 'pixel') { - geometry = new ol.geom.Point(data.coord); - } else { - geometry = new ol.geom.Point([data.lon, data.lat]); - } - break; - } - - if (isDefined(data.projection) && data.projection !== 'pixel') { - geometry = geometry.transform(data.projection, viewProjection); - } - - var feature = new ol.Feature({ - geometry: geometry - }); - - if (isDefined(data.style)) { - var style = createStyle(data.style); - feature.setStyle(style); - } - return feature; - }, - - addLayerBeforeMarkers: addLayerBeforeMarkers, - - getGroup: getGroup, - - addLayerToGroup: function(layers, layer, name) { - var groupLayer = getGroup(layers, name); - - if (!isDefined(groupLayer)) { - groupLayer = createGroup(name); - addLayerBeforeMarkers(layers,groupLayer); - } - - layer.set('group', name); - addLayerBeforeMarkers(groupLayer.getLayers(), layer); - }, - - removeLayerFromGroup: function(layers, layer, name) { - var groupLayer = getGroup(layers, name); - layer.set('group'); - removeLayer(groupLayer.getLayers(), layer.index); - }, - - removeLayer: removeLayer, - - insertLayer: function(layers, index, layer) { - if (layers.getLength() < index) { - while (layers.getLength() < index) { - layers.push(null); - } - layer.index = index; - layers.push(layer); - } else { - layer.index = index; - layers.insertAt(layer.index, layer); - for (var i = index + 1; i < layers.getLength(); i++) { - var l = layers.item(i); - if (l === null) { - layers.removeAt(i); - break; - } else { - l.index = i; - } - } - } - }, - - createOverlay: function(element, pos) { - element.css('display', 'block'); - var ov = new ol.Overlay({ - position: pos, - element: element, - positioning: 'center-left' - }); - - return ov; - } - }; -}); - -angular.module('openlayers-directive').factory('olMapDefaults', function($q, olHelpers) { - - var base64icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw' + - '7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGq' + - 'KII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR' + - '6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWV' + - 'MqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23' + - 'h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o' + - '+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzq' + - 'Bk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0g' + - 'pBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF' + - '3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAw' + - 'AhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5W' + - 'YnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRcha' + - 'h8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1E' + - 'IlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk' + - '4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/' + - 'tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdW' + - 'r7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0' + - 'ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIP' + - 'hP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmql' + - 'yvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsY' + - 'J7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/' + - 'WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIa' + - 'vznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV' + - '3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R' + - '3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDl' + - 'lwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQ' + - 'SCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92' + - 'H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GC' + - 'LVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjN' + - 'cNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg=='; - - var _getDefaults = function() { - return { - view: { - projection: 'EPSG:3857', - minZoom: undefined, - maxZoom: undefined, - rotation: 0, - extent: undefined - }, - center: { - lat: 0, - lon: 0, - zoom: 1, - autodiscover: false, - bounds: [], - centerUrlHash: false, - projection: 'EPSG:4326' - }, - styles: { - path: { - stroke: { - color: 'blue', - width: 8 - } - }, - marker: { - image: new ol.style.Icon({ - anchor: [0.5, 1], - anchorXUnits: 'fraction', - anchorYUnits: 'fraction', - opacity: 0.90, - src: base64icon - }) - } - }, - events: { - map: [], - markers: [], - layers: [] - }, - controls: { - attribution: true, - rotate: false, - zoom: true - }, - interactions: { - mouseWheelZoom: false - }, - renderer: 'canvas' - }; - }; - - var isDefined = olHelpers.isDefined; - var defaults = {}; - - // Get the _defaults dictionary, and override the properties defined by the user - return { - getDefaults: function(scope) { - if (!isDefined(scope)) { - for (var i in defaults) { - return defaults[i]; - } - } - return defaults[scope.$id]; - }, - - setDefaults: function(scope) { - var userDefaults = scope.defaults; - var scopeId = scope.$id; - var newDefaults = _getDefaults(); - - if (isDefined(userDefaults)) { - - if (isDefined(userDefaults.layers)) { - newDefaults.layers = angular.copy(userDefaults.layers); - } - - if (isDefined(userDefaults.controls)) { - newDefaults.controls = angular.copy(userDefaults.controls); - } - - if (isDefined(userDefaults.events)) { - newDefaults.events = angular.copy(userDefaults.events); - } - - if (isDefined(userDefaults.interactions)) { - newDefaults.interactions = angular.copy(userDefaults.interactions); - } - - if (isDefined(userDefaults.renderer)) { - newDefaults.renderer = userDefaults.renderer; - } - - if (isDefined(userDefaults.view)) { - newDefaults.view.maxZoom = userDefaults.view.maxZoom || newDefaults.view.maxZoom; - newDefaults.view.minZoom = userDefaults.view.minZoom || newDefaults.view.minZoom; - newDefaults.view.projection = userDefaults.view.projection || newDefaults.view.projection; - newDefaults.view.extent = userDefaults.view.extent || newDefaults.view.extent; - } - - if (isDefined(userDefaults.styles)) { - newDefaults.styles = angular.extend(newDefaults.styles, userDefaults.styles); - } - - } - - defaults[scopeId] = newDefaults; - return newDefaults; - } - }; -}); - -})); \ No newline at end of file From 36f6ac21d6aace68a6ffbadf25cbd20b34a02cd4 Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 6 Nov 2015 15:52:40 +0530 Subject: [PATCH 5/7] added check condtion undefined wrapX --- src/services/olHelpers.js | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/services/olHelpers.js b/src/services/olHelpers.js index f53faeb5..a7767a80 100644 --- a/src/services/olHelpers.js +++ b/src/services/olHelpers.js @@ -208,7 +208,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: url, attributions: createAttribution(source), tilePixelRatio: pixelRatio > 1 ? 2 : 1, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; case 'ImageWMS': @@ -221,7 +221,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, - wrapX: source.wrapX ? 0 : 1 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; @@ -235,7 +235,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, attributions: createAttribution(source), - wrapX: source.wrapX ? 0 : 1 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }; if (source.url) { @@ -268,7 +268,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ resolutions: source.tileGrid.resolutions, matrixIds: source.tileGrid.matrixIds }), - wrapX: source.wrapX ? 0 : 1 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }; if (isDefined(source.url)) { @@ -285,7 +285,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ case 'OSM': oSource = new ol.source.OSM({ attributions: createAttribution(source), - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); if (source.url) { @@ -304,7 +304,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], culture: source.culture, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }; if (source.maxZoom) { @@ -323,7 +323,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.MapQuest({ attributions: createAttribution(source), layer: source.layer, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; @@ -340,7 +340,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.XYZ({ attributions: createAttribution(source), url: _url, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; @@ -356,7 +356,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.Vector({ format: new ol.format.GeoJSON(), url: source.url, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); } else { oSource = new ol.source.Vector(); @@ -392,7 +392,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ $log(response); }); }, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); } break; @@ -407,12 +407,12 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.Vector({ format: new ol.format.TopoJSON(), url: source.url, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); } else { oSource = new ol.source.Vector(angular.extend(source.topojson, { format: new ol.format.TopoJSON(), - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX })); } break; @@ -421,7 +421,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: source.url, attributions: createAttribution(source), crossOrigin: 'anonymous', - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; @@ -437,7 +437,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ tileGrid: new ol.tilegrid.createXYZ({ maxZoom: source.maxZoom || 19 }), - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; @@ -467,7 +467,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ return url; }, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; case 'TileImage': @@ -488,7 +488,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ .replace('{y}', y.toString()); return url; }, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; case 'KML': @@ -498,7 +498,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ format: new ol.format.KML(), radius: source.radius, extractStyles: extractStyles, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; case 'Stamen': @@ -508,7 +508,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ } oSource = new ol.source.Stamen({ layer: source.layer, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; case 'ImageStatic': @@ -524,7 +524,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ projection: projection, imageExtent: projection.getExtent(), imageLoadFunction: source.imageLoadFunction, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; case 'XYZ': @@ -536,7 +536,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), minZoom: source.minZoom, maxZoom: source.maxZoom, - wrapX: (source.wrapX === true) ? 1 : 0 + wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX }); break; } From ce0df7864eedd9a5fd047676b1e22f347cf8cf8c Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 6 Nov 2015 16:14:33 +0530 Subject: [PATCH 6/7] update 'undefined' to undefined in olHelpers --- src/services/olHelpers.js | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/services/olHelpers.js b/src/services/olHelpers.js index a7767a80..f499c4a9 100644 --- a/src/services/olHelpers.js +++ b/src/services/olHelpers.js @@ -208,7 +208,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: url, attributions: createAttribution(source), tilePixelRatio: pixelRatio > 1 ? 2 : 1, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; case 'ImageWMS': @@ -221,7 +221,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; @@ -235,7 +235,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ crossOrigin: (typeof source.crossOrigin === 'undefined') ? 'anonymous' : source.crossOrigin, params: source.params, attributions: createAttribution(source), - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }; if (source.url) { @@ -268,7 +268,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ resolutions: source.tileGrid.resolutions, matrixIds: source.tileGrid.matrixIds }), - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }; if (isDefined(source.url)) { @@ -285,7 +285,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ case 'OSM': oSource = new ol.source.OSM({ attributions: createAttribution(source), - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); if (source.url) { @@ -304,7 +304,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), imagerySet: source.imagerySet ? source.imagerySet : bingImagerySets[0], culture: source.culture, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }; if (source.maxZoom) { @@ -323,7 +323,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.MapQuest({ attributions: createAttribution(source), layer: source.layer, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; @@ -340,7 +340,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.XYZ({ attributions: createAttribution(source), url: _url, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; @@ -356,7 +356,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.Vector({ format: new ol.format.GeoJSON(), url: source.url, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); } else { oSource = new ol.source.Vector(); @@ -392,7 +392,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ $log(response); }); }, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); } break; @@ -407,12 +407,12 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ oSource = new ol.source.Vector({ format: new ol.format.TopoJSON(), url: source.url, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); } else { oSource = new ol.source.Vector(angular.extend(source.topojson, { format: new ol.format.TopoJSON(), - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX })); } break; @@ -421,7 +421,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ url: source.url, attributions: createAttribution(source), crossOrigin: 'anonymous', - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; @@ -437,7 +437,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ tileGrid: new ol.tilegrid.createXYZ({ maxZoom: source.maxZoom || 19 }), - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; @@ -467,7 +467,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ return url; }, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; case 'TileImage': @@ -488,7 +488,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ .replace('{y}', y.toString()); return url; }, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; case 'KML': @@ -498,7 +498,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ format: new ol.format.KML(), radius: source.radius, extractStyles: extractStyles, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; case 'Stamen': @@ -508,7 +508,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ } oSource = new ol.source.Stamen({ layer: source.layer, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; case 'ImageStatic': @@ -524,7 +524,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ projection: projection, imageExtent: projection.getExtent(), imageLoadFunction: source.imageLoadFunction, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; case 'XYZ': @@ -536,7 +536,7 @@ angular.module('openlayers-directive').factory('olHelpers', function($q, $log, $ attributions: createAttribution(source), minZoom: source.minZoom, maxZoom: source.maxZoom, - wrapX: (source.wrapX === 'undefined') ? 1 : source.wrapX + wrapX: (source.wrapX === undefined) ? 1 : source.wrapX }); break; } From d9242b739aced9161fedf37404adf72ea83eff24 Mon Sep 17 00:00:00 2001 From: Tirumala Dilip Kumar Date: Fri, 20 Nov 2015 20:01:17 +0530 Subject: [PATCH 7/7] wrapXfeatureForPullRequestv1 --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af335b9e..c02e038a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,7 +119,7 @@ Once you have the development dependencies installed, we can use our predefined * **grunt test:unit**. Executes only the karma unitary tests. * **grunt test:e2e**. Executes only the protractor e2e tests. * **grunt coverage**. Generates a "coverage" folder with an [istanbul](https://github.com/gotwarlost/istanbul) report of wich part of the code is covered by the actual tests. -* **grunt**. The default task watches for project files changes and when a change is detected, tries to build the library file passing the jshint filter and the tests. Let's see an example: +* **grunt**. The default task watches for project files changes and when a change is detected, tries to build the library file passing the jshint filter and the tests. Let's see an example: ``` $ grunt