├── Gruntfile.js ├── examples ├── images │ ├── gizah.jpg │ ├── icon.png │ ├── eiffel.jpg │ ├── marker.png │ ├── map-marker.png │ ├── notredame.jpg │ └── versailles.jpg ├── json │ ├── LIS.geo.json │ ├── README │ ├── paths.json │ ├── PRT.geo.json │ ├── ESP.geo.json │ ├── FRA.geo.json │ ├── JPN.geo.json │ ├── ITA.geo.json │ └── features.json ├── 026-center-no-javascript-example.html ├── 010-simple-example.html ├── 056-layers-no-javascript-example.html ├── 066-markers-with-layers-no-javascript-example.html ├── 060-marker-example.html ├── 110-path-example.html ├── 020-center-example.html ├── 022-center-autodiscover-example.html ├── 053-layers-image-wms-example.html ├── 023-center-constrain-zoom-example.html ├── 052-heatmap-example.html ├── 062-markers-label-example.html ├── 044-layers-mapquest-maps-example.html ├── 070-view-rotation-example.html ├── 047-layers-topojson-example.html ├── 111-layer-tile-vector-example.html ├── 085-events-kml-example.html ├── 048-layers-static-image-example.html ├── 049-layers-stamen-example.html ├── 050-layer-geojson-change-style-example.html ├── 041-layers-zoom-tiles-changer-example.html ├── 102-controls-measure-example.html ├── 024-center-bounds-example.html ├── 101-controls-fullscreen-example.html ├── 030-custom-parameters-example.html ├── 021-center-url-hash-example.html ├── 046-layers-geojson-center-example.html ├── 112-layers-esri-basemaps-example.html ├── 043-layers-bing-maps-example.html ├── 105-controls-overviewmap-example.html ├── 084-events-add-markers-on-click-example.html ├── 061-markers-add-remove-example.html ├── 051-layer-geojson-change-style-with-function-example.html ├── 057-layers-wmts-example.html ├── 067-marker-custom-icon-example.html ├── 083-events-static-image-layer-example.html ├── 042-layers-opacity-example.html ├── 055-layers-geojon-dynamic-load-example.html ├── 065-markers-static-image-layer-example.html ├── 100-controls-example.html ├── 025-center-projections-example.html ├── 120-custom-layer-and-projection-example.html ├── 113-layers-image-wms-with-attribution-example.html ├── 104-controls-options-example.html ├── 103-controls-custom-example.html ├── 058-layers-geojson-style-function.html ├── 081-events-vector-example.html ├── 054-add-remove-multiple-layers-example.html ├── 080-events-propagation-example.html ├── 063-markers-properties-example.html ├── 064-markers-render-html-inside-labels-example.html ├── 045-layers-geojson-example.html ├── 059-layer-clustering.html ├── 040-layers-change-tiles-example.html ├── 086-events-multi-layer-vector-example.html └── 090-multiple-maps-example.html ├── grunt ├── changelog.js ├── pkg.js ├── jscs.js ├── coveralls.js ├── open.js ├── bower.js ├── ngAnnotate.js ├── uglify.js ├── bump.js ├── watch.js ├── shell.js ├── protractor.js ├── connect.js ├── aliases.yaml ├── karma.js ├── jshint.js └── concat.js ├── .npmignore ├── .gitignore ├── CHANGELOG.md ├── .jscsrc ├── .editorconfig ├── .travis.yml ├── test ├── e2e │ ├── 010-simple-example.js │ └── 020-center-example.js ├── unit │ ├── markerSpec.js │ ├── viewSpec.js │ ├── controlsSpec.js │ ├── helperSpec.js │ ├── openlayersSpec.js │ └── centerSpec.js └── protractor.conf.js ├── css ├── openlayers.css └── markers.css ├── bower.json ├── LICENSE ├── src ├── header-MIT-license.txt ├── directives │ ├── view.js │ ├── path.js │ ├── control.js │ └── openlayers.js └── services │ └── olData.js ├── doc ├── 03-defaults-attribute.md ├── 04-layers-attribute.md ├── 02-center-attribute.md └── 01-openlayers-directive.md └── package.json /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | require('load-grunt-config')(grunt); 3 | }; 4 | -------------------------------------------------------------------------------- /examples/images/gizah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/gizah.jpg -------------------------------------------------------------------------------- /examples/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/icon.png -------------------------------------------------------------------------------- /grunt/changelog.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /examples/images/eiffel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/eiffel.jpg -------------------------------------------------------------------------------- /examples/images/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/marker.png -------------------------------------------------------------------------------- /examples/images/map-marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/map-marker.png -------------------------------------------------------------------------------- /examples/images/notredame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/notredame.jpg -------------------------------------------------------------------------------- /examples/images/versailles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tombatossals/angular-openlayers-directive/HEAD/examples/images/versailles.jpg -------------------------------------------------------------------------------- /grunt/pkg.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return grunt.file.readJSON('package.json'); 5 | }; 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | doc/ 3 | grunt/ 4 | examples/ 5 | test/ 6 | *.md 7 | Gruntfile.js 8 | .travis.yml 9 | package.json 10 | bower.json 11 | node_modules 12 | bower_components -------------------------------------------------------------------------------- /examples/json/LIS.geo.json: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","id":"PRT","properties":{"name":"Lisbon"},"geometry":{"type":"Point","coordinates":[-9.394, 38.7139]}} 3 | ]} 4 | -------------------------------------------------------------------------------- /examples/json/README: -------------------------------------------------------------------------------- 1 | countries.geo.json: https://raw.github.com/johan/world.geo.json/master/countries.geo.json 2 | all.json: https://raw.github.com/lukes/ISO-3166-Countries-with-Regional-Codes/master/all/all.json 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | temp 3 | node_modules/ 4 | bower_components/ 5 | dist/ 6 | libpeerconnection.log 7 | *.swp 8 | .*.swp 9 | *.iml 10 | .idea 11 | .project 12 | selenium 13 | coverage 14 | *.log 15 | .vscode 16 | -------------------------------------------------------------------------------- /grunt/jscs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | jscs: { 6 | src: [ "src/**/*.js", "test/**/*.js" ] 7 | } 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /grunt/coveralls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | // Options 5 | return { 6 | options: { 7 | debug: true, 8 | coverage_dir: 'coverage' 9 | } 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /grunt/open.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | devserver: { 6 | path: 'http://localhost:8888' 7 | }, 8 | coverage: { 9 | path: 'http://localhost:5555' 10 | } 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /grunt/bower.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | install: { 6 | // options: { 7 | // targetDir: './bower_components', 8 | // cleanup: true 9 | // } 10 | } 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /grunt/ngAnnotate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function ngAnnotate(grunt, options) { 4 | return { 5 | options: {}, 6 | dist: { 7 | files: { 8 | 'dist/angular-openlayers-directive.js': [ 'dist/angular-openlayers-directive.pre.js' ] 9 | } 10 | } 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | angular-openlayers-directive changelog 2 | --- 3 | 4 | Hi, we've fully automated our release. Even the changelog which you can find under the [release](https://github.com/tombatossals/angular-openlayers-directive/releases) tab of our GitHub repo. 5 | 6 | You can automate your library as well. It's easy: [Release your libs like a pro](http://juristr.com/blog/2015/10/release-like-a-pro/) 7 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "google", 3 | "fileExtensions": [ ".js", "jscs" ], 4 | 5 | "requireParenthesesAroundIIFE": true, 6 | "maximumLineLength": 120, 7 | "validateIndentation": 4, 8 | 9 | "disallowKeywords": ["with"], 10 | "disallowSpacesInsideObjectBrackets": null, 11 | "disallowImplicitTypeConversion": ["string"], 12 | 13 | "safeContextKeyword": "_this" 14 | } 15 | -------------------------------------------------------------------------------- /grunt/uglify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options: { 6 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' 7 | }, 8 | dist: { 9 | files: { 10 | 'dist/<%= pkg.name %>.min.no-header.js': ['dist/angular-openlayers-directive.js'] 11 | } 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | branches: 7 | only: 8 | - master 9 | notifications: 10 | email: false 11 | node_js: 12 | - '6.1' 13 | before_install: 14 | - npm i -g npm@^2.0.0 15 | - npm install -g grunt-cli 16 | - npm install -g bower 17 | - bower install 18 | - npm install 19 | before_script: 20 | - npm prune 21 | after_success: 22 | - npm run semantic-release 23 | -------------------------------------------------------------------------------- /test/e2e/010-simple-example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('Loading 010-simple-example.html', function() { 3 | 4 | beforeEach(function() { 5 | browser.get('/examples/010-simple-example.html'); 6 | }, 30000); 7 | 8 | it('should load the Openlayers map inside the directive tag', function() { 9 | element(by.className('angular-openlayers-map')).getText().then(function(text) { 10 | expect(text).toBe('+\n−'); 11 | }); 12 | }); 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /test/e2e/020-center-example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('Loading 020-center-example.html', function() { 3 | 4 | beforeEach(function() { 5 | browser.get('/examples/020-center-example.html'); 6 | }, 30000); 7 | 8 | it('should update the zoom value in the input if clicked the zoom control', function() { 9 | element(by.className('ol-zoom-in')).click(); 10 | // Wait for zoom animation 11 | browser.sleep(300); 12 | expect(element(by.model('london.zoom')).getAttribute('value')).toBe('5'); 13 | }); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /css/openlayers.css: -------------------------------------------------------------------------------- 1 | .angular-openlayers-map:-moz-full-screen { 2 | height: 100%; 3 | } 4 | .angular-openlayers-map:-webkit-full-screen { 5 | height: 100%; 6 | } 7 | .angular-openlayers-map:full-screen { 8 | height: 100%; 9 | } 10 | 11 | .angular-openlayers-map:not(-moz-full-screen) { 12 | height: 400px; 13 | } 14 | 15 | .angular-openlayers-map:not(-webkit-full-screen) { 16 | height: 400px; 17 | } 18 | 19 | .angular-openlayers-map:not(full-screen) { 20 | height: 400px; 21 | } 22 | .ol-full-screen { 23 | position: absolute; 24 | top: 50%; 25 | } 26 | -------------------------------------------------------------------------------- /grunt/bump.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options: { 6 | files: ['package.json'], 7 | updateConfigs: [], 8 | commit: true, 9 | commitMessage: 'Release v%VERSION%', 10 | commitFiles: ['package.json'], 11 | createTag: true, 12 | tagName: 'v%VERSION%', 13 | tagMessage: 'Version %VERSION%', 14 | push: true, 15 | pushTo: 'origin', 16 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' 17 | } 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /grunt/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options : { 6 | livereload: 7777 7 | }, 8 | source: { 9 | files: ['src/**/*.js', 'test/unit/**.js', 'test/e2e/**.js', 'css/*.css'], 10 | tasks: [ 11 | 'jshint', 12 | 'jscs', 13 | 'concat:dist', 14 | 'concat:css', 15 | 'ngAnnotate', 16 | 'uglify', 17 | 'test-unit', 18 | 'concat:license' 19 | ] 20 | } 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /grunt/shell.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options: { 6 | stdout: true 7 | }, 8 | selenium: { 9 | command: 'node node_modules/protractor/bin/webdriver-manager start', 10 | options: { 11 | stdout: false, 12 | async: true 13 | } 14 | }, 15 | protractor_update: { 16 | command: 'node node_modules/protractor/bin/webdriver-manager update' 17 | }, 18 | npm_install: { 19 | command: 'npm install' 20 | } 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/json/paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "p1": { 3 | "color": "red", 4 | "weight": 8, 5 | "latlngs": [ 6 | { "lat": 51.50, "lng": -0.082 }, 7 | { "lat": 48.83, "lng": 2.37 }, 8 | { "lat": 41.91, "lng": 12.48 } 9 | ], 10 | "message": "

Route from London to Rome

Distance: 1862km

" 11 | }, 12 | "p2": { 13 | "color": "green", 14 | "weight": 8, 15 | "latlngs": [ 16 | { "lat": 48.2083537, "lng": 16.3725042 }, 17 | { "lat": 48.8534, "lng": 2.3485 } 18 | ], 19 | "label": { "message": "

Route from Vienna to Paris

Distance: 1211km

"} 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /grunt/protractor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options: { 6 | keepAlive: false, 7 | configFile: 'test/protractor.conf.js', 8 | args: { 9 | specs: [ 'test/e2e/*.js' ], 10 | } 11 | }, 12 | run: {}, 13 | saucelabs: { 14 | options: { 15 | args: { 16 | baseUrl: "http://tombatossals.github.io/angular-openlayers-directive/examples/", 17 | sauceUser: process.env.SAUCE_USERNAME, 18 | sauceKey: process.env.SAUCE_ACCESS_KEY 19 | } 20 | } 21 | } 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /examples/026-center-no-javascript-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 |

Centering map with no javascript example

16 | 17 | 18 | -------------------------------------------------------------------------------- /test/unit/markerSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W117 */ 3 | /*jshint globalstrict: true*/ 4 | /* jasmine specs for directives go here */ 5 | 6 | describe('Directive: openlayers marker', function() { 7 | var $compile = null; 8 | var scope; 9 | 10 | beforeEach(module('openlayers-directive')); 11 | beforeEach(inject(function(_$compile_, $rootScope) { 12 | $compile = _$compile_; 13 | 14 | scope = $rootScope.$new(); 15 | })); 16 | 17 | it('should not error on $scope.$destroy', function() { 18 | var element = angular.element(''); 19 | element = $compile(element)(scope); 20 | scope.$digest(); 21 | expect(function() { scope.$destroy(); }).not.toThrow(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /grunt/connect.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options: { 6 | base: '' 7 | }, 8 | webserver: { 9 | options: { 10 | port: 8888, 11 | keepalive: true 12 | } 13 | }, 14 | devserver: { 15 | options: { 16 | port: 8888 17 | } 18 | }, 19 | testserver: { 20 | options: { 21 | port: 9999 22 | } 23 | }, 24 | coverage: { 25 | options: { 26 | base: 'coverage/', 27 | directory: 'coverage/', 28 | port: 5555, 29 | keepalive: true 30 | } 31 | } 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /examples/010-simple-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 |

Simple example

16 |

Showing a simple map on your DOM requires almost no code. Look at the source code of this page.

17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/json/PRT.geo.json: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","id":"PRT","properties":{"name":"Portugal"},"geometry":{"type":"Polygon","coordinates":[[[-9.034818,41.880571],[-8.671946,42.134689],[-8.263857,42.280469],[-8.013175,41.790886],[-7.422513,41.792075],[-7.251309,41.918346],[-6.668606,41.883387],[-6.389088,41.381815],[-6.851127,41.111083],[-6.86402,40.330872],[-7.026413,40.184524],[-7.066592,39.711892],[-7.498632,39.629571],[-7.098037,39.030073],[-7.374092,38.373059],[-7.029281,38.075764],[-7.166508,37.803894],[-7.537105,37.428904],[-7.453726,37.097788],[-7.855613,36.838269],[-8.382816,36.97888],[-8.898857,36.868809],[-8.746101,37.651346],[-8.839998,38.266243],[-9.287464,38.358486],[-9.526571,38.737429],[-9.446989,39.392066],[-9.048305,39.755093],[-8.977353,40.159306],[-8.768684,40.760639],[-8.790853,41.184334],[-8.990789,41.543459],[-9.034818,41.880571]]]}} 3 | ]} 4 | -------------------------------------------------------------------------------- /css/markers.css: -------------------------------------------------------------------------------- 1 | .popup-label { 2 | background-color: #fff; 3 | border: 2px #444 solid; 4 | border-radius: 7px; 5 | -webkit-box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); 6 | -moz-box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); 7 | box-shadow: 4px 4px 5px 0px rgba(50, 50, 50, 0.75); 8 | color: #111; 9 | font: 12px/20px "Helvetica Neue", Arial, Helvetica, sans-serif; 10 | font-weight: bold; 11 | padding: 3px 6px; 12 | position: absolute; 13 | white-space: nowrap; 14 | top: -35px; 15 | left: 20px; 16 | display: none; 17 | } 18 | 19 | .popup-label img { 20 | vertical-align: middle; 21 | } 22 | 23 | .popup-label.marker:before { 24 | border-top: 6px solid transparent; 25 | border-bottom: 6px solid transparent; 26 | content: ""; 27 | border-right: 6px solid black; 28 | border-right-color: inherit; 29 | position: absolute; 30 | left: -8px; 31 | top: 5px; 32 | } 33 | -------------------------------------------------------------------------------- /examples/056-layers-no-javascript-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 |

Adding a layer with no javascript example

18 | 19 | 20 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-openlayers-directive", 3 | "description": "AngularJS directive to embed an interact with maps managed by OpenLayers library", 4 | "keywords": [ 5 | "angularjs", 6 | "javascript", 7 | "directive", 8 | "openlayers" 9 | ], 10 | "main": [ 11 | "dist/angular-openlayers-directive.min.js" 12 | ], 13 | "dependencies": { 14 | "angular": "1.4.9", 15 | "angular-sanitize": "1.4.9", 16 | "openlayers": "https://github.com/openlayers/ol3/releases/download/v4.3.4/v4.3.4-dist.zip" 17 | }, 18 | "devDependencies": { 19 | "jquery": "*", 20 | "angular-route": "1.4.9", 21 | "angular-mocks": "1.4.9", 22 | "js-polyfills": "^0.1.20" 23 | }, 24 | "ignore": [ 25 | "**/.*", 26 | "src", 27 | "doc", 28 | "grunt", 29 | "examples", 30 | "test", 31 | "*.md", 32 | "Gruntfile.js", 33 | "package.json", 34 | "bower.json", 35 | "node_modules", 36 | "bower_components" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /grunt/aliases.yaml: -------------------------------------------------------------------------------- 1 | test: 2 | - 'jshint' 3 | - 'test-unit' 4 | - 'test-e2e' 5 | 6 | test-unit: 7 | - 'karma:unit' 8 | 9 | test-e2e: 10 | - 'shell:protractor_update' 11 | - 'connect:testserver' 12 | - 'protractor:run' 13 | 14 | test-e2e-firefox: 15 | - 'shell:protractor_update' 16 | - 'connect:testserver' 17 | - 'protractor:firefox' 18 | 19 | test-coverage: 20 | - 'karma:unit_coverage' 21 | 22 | coverage: 23 | - 'karma:unit_coverage' 24 | - 'open:coverage' 25 | - 'connect:coverage' 26 | 27 | install: 28 | - 'shell:npm_install' 29 | - 'bower:install' 30 | - 'shell:protractor_update' 31 | 32 | default: 33 | - 'build' 34 | 35 | dev: 36 | - 'connect:devserver' 37 | - 'open:devserver' 38 | - 'watch:source' 39 | 40 | serve: 41 | - 'connect:webserver' 42 | 43 | build: 44 | - 'jshint' 45 | - 'jscs' 46 | - 'concat:dist' 47 | - 'concat:css' 48 | - 'ngAnnotate' 49 | - 'uglify' 50 | - 'test-unit' 51 | - 'concat:license' 52 | 53 | travis: 54 | - 'bower:install' 55 | - 'test-unit' 56 | -------------------------------------------------------------------------------- /examples/066-markers-with-layers-no-javascript-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

Adding a layer with markers with no javascript example

20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2012-2013 https://github.com/tombatossals/angular-openlayers-directive 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/json/ESP.geo.json: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","id":"ESP","properties":{"name":"Spain"},"geometry":{"type":"Polygon","coordinates":[[[-9.034818,41.880571],[-8.984433,42.592775],[-9.392884,43.026625],[-7.97819,43.748338],[-6.754492,43.567909],[-5.411886,43.57424],[-4.347843,43.403449],[-3.517532,43.455901],[-1.901351,43.422802],[-1.502771,43.034014],[0.338047,42.579546],[0.701591,42.795734],[1.826793,42.343385],[2.985999,42.473015],[3.039484,41.89212],[2.091842,41.226089],[0.810525,41.014732],[0.721331,40.678318],[0.106692,40.123934],[-0.278711,39.309978],[0.111291,38.738514],[-0.467124,38.292366],[-0.683389,37.642354],[-1.438382,37.443064],[-2.146453,36.674144],[-3.415781,36.6589],[-4.368901,36.677839],[-4.995219,36.324708],[-5.37716,35.94685],[-5.866432,36.029817],[-6.236694,36.367677],[-6.520191,36.942913],[-7.453726,37.097788],[-7.537105,37.428904],[-7.166508,37.803894],[-7.029281,38.075764],[-7.374092,38.373059],[-7.098037,39.030073],[-7.498632,39.629571],[-7.066592,39.711892],[-7.026413,40.184524],[-6.86402,40.330872],[-6.851127,41.111083],[-6.389088,41.381815],[-6.668606,41.883387],[-7.251309,41.918346],[-7.422513,41.792075],[-8.013175,41.790886],[-8.263857,42.280469],[-8.671946,42.134689],[-9.034818,41.880571]]]}} 3 | ]} 4 | -------------------------------------------------------------------------------- /examples/060-marker-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 |

Adding a marker to the map

28 |

You can add a marker to the map easily with the ol-marker sub-directive.

29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/json/FRA.geo.json: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","id":"FRA","properties":{"name":"France"},"geometry":{"type":"MultiPolygon","coordinates":[[[[9.560016,42.152492],[9.229752,41.380007],[8.775723,41.583612],[8.544213,42.256517],[8.746009,42.628122],[9.390001,43.009985],[9.560016,42.152492]]],[[[3.588184,50.378992],[4.286023,49.907497],[4.799222,49.985373],[5.674052,49.529484],[5.897759,49.442667],[6.18632,49.463803],[6.65823,49.201958],[8.099279,49.017784],[7.593676,48.333019],[7.466759,47.620582],[7.192202,47.449766],[6.736571,47.541801],[6.768714,47.287708],[6.037389,46.725779],[6.022609,46.27299],[6.5001,46.429673],[6.843593,45.991147],[6.802355,45.70858],[7.096652,45.333099],[6.749955,45.028518],[7.007562,44.254767],[7.549596,44.127901],[7.435185,43.693845],[6.529245,43.128892],[4.556963,43.399651],[3.100411,43.075201],[2.985999,42.473015],[1.826793,42.343385],[0.701591,42.795734],[0.338047,42.579546],[-1.502771,43.034014],[-1.901351,43.422802],[-1.384225,44.02261],[-1.193798,46.014918],[-2.225724,47.064363],[-2.963276,47.570327],[-4.491555,47.954954],[-4.59235,48.68416],[-3.295814,48.901692],[-1.616511,48.644421],[-1.933494,49.776342],[-0.989469,49.347376],[1.338761,50.127173],[1.639001,50.946606],[2.513573,51.148506],[2.658422,50.796848],[3.123252,50.780363],[3.588184,50.378992]]]]}} 3 | ]} 4 | -------------------------------------------------------------------------------- /examples/110-path-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |

Adding a path to the map

22 |

You can add a path to the map easily with the ol-path sub-directive.

23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/020-center-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 21 | 22 | 23 | 24 |

Center map example

25 |
26 | Latitude : 27 | Longitude : 28 | Zoom : 29 |
30 |

Center object

31 |
{{ london | json }}
32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/022-center-autodiscover-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 21 | 22 | 23 | 24 |

Center autodiscover example

25 |
26 | Latitude : 27 | Longitude : 28 | Zoom : 29 | 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/053-layers-image-wms-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |

WMS Image Layer

35 |

This map uses a WMS image layer from a geoserver.

36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/header-MIT-license.txt: -------------------------------------------------------------------------------- 1 | /**! 2 | * The MIT License 3 | * 4 | * Copyright (c) 2013 the angular-openlayers-directive Team, http://tombatossals.github.io/angular-openlayers-directive 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | * angular-google-maps 25 | * https://github.com/tombatossals/angular-openlayers-directive 26 | * 27 | * @authors https://github.com/tombatossals/angular-openlayers-directive/graphs/contributors 28 | */ 29 | -------------------------------------------------------------------------------- /grunt/karma.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (grunt, options) { 5 | return { 6 | unit: { 7 | frameworks: ['jasmine'], 8 | browsers: ['PhantomJS'], 9 | singleRun: true, 10 | options: { 11 | files: [ 12 | 'bower_components/openlayers/ol-debug.js', 13 | 'bower_components/js-polyfills/polyfill.js', 14 | 'bower_components/angular/angular.js', 15 | 'bower_components/angular-sanitize/angular-sanitize.js', 16 | 'bower_components/angular-mocks/angular-mocks.js', 17 | 'dist/angular-openlayers-directive.js', 18 | 'test/unit/*.js' 19 | ] 20 | } 21 | }, 22 | dev: { 23 | frameworks: ['jasmine'], 24 | browsers: ['Chrome', 'IE'], 25 | singleRun: false, 26 | autoWatch: true, 27 | options: { 28 | files: [ 29 | 'bower_components/openlayers/ol-debug.js', 30 | 'bower_components/js-polyfills/polyfill.js', 31 | 'bower_components/angular/angular.js', 32 | 'bower_components/angular-sanitize/angular-sanitize.js', 33 | 'bower_components/angular-mocks/angular-mocks.js', 34 | 'dist/angular-openlayers-directive.js', 35 | 'test/unit/*.js' 36 | ] 37 | } 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /examples/023-center-constrain-zoom-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 27 | 28 | 29 | 30 |

Constrain zoom map example

31 |
32 | Max Zoom : 33 | Min Zoom : 34 | Zoom : 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /doc/03-defaults-attribute.md: -------------------------------------------------------------------------------- 1 | 'Defaults' Attribute Documentation 2 | ================================== 3 | 4 | This sub-directive needs the **openlayers** main directive, so it is normaly used as an attribute of the *openlayers* tag, like this: 5 | 6 | ``` 7 | 8 | ``` 9 | 10 | It will define the default parameters from which we want to initialize our map. It's not used as a bi-directional attribute, so it will only apply the initial map parameters and nothing more. Let's see its possibilities. 11 | 12 | We can define some custom parameters that apply to the Leaflet map creation. This is the list: 13 | 14 | 15 | Let's see an example of how to use this. First of all, in our controller, we will create a new object *defaults* inside the *$scope* where we will set the parameters that we want to change. 16 | 17 | ``` 18 | angular.extend($scope, { 19 | defaults: { 20 | layer: { 21 | url: "http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png" 22 | }, 23 | interactions: { 24 | mouseWheelZoom: false 25 | }, 26 | controls: { 27 | zoom: { 28 | position: 'topright' 29 | } 30 | } 31 | } 32 | }); 33 | ``` 34 | 35 | And after that, in our HTML code we will define our openlayers directive like this: 36 | ``` 37 | 38 | ``` 39 | 40 | And that's all. A full example of using this attribute can be found [here](http://tombatossals.github.io/angular-openlayers-directive/examples/030-custom-parameters-example.html). 41 | -------------------------------------------------------------------------------- /examples/json/JPN.geo.json: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","id":"JPN","properties":{"name":"Japan"},"geometry":{"type":"MultiPolygon","coordinates":[[[[134.638428,34.149234],[134.766379,33.806335],[134.203416,33.201178],[133.79295,33.521985],[133.280268,33.28957],[133.014858,32.704567],[132.363115,32.989382],[132.371176,33.463642],[132.924373,34.060299],[133.492968,33.944621],[133.904106,34.364931],[134.638428,34.149234]]],[[[140.976388,37.142074],[140.59977,36.343983],[140.774074,35.842877],[140.253279,35.138114],[138.975528,34.6676],[137.217599,34.606286],[135.792983,33.464805],[135.120983,33.849071],[135.079435,34.596545],[133.340316,34.375938],[132.156771,33.904933],[130.986145,33.885761],[132.000036,33.149992],[131.33279,31.450355],[130.686318,31.029579],[130.20242,31.418238],[130.447676,32.319475],[129.814692,32.61031],[129.408463,33.296056],[130.353935,33.604151],[130.878451,34.232743],[131.884229,34.749714],[132.617673,35.433393],[134.608301,35.731618],[135.677538,35.527134],[136.723831,37.304984],[137.390612,36.827391],[138.857602,37.827485],[139.426405,38.215962],[140.05479,39.438807],[139.883379,40.563312],[140.305783,41.195005],[141.368973,41.37856],[141.914263,39.991616],[141.884601,39.180865],[140.959489,38.174001],[140.976388,37.142074]]],[[[143.910162,44.1741],[144.613427,43.960883],[145.320825,44.384733],[145.543137,43.262088],[144.059662,42.988358],[143.18385,41.995215],[141.611491,42.678791],[141.067286,41.584594],[139.955106,41.569556],[139.817544,42.563759],[140.312087,43.333273],[141.380549,43.388825],[141.671952,44.772125],[141.967645,45.551483],[143.14287,44.510358],[143.910162,44.1741]]]]}} 3 | ]} 4 | -------------------------------------------------------------------------------- /examples/052-heatmap-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 31 | 32 | 33 | 34 | 35 | 36 |

Layers GeoJSON example

37 |

You can load GeoJSON as new layers easily, look at the source of the layers attribute:

38 |

39 |   
40 | 
41 | 


--------------------------------------------------------------------------------
/examples/062-markers-label-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
24 |   
25 |   
26 |       
27 |           
28 |       
29 |       

Markers label example

30 |

You can show a label on the marker adding a simple property to it, and it will be shown when you mouseover the marker. The style of the markers is the same used in Leaflet label, and you can personalize it with CSS.

31 |

32 |   
33 | 
34 | 


--------------------------------------------------------------------------------
/doc/04-layers-attribute.md:
--------------------------------------------------------------------------------
 1 | 'layers' Attribute Documentation
 2 | ===================================
 3 | 
 4 | This sub-directive needs the **openlayers** main directive, so it is normaly used as an attribute of the *openlayers* tag, like this:
 5 | 
 6 | ```
 7 | 
 8 | ```
 9 | 
10 | It will map an object _layers_ of our controller scope with the corresponding object on our leaflet directive isolated scope. It's not a bidirectional relationship, only the changes made to our _tiles_ object on the controller scope will affect the map, but no viceversa.
11 | 
12 | This object defines the layers that integrate the map, so it's basically composed of three attributes: **type**, **url** and **attribution**. Let's see them in an example definition:
13 | ```
14 | $scope.layers = {
15 |     main: {
16 |         type: "tile",
17 |         source: {
18 |             type: "OSM",
19 |             url: "http://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png",
20 |             attribution: '© OpenStreetMap contributors'
21 |         }
22 |     }
23 | }
24 | ```
25 | 
26 | And that's all, we can see how the map is affected when we change the _layers_ scope object values, like these examples:
27 | 
28 | * [layers-change-tiles-example.html](http://tombatossals.github.io/angular-openlayers-directive/examples/040-layers-change-tiles-example.html).
29 | * [layers-zoom-tiles-changer-example.html](http://tombatossals.github.io/angular-openlayers-directive/examples/041-layers-zoom-tiles-changer-example.html).
30 | * [layers-opacity-example.html](http://tombatossals.github.io/angular-openlayers-directive/examples/042-layers-opacity-example.html).
31 | 


--------------------------------------------------------------------------------
/examples/044-layers-mapquest-maps-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
27 |   
28 |   
29 |     
30 |         
31 |     
32 | 
33 |     

MapQuest Layer

34 |

This map uses a MapQuest source.

35 | 36 | 41 | 42 |

Current TileLayer Url: 43 |

{{ layers | json }}
44 |

45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/070-view-rotation-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 33 | 34 | 35 | 36 |

View rotation example

37 |

You can interact with the view rotation of your map.

38 | 39 |

Degrees: {{ degrees }}

40 |

41 |   
42 | 
43 | 


--------------------------------------------------------------------------------
/test/unit/viewSpec.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | /*jshint -W117 */
 3 | /*jshint globalstrict: true*/
 4 | /* jasmine specs for directives go here */
 5 | 
 6 | describe('Directive: openlayers', function() {
 7 |     var $compile = null;
 8 |     var $rootScope = null;
 9 |     var $timeout;
10 |     var olData = null;
11 |     var olMapDefaults = null;
12 |     var scope;
13 | 
14 |     beforeEach(module('openlayers-directive'));
15 |     beforeEach(inject(function(_$compile_, _$rootScope_, _$timeout_, _olData_, _olMapDefaults_) {
16 |         $compile = _$compile_;
17 |         $rootScope = _$rootScope_;
18 |         $timeout = _$timeout_;
19 |         olData = _olData_;
20 |         olMapDefaults = _olMapDefaults_;
21 | 
22 |         scope = $rootScope.$new();
23 |     }));
24 | 
25 |     afterEach(inject(function($rootScope) {
26 |         $rootScope.$apply();
27 |     }));
28 | 
29 |     it('should have loaded openlayers library inside the directive', function() {
30 |         var element = angular.element('');
31 |         element = $compile(element)(scope);
32 |         var map;
33 |         olData.getMap().then(function(olMap) {
34 |             map = olMap;
35 |         });
36 |         scope.$digest();
37 |         expect(map).toBeDefined();
38 |     });
39 | 
40 |     it('should set default center if no center is provided', function() {
41 |         var element = angular.element('');
42 |         element = $compile(element)(scope);
43 |         var map;
44 |         olData.getMap().then(function(olMap) {
45 |             map = olMap;
46 |         });
47 |         $rootScope.$digest();
48 |         expect(map.getView().getZoom()).toEqual(1);
49 |         expect(map.getView().getCenter()[0]).toBeCloseTo(0);
50 |         expect(map.getView().getCenter()[1]).toBeCloseTo(0);
51 |     });
52 | 
53 | });
54 | 


--------------------------------------------------------------------------------
/examples/047-layers-topojson-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
37 |   
38 |   
39 |      
40 |          
41 |      
42 |      

Layers TopoJSON example

43 |

You can load TopoJSON as new layers easily, look at the source of the layers attribute:

44 |

45 |   
46 | 
47 | 


--------------------------------------------------------------------------------
/examples/111-layer-tile-vector-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
37 |   
38 |   
39 |      
40 |          
41 |      
42 |      

Layers TileVector events example

43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /grunt/jshint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt, options) { 4 | return { 5 | options: { 6 | node: true, 7 | browser: true, 8 | esnext: true, 9 | bitwise: true, 10 | curly: true, 11 | eqeqeq: true, 12 | immed: true, 13 | indent: 4, 14 | latedef: true, 15 | newcap: true, 16 | noarg: true, 17 | regexp: true, 18 | undef: true, 19 | unused: true, 20 | trailing: true, 21 | smarttabs: true, 22 | globals: { 23 | angular: false, 24 | ol: false, 25 | lvector: false, 26 | cartodb: false, 27 | // Jasmine 28 | jasmine : false, 29 | isCommonJS : false, 30 | exports : false, 31 | spyOn : false, 32 | it : false, 33 | xit : false, 34 | expect : false, 35 | runs : false, 36 | waits : false, 37 | waitsFor : false, 38 | beforeEach : false, 39 | afterEach : false, 40 | describe : false, 41 | xdescribe : false, 42 | 43 | // Protractor 44 | protractor: false, 45 | browser: false, 46 | by: false, 47 | element: false 48 | } 49 | }, 50 | source: { 51 | src: ['src/directives/*.js', 'src/services/*.js'] 52 | }, 53 | tests: { 54 | src: ['test/unit/*.js', 'test/e2e/*.js'], 55 | }, 56 | grunt: { 57 | src: ['Gruntfile.js'] 58 | } 59 | }; 60 | }; 61 | -------------------------------------------------------------------------------- /examples/085-events-kml-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/048-layers-static-image-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 34 | 35 | 36 | 37 | 38 | 39 |

Static Image Layer example

40 |

You can load an static image (no tiles) easily, look at the source of the layer object:

41 |

42 |      

43 |   
44 | 
45 | 


--------------------------------------------------------------------------------
/examples/049-layers-stamen-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
27 |   
28 |   
29 |     
30 |         
31 |     
32 | 
33 |     

Using Stamen Maps Layer

34 |

This map uses a Stamen layer. Click on the buttons to see the three types of layers:

35 | 36 | 41 | 42 |

Current TileLayer Url: 43 |

{{ stamen | json }}
44 |

45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/050-layer-geojson-change-style-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 37 | 38 | 39 | 40 | 41 | 42 |

Layers GeoJSON change style

43 |

Stroke color: 44 |

Stroke width: 45 |

Fill color: 46 | 47 | 48 | -------------------------------------------------------------------------------- /examples/041-layers-zoom-tiles-changer-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 32 | 33 | 34 | 35 | 36 | 37 |

Tiles zoom changer example

38 |

This is a map with dynamic tile change depending on zoom level

39 |

Current TileLayer Url:

{{ OSMLayer.source.url | json }}

40 |

Current Zoom Level: {{ london.zoom }}

41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/102-controls-measure-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 38 | 39 | 40 | 41 | 42 | 43 |

Fullscreen control example

44 |

Example of the fullscreen control:

45 |

46 |   
47 | 
48 | 


--------------------------------------------------------------------------------
/examples/json/ITA.geo.json:
--------------------------------------------------------------------------------
1 | {"type":"FeatureCollection","features":[
2 | {"type":"Feature","id":"ITA","properties":{"name":"Italy"},"geometry":{"type":"MultiPolygon","coordinates":[[[[15.520376,38.231155],[15.160243,37.444046],[15.309898,37.134219],[15.099988,36.619987],[14.335229,36.996631],[13.826733,37.104531],[12.431004,37.61295],[12.570944,38.126381],[13.741156,38.034966],[14.761249,38.143874],[15.520376,38.231155]]],[[[9.210012,41.209991],[9.809975,40.500009],[9.669519,39.177376],[9.214818,39.240473],[8.806936,38.906618],[8.428302,39.171847],[8.388253,40.378311],[8.159998,40.950007],[8.709991,40.899984],[9.210012,41.209991]]],[[[12.376485,46.767559],[13.806475,46.509306],[13.69811,46.016778],[13.93763,45.591016],[13.141606,45.736692],[12.328581,45.381778],[12.383875,44.885374],[12.261453,44.600482],[12.589237,44.091366],[13.526906,43.587727],[14.029821,42.761008],[15.14257,41.95514],[15.926191,41.961315],[16.169897,41.740295],[15.889346,41.541082],[16.785002,41.179606],[17.519169,40.877143],[18.376687,40.355625],[18.480247,40.168866],[18.293385,39.810774],[17.73838,40.277671],[16.869596,40.442235],[16.448743,39.795401],[17.17149,39.4247],[17.052841,38.902871],[16.635088,38.843572],[16.100961,37.985899],[15.684087,37.908849],[15.687963,38.214593],[15.891981,38.750942],[16.109332,38.964547],[15.718814,39.544072],[15.413613,40.048357],[14.998496,40.172949],[14.703268,40.60455],[14.060672,40.786348],[13.627985,41.188287],[12.888082,41.25309],[12.106683,41.704535],[11.191906,42.355425],[10.511948,42.931463],[10.200029,43.920007],[9.702488,44.036279],[8.888946,44.366336],[8.428561,44.231228],[7.850767,43.767148],[7.435185,43.693845],[7.549596,44.127901],[7.007562,44.254767],[6.749955,45.028518],[7.096652,45.333099],[6.802355,45.70858],[6.843593,45.991147],[7.273851,45.776948],[7.755992,45.82449],[8.31663,46.163642],[8.489952,46.005151],[8.966306,46.036932],[9.182882,46.440215],[9.922837,46.314899],[10.363378,46.483571],[10.442701,46.893546],[11.048556,46.751359],[11.164828,46.941579],[12.153088,47.115393],[12.376485,46.767559]]]]}}
3 | ]}
4 | 


--------------------------------------------------------------------------------
/examples/024-center-bounds-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
30 |   
31 |   
32 |     
33 |     

Map bounds example

34 |

We can define a bounds property inside our center object and it will be filled with the maximum extent of the map.

35 |

Center

36 | Latitude : 37 | Longitude : 38 | Zoom : 39 |

Center object

40 |
41 |         {{ cairo | json }}
42 |     
43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/101-controls-fullscreen-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 38 | 39 | 40 | 41 | 42 | 43 |

Fullscreen control example

44 |

Example of the fullscreen control. Controls object:

45 |

46 |   
47 | 
48 | 


--------------------------------------------------------------------------------
/examples/030-custom-parameters-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
41 |   
42 |   
43 |     
44 |     

Custom parameters example

45 |

These are the custom properties applied in this map:

46 |

47 |   
48 | 
49 | 


--------------------------------------------------------------------------------
/src/directives/view.js:
--------------------------------------------------------------------------------
 1 | angular.module('openlayers-directive').directive('olView', function($log, $q, olData, olMapDefaults, olHelpers) {
 2 |     return {
 3 |         restrict: 'A',
 4 |         scope: false,
 5 |         replace: false,
 6 |         require: 'openlayers',
 7 |         link: function(scope, element, attrs, controller) {
 8 |             var olScope = controller.getOpenlayersScope();
 9 |             var isNumber = olHelpers.isNumber;
10 |             var safeApply = olHelpers.safeApply;
11 |             var createView = olHelpers.createView;
12 | 
13 |             olScope.getMap().then(function(map) {
14 |                 var defaults = olMapDefaults.getDefaults(olScope);
15 |                 var view = olScope.view;
16 | 
17 |                 if (!view.projection) {
18 |                     view.projection = defaults.view.projection;
19 |                 }
20 | 
21 |                 if (!view.maxZoom) {
22 |                     view.maxZoom = defaults.view.maxZoom;
23 |                 }
24 | 
25 |                 if (!view.minZoom) {
26 |                     view.minZoom = defaults.view.minZoom;
27 |                 }
28 | 
29 |                 if (!view.rotation) {
30 |                     view.rotation = defaults.view.rotation;
31 |                 }
32 | 
33 |                 var mapView = createView(view);
34 |                 map.setView(mapView);
35 | 
36 |                 olScope.$watchCollection('view', function(view) {
37 |                     if (isNumber(view.rotation)) {
38 |                         mapView.setRotation(view.rotation);
39 |                     }
40 |                 });
41 | 
42 |                 var rotationEventKey = mapView.on('change:rotation', function() {
43 |                     safeApply(olScope, function(scope) {
44 |                         scope.view.rotation = map.getView().getRotation();
45 |                     });
46 |                 });
47 | 
48 |                 olScope.$on('$destroy', function() {
49 |                     ol.Observable.unByKey(rotationEventKey);
50 |                 });
51 | 
52 |             });
53 |         }
54 |     };
55 | });
56 | 


--------------------------------------------------------------------------------
/examples/021-center-url-hash-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
26 |   
27 |   
28 |     
29 |     

Center map with URL synchronization example

30 |

This demo syncs the map center position with the URL, and viceversa, using the center-url-params property.

31 |
32 | Latitude : 33 | Longitude : 34 | Zoom : 35 |
36 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/046-layers-geojson-center-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 41 | 42 | 43 | 44 | 45 | 46 |

Layers center to GeoJSON example

47 |

Click the button to center the map to the extent of the Japan GeoJSON Vector Layer.

48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/112-layers-esri-basemaps-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |

ESRI BaseMaps

34 |

This map uses ESRI BaseMaps.

35 | 36 | 41 | 42 |

43 | Current TileLayer Url: 44 |

{{ esribasemaps.source.layer | json }}
45 |

46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/043-layers-bing-maps-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |

Using a Bing Maps Layer

36 |

This map uses a Bing source. You must request an API key to use these maps here.

37 | 38 | 43 | 44 |

Current TileLayer Url: 45 |

{{ bing | json }}
46 |

47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/105-controls-overviewmap-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 40 | 41 | 42 | 43 | 44 | 45 |

Overview control example

46 |

Example of the overviewmap control. Controls object:

47 |

48 |   
49 | 
50 | 


--------------------------------------------------------------------------------
/examples/084-events-add-markers-on-click-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
47 |   
48 |   
49 |     
50 |         
51 |     
52 |   
53 | 
54 | 


--------------------------------------------------------------------------------
/examples/061-markers-add-remove-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
50 |   
51 |   
52 |       
53 |           
54 |       
55 |       

Markers simple example

56 | 57 |

You can add/remove markers to the map easily. Look at the markers object:

58 |

59 |   
60 | 
61 | 


--------------------------------------------------------------------------------
/grunt/concat.js:
--------------------------------------------------------------------------------
 1 | 'use strict';
 2 | 
 3 | var banner = '(function (root, factory) {\n' +
 4 |              '    if (typeof require === \'function\' && typeof exports === \'object\') {\n' +
 5 |              '        // CommonJS\n' +
 6 |              '        var ol = require(\'openlayers\');\n' +
 7 |              '        exports.angularOpenlayersDirective = factory(ol);\n' +
 8 |              '    } else if (typeof define === \'function\' && define.amd) {\n' +
 9 |              '        // AMD.\n' +
10 |              '        define([\'ol\'], function (ol) {\n' +
11 |              '            return root.angularOpenlayersDirective = factory(ol);\n' +
12 |              '        });\n' +
13 |              '    } else {\n' +
14 |              '        // Browser globals\n' +
15 |              '        root.angularOpenlayersDirective = factory(root.ol);\n' +
16 |              '    }\n' +
17 |              '}(this, function (ol) {\n';
18 | 
19 | module.exports = function (grunt, options) {
20 |     return {
21 |         dist: {
22 |             options: {
23 |                 banner: banner,
24 |                 footer: '\n}));'
25 |             },
26 |             src: [
27 |                 'src/directives/openlayers.js',
28 |                 'src/directives/center.js',
29 |                 'src/directives/layer.js',
30 |                 'src/directives/events.js',
31 |                 'src/directives/path.js',
32 |                 'src/directives/view.js',
33 |                 'src/directives/control.js',
34 |                 'src/directives/marker.js',
35 |                 'src/services/olData.js',
36 |                 'src/services/olHelpers.js',
37 |                 'src/services/olMapDefaults.js'
38 |             ],
39 |             dest: 'dist/angular-openlayers-directive.pre.js',
40 |         },
41 |         css: {
42 |             src: [
43 |                 'css/markers.css',
44 |                 'css/openlayers.css'
45 |             ],
46 |             dest: 'dist/angular-openlayers-directive.css'
47 |         },
48 |         license: {
49 |             src: [
50 |                 'src/header-MIT-license.txt',
51 |                 'dist/angular-openlayers-directive.min.no-header.js'
52 |             ],
53 |             dest: 'dist/angular-openlayers-directive.min.js',
54 |         },
55 |     };
56 | };
57 | 


--------------------------------------------------------------------------------
/examples/051-layer-geojson-change-style-with-function-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
54 |   
55 |   
56 |      
57 |          
58 |      
59 |      

Layers GeoJSON change style with a function

60 |

Move the map to change the vector layer style.

61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /examples/057-layers-wmts-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |

WMTS Layer

51 |

This map uses a WMTS layer from a geoserver.

52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /examples/067-marker-custom-icon-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/083-events-static-image-layer-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 49 | 50 | 51 | 52 | 53 | 54 |

Mouse position

55 |

56 |      

Mouse click position

57 |

58 |   
59 | 
60 | 


--------------------------------------------------------------------------------
/src/services/olData.js:
--------------------------------------------------------------------------------
 1 | angular.module('openlayers-directive').service('olData', function($log, $q) {
 2 | 
 3 |     var maps = {};
 4 | 
 5 |     var setResolvedDefer = function(d, mapId) {
 6 |         var id = obtainEffectiveMapId(d, mapId);
 7 |         d[id].resolvedDefer = true;
 8 |     };
 9 | 
10 |     var getUnresolvedDefer = function(d, mapId) {
11 |         var id = obtainEffectiveMapId(d, mapId);
12 |         var defer;
13 | 
14 |         if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) {
15 |             defer = $q.defer();
16 |             d[id] = {
17 |                 defer: defer,
18 |                 resolvedDefer: false
19 |             };
20 |         } else {
21 |             defer = d[id].defer;
22 |         }
23 |         return defer;
24 |     };
25 | 
26 |     var getDefer = function(d, mapId) {
27 |         var id = obtainEffectiveMapId(d, mapId);
28 |         var defer;
29 | 
30 |         if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) {
31 |             defer = getUnresolvedDefer(d, mapId);
32 |         } else {
33 |             defer = d[id].defer;
34 |         }
35 |         return defer;
36 |     };
37 | 
38 |     this.setMap = function(olMap, scopeId) {
39 |         var defer = getUnresolvedDefer(maps, scopeId);
40 |         defer.resolve(olMap);
41 |         setResolvedDefer(maps, scopeId);
42 |     };
43 | 
44 |     this.getMap = function(scopeId) {
45 |         var defer = getDefer(maps, scopeId);
46 |         return defer.promise;
47 |     };
48 | 
49 |     function obtainEffectiveMapId(d, mapId) {
50 |         var id;
51 |         var i;
52 |         if (!angular.isDefined(mapId)) {
53 |             if (Object.keys(d).length === 1) {
54 |                 for (i in d) {
55 |                     if (d.hasOwnProperty(i)) {
56 |                         id = i;
57 |                     }
58 |                 }
59 |             } else if (Object.keys(d).length === 0) {
60 |                 id = 'main';
61 |             } else {
62 |                 $log.error('[AngularJS - Openlayers] - You have more than 1 map on the DOM, ' +
63 |                            'you must provide the map ID to the olData.getXXX call');
64 |             }
65 |         } else {
66 |             id = mapId;
67 |         }
68 |         return id;
69 |     }
70 | 
71 |     this.resetMap = function(scopeId) {
72 |         if (angular.isDefined(maps[scopeId])) {
73 |             delete maps[scopeId];
74 |         }
75 |     };
76 | 
77 | });
78 | 


--------------------------------------------------------------------------------
/examples/042-layers-opacity-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
36 |   
37 |   
38 |   
39 |
40 | 41 | 42 | 43 | 44 | 45 |

Layers opacity example

46 |

This is a map that can change the tiles of the main layer by demand

47 | 48 |
49 |
50 | OSM 51 | 52 |
53 |
54 | Mapbox 55 | 56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/directives/path.js: -------------------------------------------------------------------------------- 1 | angular.module('openlayers-directive').directive('olPath', function($log, $q, olMapDefaults, olHelpers) { 2 | 3 | return { 4 | restrict: 'E', 5 | scope: { 6 | properties: '=olGeomProperties', 7 | style: '=olStyle' 8 | }, 9 | require: '^openlayers', 10 | replace: true, 11 | template: '', 12 | 13 | link: function(scope, element, attrs, controller) { 14 | var isDefined = olHelpers.isDefined; 15 | var createFeature = olHelpers.createFeature; 16 | var createOverlay = olHelpers.createOverlay; 17 | var createVectorLayer = olHelpers.createVectorLayer; 18 | var insertLayer = olHelpers.insertLayer; 19 | var removeLayer = olHelpers.removeLayer; 20 | var olScope = controller.getOpenlayersScope(); 21 | 22 | olScope.getMap().then(function(map) { 23 | var mapDefaults = olMapDefaults.getDefaults(olScope); 24 | var viewProjection = mapDefaults.view.projection; 25 | 26 | var layer = createVectorLayer(); 27 | var layerCollection = map.getLayers(); 28 | 29 | insertLayer(layerCollection, layerCollection.getLength(), layer); 30 | 31 | scope.$on('$destroy', function() { 32 | removeLayer(layerCollection, layer.index); 33 | }); 34 | 35 | if (isDefined(attrs.coords)) { 36 | var proj = attrs.proj || 'EPSG:4326'; 37 | var coords = JSON.parse(attrs.coords); 38 | var data = { 39 | type: 'Polygon', 40 | coords: coords, 41 | projection: proj, 42 | style: scope.style ? scope.style : mapDefaults.styles.path 43 | }; 44 | var feature = createFeature(data, viewProjection); 45 | layer.getSource().addFeature(feature); 46 | 47 | if (attrs.message) { 48 | scope.message = attrs.message; 49 | var extent = feature.getGeometry().getExtent(); 50 | var label = createOverlay(element, extent); 51 | map.addOverlay(label); 52 | } 53 | return; 54 | } 55 | }); 56 | } 57 | }; 58 | }); 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-openlayers-directive", 3 | "author": "David Rubert ", 4 | "contributors": ["Juri Strumpflohner "], 5 | "description": 6 | "angular-openlayers-directive - An AngularJS directive to easily interact with Openlayers maps", 7 | "homepage": "http://tombatossals.github.io/angular-openlayers-directive/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/tombatossals/angular-openlayers-directive" 11 | }, 12 | "keywords": ["angularjs", "openlayers", "cli"], 13 | "license": "MIT", 14 | "dependencies": { 15 | "angular": "~1.4.8", 16 | "angular-sanitize": "~1.4.8", 17 | "openlayers": "4.3.4" 18 | }, 19 | "devDependencies": { 20 | "grunt": "~0.4.5", 21 | "grunt-bower-task": "~0.4.0", 22 | "grunt-bump": "^0.3.0", 23 | "grunt-contrib-concat": "~0.5.0", 24 | "grunt-contrib-connect": "^0.11.2", 25 | "grunt-contrib-jshint": "^0.11.0", 26 | "grunt-contrib-uglify": "^0.9.1", 27 | "grunt-contrib-watch": "~0.6.1", 28 | "grunt-conventional-changelog": "^4.1.0", 29 | "grunt-jscs": "^2.1.0", 30 | "grunt-karma": "^0.12.0", 31 | "grunt-karma-coveralls": "~2.5.3", 32 | "grunt-ng-annotate": "^1.0.1", 33 | "grunt-open": "~0.2.3", 34 | "grunt-protractor-runner": "^2.0.0", 35 | "grunt-shell": "~1.1.1", 36 | "grunt-shell-spawn": "~0.3.0", 37 | "jasmine-core": "^2.2.0", 38 | "karma": "^0.13.9", 39 | "karma-chrome-launcher": "^0.2.0", 40 | "karma-coffee-preprocessor": "^0.3.0", 41 | "karma-coverage": "^0.5.0", 42 | "karma-firefox-launcher": "~0.1.4", 43 | "karma-html2js-preprocessor": "~0.1.0", 44 | "karma-jasmine": "~0.3.3", 45 | "karma-phantomjs-launcher": "^0.2.1", 46 | "karma-requirejs": "~0.2.2", 47 | "karma-script-launcher": "~0.1.0", 48 | "load-grunt-config": "^0.17.1", 49 | "matchdep": "~0.3.0", 50 | "phantomjs": "^2.1.0", 51 | "protractor": "~2.5.0", 52 | "publish-latest": "^1.1.2", 53 | "semantic-release": "^4.3.5" 54 | }, 55 | "scripts": { 56 | "test": "grunt build && grunt karma:unit", 57 | "test.watch": "grunt build && grunt karma:dev", 58 | "build": "grunt build", 59 | "prepublish": "npm run build", 60 | "postpublish": "publish-latest", 61 | "semantic-release": 62 | "semantic-release pre && npm publish && semantic-release post" 63 | }, 64 | "main": "dist/angular-openlayers-directive" 65 | } 66 | -------------------------------------------------------------------------------- /examples/055-layers-geojon-dynamic-load-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 60 | 61 | 62 | 63 | 64 | 65 |

Layers inline GeoJSON example

66 | 67 |

You can load inline GeoJSON as new layer easily, look at the source of the layers attribute:

68 |

69 |   
70 | 
71 | 


--------------------------------------------------------------------------------
/src/directives/control.js:
--------------------------------------------------------------------------------
 1 | angular.module('openlayers-directive')
 2 | .directive('olControl', function($log, $q, olData, olMapDefaults, olHelpers) {
 3 |     return {
 4 |         restrict: 'E',
 5 |         scope: {
 6 |             properties: '=olControlProperties'
 7 |         },
 8 |         replace: false,
 9 |         require: '^openlayers',
10 |         link: function(scope, element, attrs, controller) {
11 |             var isDefined   = olHelpers.isDefined;
12 |             var olScope   = controller.getOpenlayersScope();
13 |             var olControl;
14 |             var olControlOps;
15 |             var getControlClasses = olHelpers.getControlClasses;
16 |             var controlClasses = getControlClasses();
17 | 
18 |             olScope.getMap().then(function(map) {
19 | 
20 |                 scope.$on('$destroy', function() {
21 |                     map.removeControl(olControl);
22 |                 });
23 | 
24 |                 scope.$watch('properties', function(properties) {
25 |                     if (!isDefined(properties)) {
26 |                         return;
27 |                     }
28 | 
29 |                     initCtrls(properties);
30 |                 });
31 | 
32 |                 function initCtrls(properties) {
33 |                     if (properties && properties.control) {
34 |                         // the control instance is already defined,
35 |                         // so simply use it and go ahead
36 | 
37 |                         // is there already a control, so destroy and recreate it?
38 |                         if (olControl) {
39 |                             map.removeControl(olControl);
40 |                         }
41 | 
42 |                         olControl = properties.control;
43 |                         map.addControl(olControl);
44 |                     } else {
45 | 
46 |                         // the name is the key to instantiate an ol3 control
47 |                         if (attrs.name) {
48 |                             if (isDefined(properties)) {
49 |                                 olControlOps = properties;
50 |                             }
51 | 
52 |                             // is there already a control, so destroy and recreate it?
53 |                             if (olControl) {
54 |                                 map.removeControl(olControl);
55 |                             }
56 | 
57 |                             olControl = new controlClasses[attrs.name](olControlOps);
58 |                             map.addControl(olControl);
59 |                         }
60 |                     }
61 |                 }
62 | 
63 |                 initCtrls(scope.properties);
64 | 
65 |             });
66 | 
67 |         }
68 |     };
69 | });
70 | 


--------------------------------------------------------------------------------
/examples/065-markers-static-image-layer-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
53 |   
54 |   
55 |      
56 |          
57 |          
58 |          
59 |      
60 |      

Static Image Layer example

61 |

You can load an static image (no tiles) easily, look at the source of the layers attribute:

62 |

63 |      

64 |   
65 | 
66 | 


--------------------------------------------------------------------------------
/examples/100-controls-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
16 |     
54 |   
55 |   
56 |      
57 |          
58 |      
59 |      

Controls example

60 | 61 |

Degrees: {{ degrees }}

62 |

You can add/remove controls to the map via the controls attribute:

63 |

64 |   
65 | 
66 | 


--------------------------------------------------------------------------------
/examples/025-center-projections-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
52 |   
53 |   
54 |     
55 |     

Center map example

56 |
57 | Latitude : 58 | Longitude : 59 | Zoom : 60 |
61 |

Center object

62 |
{{ center | json }}
63 |

Sexagesimal system conversion: {{ sexagesimalCenter }}

64 |

Center object transformed to view projection EPSG:3857

65 |
{{ center | transform: 'EPSG:3857' | json }}
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/120-custom-layer-and-projection-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 58 | 59 | 60 | 66 | 67 | 68 | 69 |

Custom layer source with custom projection and extent

70 | 71 |

An example that demonstrates how to adequately setup a custom layer source with a custom projection and extent

72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /examples/113-layers-image-wms-with-attribution-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |

WMS Image Layer with Attribution

60 | 61 |

This map uses a WMS image layer from a geoserver with custom annotation defined in the layer object.

62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /examples/104-controls-options-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 57 | 58 | 59 | 60 | 61 | 62 |

Controls example

63 | 64 |

Degrees: {{ degrees }}

65 |

You can add/remove controls to the map via the controls attribute:

66 |

67 |   
68 | 
69 | 


--------------------------------------------------------------------------------
/examples/103-controls-custom-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
18 |     
69 |   
70 |   
71 |      
72 |          
73 |      
74 |      

Example of a custom control

75 |

Rotates the map 90 degrees when pressed:

76 |

77 |   
78 | 
79 | 


--------------------------------------------------------------------------------
/examples/058-layers-geojson-style-function.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
62 | 
63 | 
64 | 
65 |     
66 | 
67 | 

Layers GeoJSON features with different styles example

68 |

You can define a function to set the style for features based on properties

69 |

70 | 
71 | 
72 | 


--------------------------------------------------------------------------------
/examples/081-events-vector-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
68 |   
69 |   
70 |      
71 |          
72 |      
73 |      

Layers GeoJSON events example

74 |

Mouse over this country: {{ mouseMoveCountry }}

75 |

Mouse clicked this country: {{ mouseClickCountry }}

76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /examples/054-add-remove-multiple-layers-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 60 | 61 | 62 | 63 | 64 | 65 |

Adding/removing layers example

66 | 67 |
68 |
69 | 70 | {{ layer.name }} 71 | 72 | 73 | 74 |
75 |
76 | 77 | 78 | -------------------------------------------------------------------------------- /test/unit/controlsSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W117 */ 3 | /*jshint globalstrict: true*/ 4 | /* jasmine specs for directives go here */ 5 | 6 | describe('Directive: openlayers controls', function() { 7 | var $compile = null; 8 | var $rootScope = null; 9 | var $timeout; 10 | var olData = null; 11 | var olMapDefaults = null; 12 | var scope; 13 | 14 | var containsInstance = function(controls, instance) { 15 | for (var i in controls.array_) { 16 | if (controls.array_[i] instanceof instance) { 17 | return true; 18 | } 19 | } 20 | return false; 21 | }; 22 | 23 | beforeEach(module('openlayers-directive')); 24 | beforeEach(inject(function(_$compile_, _$rootScope_, _$timeout_, _olData_, _olMapDefaults_) { 25 | $compile = _$compile_; 26 | $rootScope = _$rootScope_; 27 | $timeout = _$timeout_; 28 | olData = _olData_; 29 | olMapDefaults = _olMapDefaults_; 30 | 31 | scope = $rootScope.$new(); 32 | })); 33 | 34 | afterEach(inject(function($rootScope) { 35 | $rootScope.$apply(); 36 | })); 37 | 38 | it('should show controls by name', function() { 39 | var element = angular.element('' + 40 | '' + 41 | ''); 42 | element = $compile(element)(scope); 43 | var controls; 44 | olData.getMap().then(function(olMap) { 45 | controls = olMap.getControls(); 46 | }); 47 | scope.$digest(); 48 | 49 | expect(containsInstance(controls, ol.control.FullScreen)).toBe(true); 50 | }); 51 | 52 | it('should add controls by scope', function() { 53 | scope.fullscreen = { 54 | control: new ol.control.FullScreen() 55 | }; 56 | var element = angular.element('' + 57 | '' + 58 | ''); 59 | element = $compile(element)(scope); 60 | var controls; 61 | olData.getMap().then(function(olMap) { 62 | controls = olMap.getControls(); 63 | }); 64 | scope.$digest(); 65 | 66 | expect(containsInstance(controls, ol.control.FullScreen)).toBe(true); 67 | }); 68 | 69 | it('should remove controls from map', function() { 70 | scope.fullscreenControl = { 71 | control: new ol.control.FullScreen() 72 | }; 73 | scope.showControl = true; 74 | var element = angular.element('' + 75 | '' + 76 | ''); 77 | element = $compile(element)(scope); 78 | var controls; 79 | olData.getMap().then(function(olMap) { 80 | controls = olMap.getControls(); 81 | }); 82 | scope.$digest(); 83 | expect(containsInstance(controls, ol.control.FullScreen)).toBe(true); 84 | 85 | scope.showControl = false; 86 | scope.$digest(); 87 | expect(containsInstance(controls, ol.control.FullScreen)).toBe(false); 88 | }); 89 | 90 | }); 91 | -------------------------------------------------------------------------------- /examples/json/features.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "geometry": { 7 | "type": "Point", 8 | "coordinates": [ 9 | -80.87088507656375, 10 | 35.21515162500578 11 | ] 12 | }, 13 | "properties": { 14 | "name": "ABBOTT NEIGHBORHOOD PARK", 15 | "address": "1300 SPRUCE ST", 16 | "radius": 5, 17 | "color": "black" 18 | } 19 | }, 20 | { 21 | "type": "Feature", 22 | "geometry": { 23 | "type": "Point", 24 | "coordinates": [ 25 | -80.83775386582222, 26 | 35.24980190252168 27 | ] 28 | }, 29 | "properties": { 30 | "name": "DOUBLE OAKS CENTER", 31 | "address": "1326 WOODWARD AV", 32 | "radius": 6, 33 | "color": "red" 34 | } 35 | }, 36 | { 37 | "type": "Feature", 38 | "geometry": { 39 | "type": "Point", 40 | "coordinates": [ 41 | -80.83827000459532, 42 | 35.25674709224663 43 | ] 44 | }, 45 | "properties": { 46 | "name": "DOUBLE OAKS NEIGHBORHOOD PARK", 47 | "address": "2605 DOUBLE OAKS RD", 48 | "radius": 7, 49 | "color": "yellow" 50 | } 51 | }, 52 | { 53 | "type": "Feature", 54 | "geometry": { 55 | "type": "Point", 56 | "coordinates": [ 57 | -80.83697759172735, 58 | 35.25751734669229 59 | ] 60 | }, 61 | "properties": { 62 | "name": "DOUBLE OAKS POOL", 63 | "address": "1200 NEWLAND RD", 64 | "radius": 8, 65 | "color": "orange" 66 | } 67 | }, 68 | { 69 | "type": "Feature", 70 | "geometry": { 71 | "type": "Point", 72 | "coordinates": [ 73 | -80.81647652154736, 74 | 35.40148708491418 75 | ] 76 | }, 77 | "properties": { 78 | "name": "DAVID B. WAYMER FLYING REGIONAL PARK", 79 | "address": "15401 HOLBROOKS RD", 80 | "radius": 9, 81 | "color": "green" 82 | } 83 | }, 84 | { 85 | "type": "Feature", 86 | "geometry": { 87 | "type": "Point", 88 | "coordinates": [ 89 | -80.83556459443902, 90 | 35.39917224760999 91 | ] 92 | }, 93 | "properties": { 94 | "name": "DAVID B. WAYMER COMMUNITY PARK", 95 | "address": "302 HOLBROOKS RD", 96 | "radius": 10, 97 | "color": "blue" 98 | } 99 | } 100 | ] 101 | } -------------------------------------------------------------------------------- /examples/080-events-propagation-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 60 | 61 | 62 | 63 |

Events defaults example

64 |

In this example we propagate two events in our map, the mouse position and the mouse click.

65 |

Set desired projection: 66 | 67 | 68 |

69 |

Mouse position

70 |

71 |     

Mouse click position

72 |

73 |   
74 | 
75 | 


--------------------------------------------------------------------------------
/examples/063-markers-properties-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
44 |   
45 |   
46 |       
47 |           
48 |           
49 |       
50 |       

Markers label example

51 |

You can interact with the marker properties to modify its behaviour.

52 |

Santiago de Compostela

53 | Message: 54 | Label show 55 | Label show on marker mouse over 56 | Draggable 57 |

Lat: , Lon:

58 |

59 |       

Finisterre

60 | Message: 61 | Label show 62 | Label show on marker mouse over 63 | Draggable 64 |

Lat: , Lon:

65 |

66 | 
67 |   
68 | 
69 | 


--------------------------------------------------------------------------------
/examples/064-markers-render-html-inside-labels-example.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
21 |     
71 |   
72 |   
73 |       
74 |           
75 |           
76 |           
77 |       
78 |       

Render HTML inside a marker label

79 |

Mouse over the markers to show an image associated with each one.

80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /examples/045-layers-geojson-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 90 | 91 | 92 | 93 | 94 | 95 |

Layers GeoJSON example

96 |

You can load GeoJSON as new layers easily, look at the source of the layers attribute:

97 |

 98 |   
 99 | 
100 | 


--------------------------------------------------------------------------------
/examples/059-layer-clustering.html:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 |   
  4 |     
  5 |     
  6 |     
  7 |     
  8 |     
  9 |     
 91 |   
 92 |   
 93 |      
 94 |          
 95 |      
 96 |      

Layer clustering example

97 | 98 |

You can activate clustering on a layer easily, look at the source of the layers:

99 |
100 |      
101 | 102 | 103 | -------------------------------------------------------------------------------- /examples/040-layers-change-tiles-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 68 | 69 | 70 |
71 |
72 | 73 | 74 | 75 | 76 |

Layers change tiles example

77 |

This is a map that can change the tiles of the main layer by demand

78 | 79 |
    80 |
  • 81 | 82 |
  • 83 |
84 | 85 |

Current TileLayer Url: 86 |

{{ layers | json }}
87 |

88 | 89 |
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/unit/helperSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W117 */ 3 | /*jshint globalstrict: true*/ 4 | /* jasmine specs for directives go here */ 5 | 6 | function replacer(k, v) { 7 | if (typeof v === 'function') { 8 | v = v.toString(); 9 | } else if (window.File && v instanceof File) { 10 | v = '[File]'; 11 | } else if (window.FileList && v instanceof FileList) { 12 | v = '[FileList]'; 13 | } 14 | return v; 15 | } 16 | 17 | describe('Method: olHelpers.createStyle', function() { 18 | var _olHelpers; 19 | 20 | beforeEach(module('openlayers-directive')); 21 | beforeEach(inject(function(olHelpers) { 22 | _olHelpers = olHelpers; 23 | })); 24 | 25 | beforeEach(function() { 26 | jasmine.addMatchers({ 27 | toBeJsonEqual: function() { 28 | return { 29 | compare: function(actual, expected) { 30 | var one = JSON.stringify(actual, replacer).replace(/(\\t|\\n)/g, ''); 31 | var two = JSON.stringify(expected, replacer).replace(/(\\t|\\n)/g, ''); 32 | return one === two; 33 | } 34 | }; 35 | } 36 | }); 37 | }); 38 | 39 | it('makes marker icon style', function() { 40 | var style = { 41 | image: { 42 | icon: { 43 | anchor: [0.5, 1], 44 | anchorXUnits: 'fraction', 45 | anchorYUnits: 'fraction', 46 | opacity: 0.90, 47 | src: 'images/map-marker.png' 48 | } 49 | } 50 | }; 51 | expect(_olHelpers.createStyle(style)) 52 | .toEqual(new ol.style.Style({ 53 | fill: null, 54 | stroke: null, 55 | image: new ol.style.Icon(style.image.icon) 56 | })); 57 | }); 58 | 59 | it('makes drawing feature style', function() { 60 | var style = { 61 | fill: { 62 | color: 'rgba(0, 0, 255, 0.6)' 63 | }, 64 | stroke: { 65 | color: 'white', 66 | width: 3 67 | } 68 | }; 69 | 70 | expect(_olHelpers.createStyle(style)) 71 | .toEqual(new ol.style.Style({ 72 | fill: new ol.style.Fill({ 73 | color: style.fill.color 74 | }), 75 | stroke: new ol.style.Stroke({ 76 | color: style.stroke.color, 77 | width: style.stroke.width 78 | }), 79 | image: null 80 | })); 81 | }); 82 | 83 | xit('makes circle feature style', function() { 84 | var style = { 85 | image: { 86 | circle: { 87 | radius: 8, 88 | fill: { 89 | color: 'rgba(0, 0, 255, 0.6)' 90 | }, 91 | stroke: { 92 | color: 'white', 93 | width: 3 94 | } 95 | } 96 | } 97 | }; 98 | 99 | expect(_olHelpers.createStyle(style)) 100 | .toBeJsonEqual(new ol.style.Style({ 101 | fill: null, 102 | stroke: null, 103 | image: new ol.style.Circle({ 104 | radius: 8, 105 | fill: new ol.style.Fill({ 106 | color: 'rgba(0, 0, 255, 0.6)' 107 | }), 108 | stroke: new ol.style.Stroke({ 109 | color: 'white', 110 | width: 3 111 | }) 112 | }) 113 | })); 114 | }); 115 | 116 | }); 117 | -------------------------------------------------------------------------------- /examples/086-events-multi-layer-vector-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 84 | 85 | 86 | 87 | 88 | 89 |

Layers GeoJSON events example

90 |

Mouse over this country: {{ mouseMoveCountry }}

91 |

Mouse clicked this country: {{ mouseClickCountry }}

92 | 93 |

Mouse over this feature: {{ mouseMoveFeature }}

94 |

Mouse clicked this feature: {{ mouseClickFeature }}

95 | 96 | 97 | -------------------------------------------------------------------------------- /doc/02-center-attribute.md: -------------------------------------------------------------------------------- 1 | 'ol-center' Attribute Documentation 2 | =================================== 3 | 4 | This is an attribute of the **openlayers** main directive, and we will use it like this: 5 | 6 | ``` 7 | 8 | ``` 9 | 10 | It will map an object *center* of our controller scope with the corresponding object on our directive isolated scope. It's a bidirectional relationship, so a change in this object on the controller scope will affect the map center position, or an interaction on the map which changes the map center will update our *center* values. Let's define the center model with an example: 11 | 12 | ``` 13 | $scope.center = { 14 | lat: 51.505, 15 | lon: -0.09 16 | zoom: 4 17 | } 18 | ``` 19 | 20 | It uses the projection EPSG:3857 by default, and we can see that a center is conformed by three required attributes: *lat*, *lon* and *zoom*. When we associate that object with our *openlayers-directive* the bi-directional relation will start. 21 | 22 | Let's see a complete example of how to use this. We must create a center object in our controller, pass its name to our directive *center* attribute, an that's all. 23 | 24 | ``` 25 | angular.extend($scope, { 26 | center: { 27 | lat: 51.505, 28 | lon: -0.09 29 | zoom: 4 30 | } 31 | }); 32 | ``` 33 | 34 | And after that, in our HTML code we will define our openlayers directive like this: 35 | 36 | ``` 37 | 38 | ``` 39 | 40 | And that's all. A simple example of using this attribute can be found [here](http://tombatossals.github.io/angular-openlayers-directive/examples/020-center-example.html). 41 | 42 | Autodiscover 43 | ------------ 44 | 45 | The *lat*, *long* and *zoom* properties are mandatory to make the center work, but we have an optional property which we can use to auto-discover the position of the user browsing our page using the [W3C Geolocation API](http://dev.w3.org/geo/api/spec-source.html) using the corresponding methods defined in the [Openlayers API](http://openlayers.org/en/v3.0.0/apidoc/ol.Geolocation.html). 46 | 47 | For example, we could show the user geographic position on start, or when he press a button. This property is defined like this: 48 | 49 | ``` 50 | angular.extend($scope, { 51 | center: { 52 | lat: 0, 53 | lon: 0, 54 | zoom: 1, 55 | autodiscover: true 56 | } 57 | }); 58 | ``` 59 | 60 | Whenever we set the *autodiscover* attribute to our center object, the map will be positioned to the geographic location of the device (if the user allows it). 61 | 62 | We can see an example of how to use this [here](http://tombatossals.github.io/angular-openlayers-directive/examples/022-center-autodiscover-example.html). 63 | 64 | Center position coded on a hash URL param 65 | ----------------------------------------- 66 | 67 | We can use a special feature of the center attribute which will allow us to synchronize the center position of the map with the URL of the browser, adding to it a special GET parameter where the center is coded. This way, we can persist the map position on the browser URL. 68 | 69 | ``` 70 | center: { 71 | lat: 51.505, 72 | lon: -0.09 73 | zoom: 4, 74 | urlHash: true 75 | } 76 | ``` 77 | 78 | Adding that attribute to our center object will synchronize the map center with a GET parameter on the URL of this form `?c=lat:lon:zoom`. Furthermore, whenever the map center is changed a new event `centerUrlHashChanged` will be emitted to the parent scope so you can update your `$location.search` with the new info (if you want). 79 | 80 | You can take a look of this feature on this [demo](http://tombatossals.github.io/angular-openlayers-directive/examples/021-url-hash-center-example.html). 81 | 82 | Bounds 83 | ------ 84 | 85 | Maybe we are interested in knowing about the bounds of the map rendered on screen to the user. 86 | 87 | ``` 88 | center { 89 | extent: [ 0, 0, 51.505, -0.09 ] 90 | } 91 | ``` 92 | -------------------------------------------------------------------------------- /doc/01-openlayers-directive.md: -------------------------------------------------------------------------------- 1 | Openlayers directive Documentation 2 | ================================== 3 | 4 | This directive acts as an intermediary between the AngularJS framework and the Openlayers (version 3) map management library. It's composed of a main directive **<openlayers>** and attributes (coded as sub-directives) of the main directive. For example, we could add to our HTML code: 5 | 6 | ``` 7 | 8 | ``` 9 | 10 | Here we have the main **openlayers** directive, with the attribute **center** and two more attributes **width** and **height**. 11 | 12 | Before detailing how to use the directive and its attributes, let's talk about initializing our web page to be able to work with the directive. We must load the required JS libraries and CSS in our HTML: 13 | 14 | ``` 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | After loading the required libraries, we only need to define our AngularJS application (depending on 'openlayers-directive') and an application controller to be able to load our map. Showing the map on screen will require that we set the width and height of our map, via CSS or as attributes of the *openlayers* tag. Let' see how to do it: 25 | 26 | - We can add *height* and *width* attributes to our *openlayers* directive inline. Example: 27 | 28 | ``` 29 | 30 | ``` 31 | 32 | - We can set the *width* and *height* of the common CSS class '*angular-openlayers-map*' applied to all maps. Beware this will be applied to all maps rendered on your application. Example: 33 | 34 | ``` 35 | 41 | ``` 42 | 43 | - We can set and *id* to our map, and set the CSS properties to this specifid id. Example: 44 | 45 | ``` 46 | 52 | ... 53 | 54 | ``` 55 | 56 | Great, let's see now the complete HTML and inline javascript code needed to load our first map: 57 | 58 | ``` 59 | 60 | 61 | 62 | 63 | 64 | 65 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ``` 75 | 76 | You can see this example in action on the [simple-example demo file](http://tombatossals.github.io/angular-openlayers-directive/examples/01-simple-example.html). 77 | 78 | Take a look at the [AngularJS controller documentation](http://docs.angularjs.org/guide/controller) if you want to learn more about Angular controller definition, or to the [AngularJS ngApp](http://docs.angularjs.org/api/ng.directive:ngApp) to know how to bootstrap an Angular application. 79 | 80 | Attributes Documentation 81 | ======================== 82 | 83 | We have much more possibilities than showing a simple map, but this will need that we take a closer look at the attributes, listed below: 84 | 85 | - [ol-defaults attribute](https://github.com/tombatossals/angular-openlayers-directive/blob/master/doc/03-defaults-attribute.md) 86 | - [ol-center attribute](https://github.com/tombatossals/angular-openlayers-directive/blob/master/doc/02-center-attribute.md) 87 | - [ol-layers attribute](https://github.com/tombatossals/angular-openlayers-directive/blob/master/doc/04-layers-attribute.md) 88 | -------------------------------------------------------------------------------- /examples/090-multiple-maps-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 96 | 97 | 98 |
99 | 100 | 101 | 102 |
103 |
104 | 105 | 106 | 107 |
108 |

Two maps sharing center example

109 |

Drag the center in any of the maps

110 | 111 | 112 | -------------------------------------------------------------------------------- /test/unit/openlayersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W117 */ 3 | /*jshint globalstrict: true*/ 4 | /* jasmine specs for directives go here */ 5 | 6 | describe('Directive: openlayers', function() { 7 | var $compile = null; 8 | var $rootScope = null; 9 | var $timeout; 10 | var olData = null; 11 | var olHelpers; 12 | var olMapDefaults = null; 13 | var scope; 14 | 15 | beforeEach(module('openlayers-directive')); 16 | beforeEach(inject(function(_$compile_, _$rootScope_, _$timeout_, _olData_, _olHelpers_, _olMapDefaults_) { 17 | $compile = _$compile_; 18 | $rootScope = _$rootScope_; 19 | $timeout = _$timeout_; 20 | olData = _olData_; 21 | olHelpers = _olHelpers_; 22 | olMapDefaults = _olMapDefaults_; 23 | 24 | scope = $rootScope.$new(); 25 | })); 26 | 27 | afterEach(inject(function($rootScope) { 28 | $rootScope.$apply(); 29 | })); 30 | 31 | it('should have loaded openlayers library inside the directive', function() { 32 | var element = angular.element(''); 33 | element = $compile(element)(scope); 34 | var map; 35 | olData.getMap().then(function(olMap) { 36 | map = olMap; 37 | }); 38 | scope.$digest(); 39 | expect(map).toBeDefined(); 40 | }); 41 | 42 | it('should set default center if not center is provided', function() { 43 | var element = angular.element(''); 44 | element = $compile(element)(scope); 45 | var map; 46 | var defaults = olMapDefaults.getDefaults(); 47 | 48 | olData.getMap().then(function(olMap) { 49 | map = olMap; 50 | }); 51 | 52 | scope.$digest(); 53 | expect(map.getView().getZoom()).toEqual(defaults.center.zoom); 54 | expect(map.getView().getCenter()[0]).toBeCloseTo(defaults.center.lon); 55 | expect(map.getView().getCenter()[1]).toBeCloseTo(defaults.center.lat); 56 | }); 57 | 58 | it('should set default layer if not layers are provided', function() { 59 | var element = angular.element(''); 60 | element = $compile(element)(scope); 61 | var map; 62 | olData.getMap().then(function(olMap) { 63 | map = olMap; 64 | }); 65 | scope.$digest(); 66 | var olLayers = map.getLayers(); 67 | expect(olLayers.getLength()).toEqual(1); 68 | var layer = olLayers.item(0); 69 | expect(layer instanceof ol.layer.Tile).toBe(true); 70 | var olSource = layer.getSource(); 71 | expect(olSource instanceof ol.source.OSM).toBe(true); 72 | }); 73 | 74 | it('should set the default view if not specified', function() { 75 | var element = angular.element(''); 76 | element = $compile(element)(scope); 77 | var map; 78 | var defaults = olMapDefaults.getDefaults(); 79 | 80 | olData.getMap().then(function(olMap) { 81 | map = olMap; 82 | }); 83 | 84 | scope.$digest(); 85 | var view = map.getView(); 86 | expect(view.getProjection().getCode()).toEqual(defaults.view.projection); 87 | expect(view.getRotation()).toEqual(defaults.view.rotation); 88 | }); 89 | 90 | it('should set the default controls if not specified', function() { 91 | var element = angular.element(''); 92 | element = $compile(element)(scope); 93 | var defaults = olMapDefaults.getDefaults(); 94 | var controls; 95 | 96 | olData.getMap().then(function(olMap) { 97 | controls = olMap.getControls(); 98 | }); 99 | 100 | scope.$digest(); 101 | var activeControls = Object.keys(defaults.controls).filter(function(c) { 102 | return defaults.controls[c] === true; 103 | }); 104 | expect(controls.getLength()).toEqual(activeControls.length); 105 | 106 | var actualControls = Object.keys(olHelpers.detectControls(controls)); 107 | actualControls.sort(); 108 | activeControls.sort(); 109 | expect(activeControls).toEqual(actualControls); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/unit/centerSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W117 */ 3 | /*jshint globalstrict: true*/ 4 | /* jasmine specs for directives go here */ 5 | 6 | describe('Directive: openlayers center', function() { 7 | var $compile; 8 | var $rootScope; 9 | var $timeout; 10 | var $location; 11 | var olData; 12 | var olMapDefaults; 13 | var scope; 14 | 15 | beforeEach(module('openlayers-directive')); 16 | beforeEach(inject(function(_$compile_, _$rootScope_, _$timeout_, _olData_, _olMapDefaults_, _$location_) { 17 | $compile = _$compile_; 18 | $rootScope = _$rootScope_; 19 | $timeout = _$timeout_; 20 | $location = _$location_; 21 | olData = _olData_; 22 | olMapDefaults = _olMapDefaults_; 23 | 24 | scope = $rootScope.$new(); 25 | })); 26 | 27 | afterEach(inject(function($rootScope) { 28 | $rootScope.$apply(); 29 | })); 30 | 31 | it('should have default {[0, 0], 1} parameters on the map if not correctly defined', function() { 32 | scope.center = {}; 33 | var element = angular.element(''); 34 | element = $compile(element)(scope); 35 | scope.$digest(); 36 | 37 | var map; 38 | olData.getMap().then(function(olMap) { 39 | map = olMap; 40 | }); 41 | 42 | scope.$digest(); 43 | var zoom = map.getView().getZoom(); 44 | var center = map.getView().getCenter(); 45 | expect(zoom).toEqual(1); 46 | expect(center[0]).toBeCloseTo(0); 47 | expect(center[1]).toBeCloseTo(0); 48 | }); 49 | 50 | it('should update the map center if the initial center scope properties are set', function() { 51 | scope.center = { 52 | lat: 0.96658, 53 | lon: 2.02, 54 | zoom: 4 55 | }; 56 | 57 | var element = angular.element(''); 58 | element = $compile(element)(scope); 59 | 60 | var map; 61 | olData.getMap().then(function(olMap) { 62 | map = olMap; 63 | }); 64 | 65 | scope.$digest(); 66 | var defaults = olMapDefaults.getDefaults(); 67 | var zoom = map.getView().getZoom(); 68 | var mapCenter = map.getView().getCenter(); 69 | mapCenter = ol.proj.transform([mapCenter[1], mapCenter[0]], defaults.view.projection, scope.center.projection); 70 | expect(zoom).toEqual(4); 71 | expect(mapCenter[0]).toBeCloseTo(0.96658); 72 | expect(mapCenter[1]).toBeCloseTo(2.02); 73 | }); 74 | 75 | it('should update the map center if the scope center properties changes', function() { 76 | scope.center = { 77 | lat: 0.96658, 78 | lon: 2.02, 79 | zoom: 4 80 | }; 81 | 82 | var element = angular.element(''); 83 | element = $compile(element)(scope); 84 | 85 | var map; 86 | olData.getMap().then(function(olMap) { 87 | map = olMap; 88 | }); 89 | scope.$digest(); 90 | 91 | var defaults = olMapDefaults.getDefaults(); 92 | var mapCenter = map.getView().getCenter(); 93 | mapCenter = ol.proj.transform([mapCenter[1], mapCenter[0]], defaults.view.projection, scope.center.projection); 94 | expect(mapCenter[0]).toBeCloseTo(0.96658); 95 | expect(mapCenter[1]).toBeCloseTo(2.01958); 96 | expect(map.getView().getZoom()).toEqual(4); 97 | 98 | scope.center = { 99 | lat: 2.0304, 100 | lon: 4.04, 101 | zoom: 8 102 | }; 103 | 104 | scope.$digest(); 105 | 106 | mapCenter = map.getView().getCenter(); 107 | mapCenter = ol.proj.transform([mapCenter[1], mapCenter[0]], defaults.view.projection, scope.center.projection); 108 | expect(mapCenter[0]).toBeCloseTo(2.0304); 109 | expect(mapCenter[1]).toBeCloseTo(4.0366); 110 | expect(map.getView().getZoom()).toEqual(8); 111 | }); 112 | 113 | it('should constrain max/min zoom if specified', function() { 114 | scope.center = { 115 | lat: 0.96658, 116 | lon: 2.02, 117 | zoom: 8, 118 | centerUrlHash: true 119 | }; 120 | 121 | scope.defaults = { 122 | view: { 123 | maxZoom: 6, 124 | minZoom: 3 125 | } 126 | }; 127 | 128 | var element = angular.element(''); 129 | element = $compile(element)(scope); 130 | 131 | var map; 132 | olData.getMap().then(function(olMap) { 133 | map = olMap; 134 | }); 135 | 136 | scope.$digest(); 137 | expect(map.getView().getZoom()).toEqual(6); 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /src/directives/openlayers.js: -------------------------------------------------------------------------------- 1 | angular.module('openlayers-directive', ['ngSanitize']).directive('openlayers', function($log, $q, $compile, olHelpers, 2 | olMapDefaults, olData) { 3 | return { 4 | restrict: 'EA', 5 | transclude: true, 6 | replace: true, 7 | scope: { 8 | center: '=olCenter', 9 | defaults: '=olDefaults', 10 | view: '=olView', 11 | events: '=olEvents' 12 | }, 13 | template: '
', 14 | controller: function($scope) { 15 | var _map = $q.defer(); 16 | $scope.getMap = function() { 17 | return _map.promise; 18 | }; 19 | 20 | $scope.setMap = function(map) { 21 | _map.resolve(map); 22 | }; 23 | 24 | this.getOpenlayersScope = function() { 25 | return $scope; 26 | }; 27 | }, 28 | link: function(scope, element, attrs) { 29 | var isDefined = olHelpers.isDefined; 30 | var createLayer = olHelpers.createLayer; 31 | var setMapEvents = olHelpers.setMapEvents; 32 | var setViewEvents = olHelpers.setViewEvents; 33 | var createView = olHelpers.createView; 34 | var defaults = olMapDefaults.setDefaults(scope); 35 | 36 | // Set width and height if they are defined 37 | if (isDefined(attrs.width)) { 38 | if (isNaN(attrs.width)) { 39 | element.css('width', attrs.width); 40 | } else { 41 | element.css('width', attrs.width + 'px'); 42 | } 43 | } 44 | 45 | if (isDefined(attrs.height)) { 46 | if (isNaN(attrs.height)) { 47 | element.css('height', attrs.height); 48 | } else { 49 | element.css('height', attrs.height + 'px'); 50 | } 51 | } 52 | 53 | if (isDefined(attrs.lat)) { 54 | defaults.center.lat = parseFloat(attrs.lat); 55 | } 56 | 57 | if (isDefined(attrs.lon)) { 58 | defaults.center.lon = parseFloat(attrs.lon); 59 | } 60 | 61 | if (isDefined(attrs.zoom)) { 62 | defaults.center.zoom = parseFloat(attrs.zoom); 63 | } 64 | 65 | var controls = ol.control.defaults(defaults.controls); 66 | var interactions = ol.interaction.defaults(defaults.interactions); 67 | var view = createView(defaults.view); 68 | 69 | // Create the Openlayers Map Object with the options 70 | var map = new ol.Map({ 71 | target: element[0], 72 | controls: controls, 73 | interactions: interactions, 74 | renderer: defaults.renderer, 75 | view: view, 76 | loadTilesWhileAnimating: defaults.loadTilesWhileAnimating, 77 | loadTilesWhileInteracting: defaults.loadTilesWhileInteracting 78 | }); 79 | 80 | scope.$on('$destroy', function() { 81 | olData.resetMap(attrs.id); 82 | map.setTarget(null); 83 | map = null; 84 | }); 85 | 86 | // If no layer is defined, set the default tileLayer 87 | if (!attrs.customLayers) { 88 | var l = { 89 | type: 'Tile', 90 | source: { 91 | type: 'OSM' 92 | } 93 | }; 94 | var layer = createLayer(l, view.getProjection(), 'default'); 95 | map.addLayer(layer); 96 | map.set('default', true); 97 | } 98 | 99 | if (!isDefined(attrs.olCenter)) { 100 | var c = ol.proj.transform([defaults.center.lon, 101 | defaults.center.lat 102 | ], 103 | defaults.center.projection, view.getProjection() 104 | ); 105 | view.setCenter(c); 106 | view.setZoom(defaults.center.zoom); 107 | } 108 | 109 | // Set the Default events for the map 110 | setMapEvents(defaults.events, map, scope); 111 | 112 | //Set the Default events for the map view 113 | setViewEvents(defaults.events, map, scope); 114 | 115 | // Resolve the map object to the promises 116 | scope.setMap(map); 117 | olData.setMap(map, attrs.id); 118 | 119 | } 120 | }; 121 | }); 122 | -------------------------------------------------------------------------------- /test/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // A reference configuration file. 2 | exports.config = { 3 | // ----- How to setup Selenium ----- 4 | // 5 | // There are three ways to specify how to use Selenium. Specify one of the 6 | // following: 7 | // 8 | // 1. seleniumServerJar - to start Selenium Standalone locally. 9 | // 2. seleniumAddress - to connect to a Selenium server which is already 10 | // running. 11 | // 3. sauceUser/sauceKey - to use remote Selenium servers via SauceLabs. 12 | // 13 | // If the chromeOnly option is specified, no Selenium server will be started, 14 | // and chromeDriver will be used directly (from the location specified in 15 | // chromeDriver) 16 | 17 | // The location of the selenium standalone server .jar file. 18 | seleniumServerJar: '../node_modules/protractor/selenium/selenium-server-standalone-2.47.1.jar', 19 | // The port to start the selenium server on, or null if the server should 20 | // find its own unused port. 21 | seleniumPort: null, 22 | // Chromedriver location is used to help the selenium standalone server 23 | // find chromedriver. This will be passed to the selenium jar as 24 | // the system property webdriver.chrome.driver. If null, selenium will 25 | // attempt to find chromedriver using PATH. 26 | chromeDriver: '../node_modules/protractor/selenium/chromedriver', 27 | // If true, only chromedriver will be started, not a standalone selenium. 28 | // Tests for browsers other than chrome will not run. 29 | chromeOnly: false, 30 | // Additional command line options to pass to selenium. For example, 31 | // if you need to change the browser timeout, use 32 | // seleniumArgs: ['-browserTimeout=60'], 33 | seleniumArgs: [], 34 | 35 | // If sauceUser and sauceKey are specified, seleniumServerJar will be ignored. 36 | // The tests will be run remotely using SauceLabs. 37 | sauceUser: null, 38 | sauceKey: null, 39 | 40 | // The address of a running selenium server. If specified, Protractor will 41 | // connect to an already running instance of selenium. This usually looks like 42 | // seleniumAddress: 'http://localhost:4444/wd/hub' 43 | //seleniumAddress: 'http://localhost:4444/wd/hub', 44 | 45 | // The timeout for each script run on the browser. This should be longer 46 | // than the maximum time your application needs to stabilize between tasks. 47 | allScriptsTimeout: 11000, 48 | 49 | // ----- What tests to run ----- 50 | // 51 | // Spec patterns are relative to the location of this config. 52 | specs: [ 53 | 'e2e/*.js', 54 | ], 55 | 56 | // ----- Capabilities to be passed to the webdriver instance ---- 57 | // 58 | // For a full list of available capabilities, see 59 | // https://code.google.com/p/selenium/wiki/DesiredCapabilities 60 | // and 61 | // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js 62 | capabilities: { 63 | 'browserName': 'chrome' 64 | }, 65 | 66 | // ----- More information for your tests ---- 67 | // 68 | // A base URL for your application under test. Calls to protractor.get() 69 | // with relative paths will be prepended with this. 70 | baseUrl: 'http://localhost:9999/examples/', 71 | 72 | // Selector for the element housing the angular app - this defaults to 73 | // body, but is necessary if ng-app is on a descendant of 74 | rootElement: 'body', 75 | 76 | // A callback function called once protractor is ready and available, and 77 | // before the specs are executed 78 | // You can specify a file containing code to run by setting onPrepare to 79 | // the filename string. 80 | onPrepare: function() { 81 | // At this point, global 'protractor' object will be set up, and jasmine 82 | // will be available. For example, you can add a Jasmine reporter with: 83 | // jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter( 84 | // 'outputdir/', true, true)); 85 | }, 86 | 87 | // The params object will be passed directly to the protractor instance, 88 | // and can be accessed from your test. It is an arbitrary object and can 89 | // contain anything you my need in your test. 90 | // This can be changed via the command line as: 91 | // --params.login.user 'Joe' 92 | params: { 93 | login: { 94 | user: 'Jane', 95 | password: '1234' 96 | } 97 | }, 98 | 99 | // ----- Options to be passed to minijasminenode ----- 100 | // 101 | // See the full list at https://github.com/juliemr/minijasminenode 102 | jasmineNodeOpts: { 103 | // onComplete will be called just before the driver quits. 104 | onComplete: null, 105 | // If true, display spec names. 106 | isVerbose: true, 107 | // If true, print colors to the terminal. 108 | showColors: true, 109 | // If true, include stack traces in failures. 110 | includeStackTrace: true, 111 | // Default time to wait in ms before a test fails. 112 | defaultTimeoutInterval: 30000 113 | } 114 | }; 115 | --------------------------------------------------------------------------------