├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist ├── angular-heremaps.js └── angular-heremaps.min.js ├── example ├── app.module.js └── marker.svg ├── gulpfile.js ├── index.html ├── karma.conf.js ├── package.json └── src ├── heremaps.directive.js ├── heremaps.directive.spec.js ├── index.js └── providers ├── api.service.js ├── consts.js ├── map-modules ├── events │ ├── events.js │ └── infobubble.js ├── index.js └── ui │ └── ui.js ├── mapconfig.provider.js ├── maputils.service.js ├── markers ├── default.marker.js ├── dom.marker.js ├── index.js ├── marker.js ├── markers.service.js └── svg.marker.js └── routes ├── index.js └── routes.service.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | .idea/* 3 | coverage/ 4 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - npm install -g codeclimate-test-reporter 3 | install: 4 | - npm i 5 | language: node_js 6 | node_js: 7 | - "4.2.4" 8 | script: 9 | - ./node_modules/.bin/gulp build 10 | - npm test 11 | after_script: 12 | - codeclimate-test-reporter < ./coverage/**/lcov.info 13 | addons: 14 | code_climate: 15 | repo_token: c7535f88a3e1a0d9d2c8450a4e35e3c87fdf21251a7123957fbd34071a3cb545 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dmytro Verbovyi 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/dverbovyi/angular-heremaps.svg?branch=master)](https://travis-ci.org/dverbovyi/angular-heremaps) 2 | [![Code Climate](https://codeclimate.com/github/dverbovyi/angular-heremaps/badges/gpa.svg)](https://codeclimate.com/github/dverbovyi/angular-heremaps) 3 | [![npm version](https://badge.fury.io/js/angular-heremaps.svg)](https://badge.fury.io/js/angular-heremaps) 4 | 5 | 6 | # angular-heremaps 7 | *Live demo* **https://dverbovyi.github.io/angular-heremaps/** 8 | 9 | AngularJS directive for working with Here Maps 10 | 11 | ### 0.1.9 latest release 12 | [see release notes](https://github.com/dverbovyi/angular-heremaps/releases/tag/v0.1.9) 13 | 14 | ### Install guide: 15 | 16 | npm install angular-heremaps 17 | 18 | ##### include angular-heremaps file 19 | 20 | ```html 21 | 22 | ``` 23 | 24 | ##### add dependency in your angular application 25 | 26 | ```javascript 27 | angular.module('exampleModule', ['heremaps']) 28 | ``` 29 | 30 | ##### add config provider: 31 | Before, you should register [here](https://developer.here.com/plans/api/consumer-mapping) and get your app id. Then pass it below 32 | 33 | ```javascript 34 | angular.module('exampleModule') 35 | .config(["HereMapsConfigProvider", function(HereMapsConfigProvider) { 36 | HereMapsConfigProvider.setOptions({ 37 | 'app_id': 'your_app_id_here', 38 | 'app_code': 'your_app_code_here', 39 | 'useHTTPS': true 40 | }); 41 | }]); 42 | ``` 43 | 44 | #### Simple directive initialization with default options. 45 | 46 | ```html 47 |
48 | ``` 49 | 50 | See details on [wiki pages](https://github.com/dverbovyi/angular-heremaps/wiki) 51 | 52 | Please report, any issue [here](https://github.com/dverbovyi/angular-heremaps/issues) 53 | 54 | 55 | ### To Contribute 56 | 57 | #### Fork and clone the project 58 | git clone https://github.com/{{username}}/angular-heremaps.git 59 | 60 | and make pull request 61 | 62 | #### Install dependencies 63 | cd angular-heremaps 64 | 65 | npm i 66 | 67 | #### Start dev-server 68 | 69 | gulp serve 70 | 71 | #### Build resources 72 | 73 | gulp build 74 | 75 | -------------------------------------------------------------------------------- /dist/angular-heremaps.min.js: -------------------------------------------------------------------------------- 1 | !function e(t,r,n){function o(a,s){if(!r[a]){if(!t[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var p=r[a]={exports:{}};t[a][0].call(p.exports,function(e){var r=t[a][1][e];return o(r||e)},p,p.exports,e,t,r,n)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a",replace:!0,scope:{opts:"&options",places:"&",onMapReady:"&mapReady",events:"&"},controller:l}}t.exports=n,n.$inject=["$timeout","$window","$rootScope","$filter","HereMapsConfig","HereMapsAPIService","HereMapsUtilsService","HereMapsMarkerService","HereMapsRoutesService","HereMapsCONSTS","HereMapsEventsFactory","HereMapsUiFactory"]},{}],2:[function(e,t,r){e("./providers/markers"),e("./providers/map-modules"),e("./providers/routes"),t.exports=angular.module("heremaps",["heremaps-markers-module","heremaps-routes-module","heremaps-map-modules"]).provider("HereMapsConfig",e("./providers/mapconfig.provider")).service("HereMapsUtilsService",e("./providers/maputils.service")).service("HereMapsAPIService",e("./providers/api.service")).constant("HereMapsCONSTS",e("./providers/consts")).directive("heremaps",e("./heremaps.directive"))},{"./heremaps.directive":1,"./providers/api.service":3,"./providers/consts":4,"./providers/map-modules":7,"./providers/mapconfig.provider":9,"./providers/maputils.service":10,"./providers/markers":13,"./providers/routes":17}],3:[function(e,t,r){function n(e,t,r,n,o){function i(){return h(O.CORE).then(function(){return h(O.SERVICE)})}function a(e,t){for(var r in t)if(t.hasOwnProperty(r)&&e[r]){var n=l(r);n().then(t[r])}}function s(t){var r=e.defer();return t&&n.isValidCoords(t.coords)?r.resolve({coords:t.coords}):navigator.geolocation.getCurrentPosition(function(e){r.resolve(e)},function(e){r.reject(e)},t),r.promise}function u(t,r){if(!r.coords)return console.error("Missed required coords");var n=t.getGeocodingService(),o=e.defer(),i={prox:[r.coords.lat,r.coords.lng,r.radius||250].join(","),mode:"retrieveAddresses",maxresults:"1",gen:"8",language:r.lang||"en-gb"};return n.reverseGeocode(i,function(e){o.resolve(e)},function(e){o.reject(e)}),o.promise}function c(t,r){if(!r)return console.error("Missed required parameters");var n=t.getGeocodingService(),o=e.defer(),i={gen:8};for(var a in r)i[a]=r[a];return n.geocode(i,function(e){o.resolve(e)},function(e){o.reject(e)}),o.promise}function p(n){if(!n)return console.error("Missing required parameters");var o=T+O.AUTOCOMPLETE_URL,i=e.defer(),a={query:"",beginHighlight:"",endHighlight:"",maxresults:"5"};for(var s in a)angular.isDefined(n[s])&&(a[s]=n[s]);return a.app_id=r.app_id,a.app_code=r.app_code,t.get(o,{params:a}).success(function(e){i.resolve(e)}).error(function(e){i.reject(e)}),i.promise}function d(n){if(!n)return console.error("Missing Location Identifier");var o=T+O.LOCATION_URL,i=e.defer(),a={locationid:n,gen:9,app_id:r.app_id,app_code:r.app_code};return t.get(o,{params:a}).success(function(e){i.resolve(e)}).error(function(e){i.reject(e)}),i.promise}function l(e){var t;switch(e){case o.MODULES.UI:t=f;break;case o.MODULES.EVENTS:t=m;break;default:throw new Error("Unknown module",e)}return t}function f(){if(!v(O.UI.src)){var e=n.createLinkTag({rel:"stylesheet",type:"text/css",href:g(O.UI.href)});e&&I.appendChild(e)}return h(O.UI.src)}function m(){return h(O.EVENTS)}function g(e){return[T,O.BASE,H.V,"/",H.SUB,"/",e].join("")}function h(t){var r,o,i=e.defer();return v(t)?i.resolve():(r=g(t),o=n.createScriptTag({src:r}),o&&I.appendChild(o),x[t].push(i),o.onload=k.bind(null,t),o.onerror=b.bind(null,t)),i.promise}function v(e){var t=null;switch(e){case O.CORE:t=E;break;case O.SERVICE:t=M;break;case O.UI.src:t=S;break;case O.EVENTS:t=w;break;default:t=function(){return!1}}return t()}function E(){return!!window.H}function M(){return!(!window.H||!window.H.service)}function S(){return!(!window.H||!window.H.ui)}function w(){return!(!window.H||!window.H.mapevents)}function k(e){for(var t=x[e],r=0,n=t.length;r',onStateChange:function(o){i.getState()!==H.ui.base.Button.State.DOWN&&e.getPosition().then(function(e){var o={lng:e.coords.longitude,lat:e.coords.latitude};if(n.map.setCenter(o),r.zoom(n.map,17,.08),n.userMarker)return void n.userMarker.setPosition(o);n.userMarker=t.addUserMarker(n.map,{pos:o})})}});return o.addChild(i),o}function s(e){if(o.isValidAlignment(this.alignment))for(var t in e){var r=this.ui.getControl(e[t]);e.hasOwnProperty(t)&&r&&r.setAlignment(this.alignment)}}function u(e){return!!(n.CONTROLS.POSITIONS.indexOf(e)+1)}o.isValidAlignment=u;var c=o.prototype;return c.setupControls=i,c.createUserControl=a,c.setControlsAlignment=s,{start:function(e){if(!(e.platform.map instanceof H.Map||e.platform.layers))return console.error("Missed ui module dependencies");new o(e.platform,e.alignment)}}}t.exports=n,n.$inject=["HereMapsAPIService","HereMapsMarkerService","HereMapsUtilsService","HereMapsCONSTS"]},{}],9:[function(e,t,r){t.exports=function(){var e={};this.$get=function(){return{app_id:e.app_id,app_code:e.app_code,apiVersion:e.apiVersion||"3.0",useHTTPS:e.useHTTPS,useCIT:!!e.useCIT,mapTileConfig:e.mapTileConfig}},this.setOptions=function(t){e=t}}},{}],10:[function(e,t,r){function n(e,t,r){function n(e,r){var n=null;return function(){t&&t.cancel(n),n=t(e,r)}}function o(e,t,r,n){e.addEventListener(t,r,!!n)}function i(e,t){return!(!e.$root||"$apply"===e.$root.$$phase||"$digest"===e.$root.$$phase)&&(e.$digest(t||angular.noop),!0)}function a(e){var t=document.getElementById(e.src);return!t&&(t=document.createElement("script"),t.type="text/javascript",t.id=e.src,f(t,e),t)}function s(e){var t=document.getElementById(e.href);return!t&&(t=document.createElement("link"),t.id=e.href,f(t,e),t)}function u(e){return e&&("string"==typeof e.latitude||"number"==typeof e.latitude)&&("string"==typeof e.longitude||"number"==typeof e.longitude)}function c(e,t,n){var o=e.getZoom(),i=(n||r.ANIMATION_ZOOM_STEP,o>=t?-1:1),a=n*i;return function r(){if(!n||Math.floor(o)===Math.floor(t))return void e.setZoom(t);o+=a,e.setZoom(o),requestAnimationFrame(r)}()}function p(){return H}function d(e,t){return H.geo.Rect.fromPoints(e,t,!0)}function l(){var e=/[xy]/g,t=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(e,function(e){var r=(t+16*Math.random())%16|0;return t=Math.floor(t/16),("x"==e?r:3&r|8).toString(16)})}function f(e,t){if(!e||!t)throw new Error("Missed attributes");for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])}return{throttle:n,createScriptTag:a,createLinkTag:s,runScopeDigestIfNeed:i,isValidCoords:u,addEventListener:o,zoom:c,getBoundsRectFromPoints:d,generateId:l,getMapFactory:p}}t.exports=n,n.$inject=["$rootScope","$timeout","HereMapsCONSTS"]},{}],11:[function(e,t,r){function n(e){function t(e){this.place=e,this.setCoords()}function r(){var e=new H.map.Marker(this.coords);return this.addInfoBubble(e),e}var n=t.prototype=new e;return n.constructor=t,n.create=r,t}t.exports=n,n.$inject=["HereMapsMarkerInterface"]},{}],12:[function(e,t,r){function n(e){function t(e){this.place=e,this.setCoords()}function r(){var e=new H.map.DomMarker(this.coords,{icon:this.getIcon()});return this.addInfoBubble(e),e}function n(){var e=this.place.markup;if(!e)throw new Error("markup missed");return new H.map.DomIcon(e)}function o(e,t,r){var n=r?"removeEventListener":"addEventListener";for(var o in t)t.hasOwnProperty(o)&&e[n].call(null,o,t[o])}var i=t.prototype=new e;return i.constructor=t,i.create=r,i.getIcon=n,i.setupEvents=o,t}t.exports=n,n.$inject=["HereMapsMarkerInterface"]},{}],13:[function(e,t,r){t.exports=angular.module("heremaps-markers-module",[]).factory("HereMapsMarkerInterface",e("./marker.js")).factory("HereMapsDefaultMarker",e("./default.marker.js")).factory("HereMapsDOMMarker",e("./dom.marker.js")).factory("HereMapsSVGMarker",e("./svg.marker.js")).service("HereMapsMarkerService",e("./markers.service.js"))},{"./default.marker.js":11,"./dom.marker.js":12,"./marker.js":14,"./markers.service.js":15,"./svg.marker.js":16}],14:[function(e,t,r){t.exports=function(){function e(){throw new Error("Abstract class! The Instance should be created")}function t(){}function r(){throw new Error("create:: not implemented")}function n(){this.coords={lat:this.place.pos.lat,lng:this.place.pos.lng}}function o(e){this.place.popup&&e.setData(this.place.popup)}var i=e.prototype;return i.create=r,i.setCoords=n,i.addInfoBubble=o,t.prototype=i,t}},{}],15:[function(e,t,r){function n(e,t,r,n){function o(e){return e instanceof H.map.Marker||e instanceof H.map.DomMarker}function i(e,t){return e.userMarker?e.userMarker:(t.markup='',e.userMarker=new r(t).create(),e.addObject(e.userMarker),e.userMarker)}function a(e,t,r){if(t&&t.length){if(!(e instanceof H.Map))throw new Error("Unsupported map instance");e.markersGroup||(e.markersGroup=new H.map.Group),t.forEach(function(t,r){var n=c(t),o=t.draggable?p(n.create()):n.create();e.markersGroup.addObject(o)}),e.addObject(e.markersGroup),r&&s(e,e.markersGroup.getBounds())}}function s(e,t,r){e.setViewBounds(t,!!r)}function u(e,t,r){e.markersGroup&&(e.markersGroup.removeAll(),e.removeObject(e.markersGroup),e.markersGroup=null),a.apply(null,arguments)}function c(n){var o;switch(n.type?n.type.toUpperCase():null){case d.DOM:o=t;break;case d.SVG:o=r;break;default:o=e}return new o(n)}function p(e){return e.draggable=!0,e}var d=n.MARKER_TYPES;return{addMarkersToMap:a,addUserMarker:i,updateMarkers:u,isMarkerInstance:o,setViewBounds:s}}t.exports=n,n.$inject=["HereMapsDefaultMarker","HereMapsDOMMarker","HereMapsSVGMarker","HereMapsCONSTS"]},{}],16:[function(e,t,r){function n(e){function t(e){this.place=e,this.setCoords()}function r(){var e=new H.map.Marker(this.coords,{icon:this.getIcon()});return this.addInfoBubble(e),e}function n(){var e=this.place.markup;if(!e)throw new Error("markup missed");return new H.map.Icon(e)}var o=t.prototype=new e;return o.constructor=t,o.create=r,o.getIcon=n,t}t.exports=n,n.$inject=["HereMapsMarkerInterface"]},{}],17:[function(e,t,r){t.exports=angular.module("heremaps-routes-module",[]).service("HereMapsRoutesService",e("./routes.service.js"))},{"./routes.service.js":18}],18:[function(e,t,r){function n(e,t){function r(t,r){var n=t.platform,o=(t.map,n.getRoutingService()),a=r.direction,s=a.waypoints,u="{{MODE}};{{VECHILE}}".replace(/{{MODE}}/,a.mode||"fastest").replace(/{{VECHILE}}/,r.driveType),c={mode:u,representation:a.representation||"display",language:a.language||"en-gb"};s.forEach(function(e,t){c["waypoint"+t]=[e.lat,e.lng].join(",")}),i(c,a.attrs);var p=e.defer();return o.calculateRoute(c,function(e){p.resolve(e)},function(e){p.reject(e)}),p.promise}function n(e){var t=e.routesGroup;t&&(t.removeAll(),e.removeObject(t),e.routesGroup=null)}function o(e,r,o){o&&n(e);var i=r.route;if(e&&i&&i.shape){var a=new H.geo.Strip,s=null;i.shape.forEach(function(e){var t=e.split(",");a.pushLatLngAlt(t[0],t[1])});var u=r.style||{};s=new H.map.Polyline(a,{style:{lineWidth:u.lineWidth||4,strokeColor:u.color||"rgba(0, 128, 255, 0.7)"}});var c=e.routesGroup;c||(c=e.routesGroup=new H.map.Group,e.addObject(c)),c.addObject(s),r.zoomToBounds&&t.setViewBounds(e,s.getBounds(),!0)}}function i(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r+"attributes"]=t[r])}return{calculateRoute:r,addRouteToMap:o,cleanRoutes:n}}t.exports=n,n.$inject=["$q","HereMapsMarkerService"]},{}]},{},[2]); -------------------------------------------------------------------------------- /example/app.module.js: -------------------------------------------------------------------------------- 1 | 2 | (function () { 3 | 4 | 'use strict'; 5 | 6 | angular 7 | .module('demoModule', ['heremaps']) 8 | .config(["HereMapsConfigProvider", function (HereMapsConfigProvider) { 9 | HereMapsConfigProvider.setOptions({ 10 | 'app_id': 'DemoAppId01082013GAL', 11 | 'app_code': 'AJKnXv84fjrb0KIHawS0Tg', 12 | 'useHTTPS': true, 13 | 'useCIT': true, 14 | 'mapTileConfig': { 15 | metadataQueryParams: { 16 | 'lg2': 'ara' 17 | } 18 | } 19 | }); 20 | }]); 21 | 22 | angular.module('demoModule') 23 | .controller('DemoCtrl', ['$scope', DemoCtrl]); 24 | 25 | function DemoCtrl($scope) { 26 | $scope.mapOptions = { 27 | height: 640, 28 | width: 480, 29 | zoom: 13, 30 | draggable: true, 31 | resize: true, 32 | coords: { 33 | longitude: 55.1021576, 34 | latitude: 25.064732 35 | } 36 | }; 37 | 38 | $scope.onMapReady = function (heremaps) { 39 | $scope.heremaps = heremaps; 40 | 41 | heremaps.setCenter({ 42 | lat: 25.1075831, lng: 55.159061 43 | }); 44 | 45 | heremaps.setZoom(13); 46 | 47 | heremaps.calculateRoute('car', { 48 | mode: 'fastest', 49 | waypoints: [ 50 | { lat: 25.1075831, lng: 55.1461 }, 51 | { lat: 25.1075831, lng: 55.179061 } 52 | ] 53 | }).then(function(result){ 54 | if(!result.response) 55 | return; 56 | 57 | heremaps.addRouteToMap({ 58 | zoomToBounds: false, 59 | route: result.response.route[0], 60 | style: { 61 | lineWidth: 5, 62 | color: 'rgba(0, 128, 255, 1)' 63 | } 64 | }); 65 | }).catch(handleError); 66 | }; 67 | 68 | $scope.markers = [ 69 | { 70 | pos: { lat: 25.1075831, lng: 55.1461 }, 71 | popup: { 72 | display: 'onHover', 73 | markup: '
Default Marker
' 74 | } 75 | }, 76 | { 77 | pos: { lat: 25.1075831, lng: 55.179061 } 78 | }, 79 | { 80 | pos: { lat: 25.1075831, lng: 55.079061 }, 81 | type: 'DOM', 82 | markup: '

DOM Marker

(Click me)
', 83 | popup: { 84 | display: 'onClick', 85 | markup: 'View on GitHub' 86 | } 87 | }, 88 | { 89 | pos: { lat: 25.1075831, lng: 55.2 }, 90 | type: 'SVG', 91 | draggable: true, 92 | markup: './example/marker.svg' 93 | } 94 | ]; 95 | 96 | $scope.listeners = { 97 | 'click': function () { 98 | console.info('click'); 99 | }, 100 | 'mapviewchangeend': function () { 101 | console.info('mapviewchangeend'); 102 | } 103 | }; 104 | 105 | function handleError(e) { 106 | console.error(e); 107 | } 108 | } 109 | })(); -------------------------------------------------------------------------------- /example/marker.svg: -------------------------------------------------------------------------------- 1 | SVGdrag me -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Dmytro on 3/27/2016. 3 | */ 4 | var browserify = require('browserify'), 5 | gulp = require('gulp'), 6 | source = require('vinyl-source-stream'), 7 | minify = require('gulp-minify'), 8 | buffer = require('vinyl-buffer'), 9 | config = require('./package.json'), 10 | argv = require('yargs').argv, 11 | browserSync = require("browser-sync").create(); 12 | 13 | /* pathConfig*/ 14 | var entryPoint = './src/index.js', 15 | browserDir = './', 16 | jsWatchPath = './src/**/*.js'; 17 | /**/ 18 | 19 | gulp.task('browser-sync', function () { 20 | browserSync.init({ 21 | server: { 22 | baseDir: browserDir 23 | } 24 | }); 25 | }); 26 | 27 | gulp.task('build', function () { 28 | return browserify(entryPoint, { debug: true }) 29 | .bundle() 30 | .pipe(source('angular-heremaps.js')) 31 | .pipe(buffer()) 32 | .pipe(minify({ 33 | ext: { 34 | min: '.min.js' 35 | }, 36 | })) 37 | .pipe(gulp.dest('./dist/')) 38 | .pipe(browserSync.reload({ stream: true })); 39 | }); 40 | 41 | gulp.task('serve', ['build', 'browser-sync'], function () { 42 | gulp.watch(jsWatchPath, ['build']).on('change', browserSync.reload); 43 | gulp.watch("index.html").on('change', browserSync.reload); 44 | }) 45 | 46 | gulp.task('default', ['build']); 47 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 | 13 | 53 | 54 | 55 | 56 |
57 |
64 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Dmytro on 4/26/2016. 3 | */ 4 | var istanbul = require('browserify-istanbul'); 5 | 6 | module.exports = function (config) { 7 | config.set({ 8 | basePath: '', 9 | frameworks: ['browserify', 'jasmine'], 10 | 11 | files: [ 12 | './node_modules/angular/angular.js', 13 | './node_modules/angular-mocks/angular-mocks.js', 14 | './src/**/*.js', 15 | './src/**/*spec.js' 16 | ], 17 | 18 | preprocessors: { 19 | './src/**/*.js': ['browserify'] 20 | }, 21 | 22 | browserify: { 23 | debug: true, 24 | transform: ['browserify-istanbul'] 25 | }, 26 | 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | 30 | plugins : [ 31 | 'karma-browserify', 32 | 'karma-jasmine', 33 | 'karma-mocha-reporter', 34 | 'karma-phantomjs-launcher', 35 | 'karma-chrome-launcher', 36 | 'karma-coverage' 37 | ], 38 | 39 | reporters: ['mocha', 'progress', 'coverage'], 40 | 41 | coverageReporter: { 42 | reporters: [{ 43 | type: 'lcov', 44 | dir: 'coverage/' 45 | }, { 46 | type: 'text-summary' 47 | }] 48 | }, 49 | 50 | browsers: ['PhantomJS'], 51 | // browsers: ['Chrome'], 52 | 53 | autoWatch: false, 54 | singleRun: true 55 | }); 56 | }; 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-heremaps", 3 | "version": "0.1.9", 4 | "description": "Angular directive for working with HereMaps", 5 | "source-folder": "/dist", 6 | "main": "angular-heremaps.js", 7 | "output": "angular-heremaps.js", 8 | "scripts": { 9 | "test": "karma start", 10 | "build": "./node_modules/.bin/gulp build" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/dverbovyi/angular-heremaps.git" 15 | }, 16 | "keywords": [ 17 | "heremaps", 18 | "here maps", 19 | "javascript", 20 | "angular", 21 | "angularjs" 22 | ], 23 | "author": "Dmytro Verbovyi: https://github.com/dverbovyi, Andrii Vandakurov: https://github.com/toastman", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/dverbovyi/angular-heremaps/issues" 27 | }, 28 | "homepage": "https://dverbovyi.github.io/angular-heremaps/", 29 | "dependencies": { 30 | "angular": "^1.5.6" 31 | }, 32 | "devDependencies": { 33 | "angular-mocks": "^1.5.6", 34 | "browser-sync": "^2.16.0", 35 | "browserify": "^13.0.1", 36 | "browserify-istanbul": "^2.0.0", 37 | "gulp": "^3.9.1", 38 | "gulp-minify": "0.0.14", 39 | "gulp-sourcemaps": "^1.6.0", 40 | "istanbul": "^0.4.3", 41 | "jasmine": "^2.4.1", 42 | "karma": "^0.13.22", 43 | "karma-browserify": "^5.0.5", 44 | "karma-chrome-launcher": "^1.0.1", 45 | "karma-coverage": "^1.0.0", 46 | "karma-jasmine": "^1.0.2", 47 | "karma-mocha-reporter": "^2.0.3", 48 | "karma-phantomjs-launcher": "^1.0.0", 49 | "phantomjs-prebuilt": "^2.1.7", 50 | "vinyl-buffer": "^1.0.0", 51 | "vinyl-source-stream": "^1.1.0", 52 | "watchify": "^3.7.0", 53 | "yargs": "^4.7.1" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/heremaps.directive.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsDirective; 2 | 3 | HereMapsDirective.$inject = [ 4 | '$timeout', 5 | '$window', 6 | '$rootScope', 7 | '$filter', 8 | 'HereMapsConfig', 9 | 'HereMapsAPIService', 10 | 'HereMapsUtilsService', 11 | 'HereMapsMarkerService', 12 | 'HereMapsRoutesService', 13 | 'HereMapsCONSTS', 14 | 'HereMapsEventsFactory', 15 | 'HereMapsUiFactory' 16 | ]; 17 | function HereMapsDirective( 18 | $timeout, 19 | $window, 20 | $rootScope, 21 | $filter, 22 | HereMapsConfig, 23 | HereMapsAPIService, 24 | HereMapsUtilsService, 25 | HereMapsMarkerService, 26 | HereMapsRoutesService, 27 | HereMapsCONSTS, 28 | HereMapsEventsFactory, 29 | HereMapsUiFactory) { 30 | 31 | HereMapsDirectiveCtrl.$inject = ['$scope', '$element', '$attrs']; 32 | 33 | return { 34 | restrict: 'EA', 35 | template: "
", 36 | replace: true, 37 | scope: { 38 | opts: '&options', 39 | places: '&', 40 | onMapReady: "&mapReady", 41 | events: '&' 42 | }, 43 | controller: HereMapsDirectiveCtrl 44 | } 45 | 46 | function HereMapsDirectiveCtrl($scope, $element, $attrs) { 47 | var CONTROL_NAMES = HereMapsCONSTS.CONTROLS.NAMES, 48 | places = $scope.places(), 49 | opts = $scope.opts(), 50 | listeners = $scope.events(); 51 | 52 | var options = angular.extend({}, HereMapsCONSTS.DEFAULT_MAP_OPTIONS, opts), 53 | position = HereMapsUtilsService.isValidCoords(options.coords) ? 54 | options.coords : HereMapsCONSTS.DEFAULT_MAP_OPTIONS.coords; 55 | 56 | var heremaps = { id: HereMapsUtilsService.generateId() }, 57 | mapReady = $scope.onMapReady(), 58 | _onResizeMap = null; 59 | 60 | $timeout(function () { 61 | return _setMapSize(); 62 | }).then(function () { 63 | HereMapsAPIService.loadApi().then(_apiReady); 64 | }); 65 | 66 | options.resize && addOnResizeListener(); 67 | 68 | $scope.$on('$destroy', function () { 69 | $window.removeEventListener('resize', _onResizeMap); 70 | }); 71 | 72 | function addOnResizeListener() { 73 | _onResizeMap = HereMapsUtilsService.throttle(_resizeHandler, HereMapsCONSTS.UPDATE_MAP_RESIZE_TIMEOUT); 74 | $window.addEventListener('resize', _onResizeMap); 75 | } 76 | 77 | function _apiReady() { 78 | _setupMapPlatform(); 79 | _setupMap(); 80 | } 81 | 82 | function _setupMapPlatform() { 83 | if (!HereMapsConfig.app_id || !HereMapsConfig.app_code) 84 | throw new Error('app_id or app_code were missed. Please specify their in HereMapsConfig'); 85 | 86 | heremaps.platform = new H.service.Platform(HereMapsConfig); 87 | heremaps.layers = heremaps.platform.createDefaultLayers(); 88 | } 89 | 90 | function _getLocation(enableHighAccuracy, maximumAge) { 91 | var _enableHighAccuracy = !!enableHighAccuracy, 92 | _maximumAge = maximumAge || 0; 93 | 94 | return HereMapsAPIService.getPosition({ 95 | enableHighAccuracy: _enableHighAccuracy, 96 | maximumAge: _maximumAge 97 | }); 98 | } 99 | 100 | function _locationFailure() { 101 | console.error('Can not get a geo position'); 102 | } 103 | 104 | function _setupMap() { 105 | _initMap(function () { 106 | HereMapsAPIService.loadModules($attrs.$attr, { 107 | "controls": _uiModuleReady, 108 | "events": _eventsModuleReady 109 | }); 110 | }); 111 | } 112 | 113 | function _initMap(cb) { 114 | var map = heremaps.map = new H.Map($element[0], heremaps.layers.normal.map, { 115 | zoom: HereMapsUtilsService.isValidCoords(position) ? options.zoom : options.maxZoom, 116 | center: new H.geo.Point(position.latitude, position.longitude) 117 | }); 118 | 119 | HereMapsMarkerService.addMarkersToMap(map, places, true); 120 | 121 | if (HereMapsConfig.mapTileConfig) 122 | _setCustomMapStyles(map, HereMapsConfig.mapTileConfig); 123 | 124 | mapReady && mapReady(MapProxy()); 125 | 126 | cb && cb(); 127 | 128 | } 129 | 130 | function _uiModuleReady() { 131 | HereMapsUiFactory.start({ 132 | platform: heremaps, 133 | alignment: $attrs.controls 134 | }); 135 | } 136 | 137 | function _eventsModuleReady() { 138 | HereMapsEventsFactory.start({ 139 | platform: heremaps, 140 | listeners: listeners, 141 | options: options, 142 | injector: _moduleInjector 143 | }); 144 | } 145 | 146 | function _moduleInjector() { 147 | return function (id) { 148 | return heremaps[id]; 149 | } 150 | } 151 | 152 | function _resizeHandler(height, width) { 153 | _setMapSize.apply(null, arguments); 154 | 155 | heremaps.map.getViewPort().resize(); 156 | } 157 | 158 | function _setMapSize(height, width) { 159 | var height = height || $element[0].parentNode.offsetHeight || options.height, 160 | width = width || $element[0].parentNode.offsetWidth || options.width; 161 | 162 | $scope.mapHeight = height + 'px'; 163 | $scope.mapWidth = width + 'px'; 164 | 165 | HereMapsUtilsService.runScopeDigestIfNeed($scope); 166 | } 167 | 168 | function _setCustomMapStyles(map, config) { 169 | // Create a MapTileService instance to request base tiles (i.e. base.map.api.here.com): 170 | var mapTileService = heremaps.platform.getMapTileService({ 'type': 'base' }); 171 | 172 | // Create a tile layer which requests map tiles 173 | var newStyleLayer = mapTileService.createTileLayer( 174 | 'maptile', 175 | config.scheme || 'normal.day', 176 | config.size || 256, 177 | config.format || 'png8', 178 | config.metadataQueryParams || {} 179 | ); 180 | 181 | // Set new style layer as a base layer on the map: 182 | map.setBaseLayer(newStyleLayer); 183 | } 184 | 185 | function MapProxy() { 186 | return { 187 | refresh: function () { 188 | var currentBounds = this.getViewBounds(); 189 | 190 | this.setMapSizes(); 191 | this.setViewBounds(currentBounds); 192 | }, 193 | setMapSizes: function (height, width) { 194 | _resizeHandler.apply(null, arguments); 195 | }, 196 | getPlatform: function () { 197 | return heremaps; 198 | }, 199 | calculateRoute: function (driveType, direction) { 200 | return HereMapsRoutesService.calculateRoute(heremaps, { 201 | driveType: driveType, 202 | direction: direction 203 | }); 204 | }, 205 | addRouteToMap: function (routeData, clean) { 206 | HereMapsRoutesService.addRouteToMap(heremaps.map, routeData, clean); 207 | }, 208 | setZoom: function (zoom, step) { 209 | HereMapsUtilsService.zoom(heremaps.map, zoom || 10, step); 210 | }, 211 | getZoom: function () { 212 | return heremaps.map.getZoom(); 213 | }, 214 | getCenter: function () { 215 | return heremaps.map.getCenter(); 216 | }, 217 | getViewBounds: function () { 218 | return heremaps.map.getViewBounds(); 219 | }, 220 | setViewBounds: function (boundingRect, opt_animate) { 221 | HereMapsMarkerService.setViewBounds(heremaps.map, boundingRect, opt_animate); 222 | }, 223 | getBoundsRectFromPoints: function (topLeft, bottomRight) { 224 | return HereMapsUtilsService.getBoundsRectFromPoints.apply(null, arguments); 225 | }, 226 | setCenter: function (coords, opt_animate) { 227 | if (!coords) { 228 | return console.error('coords are not specified!'); 229 | } 230 | 231 | heremaps.map.setCenter(coords, opt_animate); 232 | }, 233 | cleanRoutes: function () { 234 | HereMapsRoutesService.cleanRoutes(heremaps.map); 235 | }, 236 | 237 | /** 238 | * @param {Boolean} enableHighAccuracy 239 | * @param {Number} maximumAge - the maximum age in milliseconds of a possible cached position that is acceptable to return. If set to 0, it means that the device cannot use a cached position and must attempt to retrieve the real current position 240 | * @return {Promise} 241 | */ 242 | getUserLocation: function (enableHighAccuracy, maximumAge) { 243 | return _getLocation.apply(null, arguments).then(function (position) { 244 | var coords = position.coords; 245 | 246 | return { 247 | lat: coords.latitude, 248 | lng: coords.longitude 249 | }; 250 | }) 251 | }, 252 | geocodePosition: function (coords, options) { 253 | return HereMapsAPIService.geocodePosition(heremaps.platform, { 254 | coords: coords, 255 | radius: options && options.radius, 256 | lang: options && options.lang 257 | }); 258 | }, 259 | geocodeAddress: function (address) { 260 | return HereMapsAPIService.geocodeAddress(heremaps.platform, { 261 | searchtext: address && address.searchtext, 262 | country: address && address.country, 263 | city: address && address.city, 264 | street: address && address.street, 265 | housenumber: address && address.housenumber 266 | }); 267 | }, 268 | geocodeAutocomplete: function (query, options) { 269 | return HereMapsAPIService.geocodeAutocomplete({ 270 | query: query, 271 | beginHighlight: options && options.beginHighlight, 272 | endHighlight: options && options.endHighlight, 273 | maxresults: options && options.maxresults 274 | }); 275 | }, 276 | findLocationById: function (locationId) { 277 | return HereMapsAPIService.findLocationById(locationId); 278 | }, 279 | updateMarkers: function (places, refreshViewbounds) { 280 | HereMapsMarkerService.updateMarkers(heremaps.map, places, refreshViewbounds); 281 | }, 282 | getMapFactory: function (){ 283 | return HereMapsUtilsService.getMapFactory(); 284 | } 285 | } 286 | } 287 | 288 | } 289 | }; 290 | -------------------------------------------------------------------------------- /src/heremaps.directive.spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Dmytro on 4/11/2016. 3 | */ 4 | 5 | describe('Here Maps directive', function () { 6 | var scope, $compile, $rootScope, $timeout, 7 | template = angular.element('
'); 8 | 9 | 10 | beforeEach(function(){ 11 | angular.mock.module('heremaps'); 12 | 13 | inject(function (_$compile_, _$rootScope_, _$timeout_) { 14 | $compile = _$compile_; 15 | $timeout = _$timeout_; 16 | $rootScope = _$rootScope_; 17 | $scope = $rootScope.$new(); 18 | }) 19 | 20 | }); 21 | 22 | it('Should compile a directive', function () { 23 | var result = $compile(template)($scope); 24 | $timeout.flush(); 25 | $scope.$digest(); 26 | expect(result[0].outerHTML).toBe('
'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | require('./providers/markers'); 2 | require('./providers/map-modules'); 3 | require('./providers/routes'); 4 | 5 | module.exports = angular.module('heremaps', [ 6 | 'heremaps-markers-module', 7 | 'heremaps-routes-module', 8 | 'heremaps-map-modules' 9 | ]) 10 | .provider('HereMapsConfig', require('./providers/mapconfig.provider')) 11 | .service('HereMapsUtilsService', require('./providers/maputils.service')) 12 | .service('HereMapsAPIService', require('./providers/api.service')) 13 | .constant('HereMapsCONSTS', require('./providers/consts')) 14 | .directive('heremaps', require('./heremaps.directive')); 15 | -------------------------------------------------------------------------------- /src/providers/api.service.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsAPIService; 2 | 3 | HereMapsAPIService.$inject = [ 4 | '$q', 5 | '$http', 6 | 'HereMapsConfig', 7 | 'HereMapsUtilsService', 8 | 'HereMapsCONSTS' 9 | ]; 10 | function HereMapsAPIService($q, $http, HereMapsConfig, HereMapsUtilsService, HereMapsCONSTS) { 11 | var version = HereMapsConfig.apiVersion, 12 | protocol = HereMapsConfig.useHTTPS ? 'https' : 'http'; 13 | 14 | var API_VERSION = { 15 | V: parseInt(version), 16 | SUB: version 17 | }; 18 | 19 | var CONFIG = { 20 | BASE: "://js.api.here.com/v", 21 | CORE: "mapsjs-core.js", 22 | SERVICE: "mapsjs-service.js", 23 | UI: { 24 | src: "mapsjs-ui.js", 25 | href: "mapsjs-ui.css" 26 | }, 27 | EVENTS: "mapsjs-mapevents.js", 28 | AUTOCOMPLETE_URL: "://autocomplete.geocoder.cit.api.here.com/6.2/suggest.json", 29 | LOCATION_URL: "://geocoder.cit.api.here.com/6.2/geocode.json" 30 | }; 31 | 32 | var API_DEFERSQueue = {}; 33 | 34 | API_DEFERSQueue[CONFIG.CORE] = []; 35 | API_DEFERSQueue[CONFIG.SERVICE] = []; 36 | API_DEFERSQueue[CONFIG.UI.src] = []; 37 | API_DEFERSQueue[CONFIG.PANO] = []; 38 | API_DEFERSQueue[CONFIG.EVENTS] = []; 39 | 40 | var head = document.getElementsByTagName('head')[0]; 41 | 42 | return { 43 | loadApi: loadApi, 44 | loadModules: loadModules, 45 | getPosition: getPosition, 46 | geocodePosition: geocodePosition, 47 | geocodeAddress: geocodeAddress, 48 | geocodeAutocomplete: geocodeAutocomplete, 49 | findLocationById: findLocationById 50 | }; 51 | 52 | //#region PUBLIC 53 | function loadApi() { 54 | return _getLoader(CONFIG.CORE) 55 | .then(function () { 56 | return _getLoader(CONFIG.SERVICE); 57 | }); 58 | } 59 | 60 | function loadModules(attrs, handlers) { 61 | for (var key in handlers) { 62 | if (!handlers.hasOwnProperty(key) || !attrs[key]) 63 | continue; 64 | 65 | var loader = _getLoaderByAttr(key); 66 | 67 | loader() 68 | .then(handlers[key]); 69 | } 70 | } 71 | 72 | function getPosition(options) { 73 | var deferred = $q.defer(); 74 | 75 | if (options && HereMapsUtilsService.isValidCoords(options.coords)) { 76 | deferred.resolve({ coords: options.coords }); 77 | } else { 78 | navigator.geolocation.getCurrentPosition(function (response) { 79 | deferred.resolve(response); 80 | }, function (error) { 81 | deferred.reject(error); 82 | }, options); 83 | } 84 | 85 | return deferred.promise; 86 | } 87 | 88 | function geocodePosition(platform, params) { 89 | if (!params.coords) 90 | return console.error('Missed required coords'); 91 | 92 | var geocoder = platform.getGeocodingService(), 93 | deferred = $q.defer(), 94 | _params = { 95 | prox: [params.coords.lat, params.coords.lng, params.radius || 250].join(','), 96 | mode: 'retrieveAddresses', 97 | maxresults: '1', 98 | gen: '8', 99 | language: params.lang || 'en-gb' 100 | }; 101 | 102 | geocoder.reverseGeocode(_params, function (response) { 103 | deferred.resolve(response) 104 | }, function (error) { 105 | deferred.reject(error) 106 | }); 107 | 108 | return deferred.promise; 109 | } 110 | 111 | function geocodeAddress(platform, params) { 112 | if (!params) 113 | return console.error('Missed required parameters'); 114 | 115 | var geocoder = platform.getGeocodingService(), 116 | deferred = $q.defer(), 117 | _params = { gen: 8 }; 118 | 119 | for (var key in params) { _params[key] = params[key]; } 120 | 121 | geocoder.geocode(_params, function (response) { 122 | deferred.resolve(response) 123 | }, function (error) { 124 | deferred.reject(error) 125 | }); 126 | 127 | return deferred.promise; 128 | } 129 | 130 | function geocodeAutocomplete(params) { 131 | if (!params) 132 | return console.error('Missing required parameters'); 133 | 134 | var autocompleteUrl = protocol + CONFIG.AUTOCOMPLETE_URL, 135 | deferred = $q.defer(), 136 | _params = { 137 | query: "", 138 | beginHighlight: "", 139 | endHighlight: "", 140 | maxresults: "5" 141 | }; 142 | 143 | for (var key in _params) { 144 | if (angular.isDefined(params[key])) { 145 | _params[key] = params[key]; 146 | } 147 | } 148 | 149 | _params.app_id = HereMapsConfig.app_id; 150 | _params.app_code = HereMapsConfig.app_code; 151 | 152 | $http.get(autocompleteUrl, { params: _params }) 153 | .success(function(response) { 154 | deferred.resolve(response); 155 | }) 156 | .error(function(error) { 157 | deferred.reject(error); 158 | }); 159 | 160 | return deferred.promise; 161 | } 162 | 163 | /** 164 | * Finds location by HERE Maps Location identifier. 165 | */ 166 | function findLocationById(locationId) { 167 | if (!locationId) 168 | return console.error('Missing Location Identifier'); 169 | 170 | var locationUrl = protocol + CONFIG.LOCATION_URL, 171 | deferred = $q.defer(), 172 | _params = { 173 | locationid: locationId, 174 | gen: 9, 175 | app_id: HereMapsConfig.app_id, 176 | app_code: HereMapsConfig.app_code 177 | }; 178 | 179 | $http.get(locationUrl, { params: _params }) 180 | .success(function(response) { 181 | deferred.resolve(response); 182 | }) 183 | .error(function(error) { 184 | deferred.reject(error); 185 | }); 186 | 187 | return deferred.promise; 188 | } 189 | 190 | //#endregion PUBLIC 191 | 192 | function _getLoaderByAttr(attr) { 193 | var loader; 194 | 195 | switch (attr) { 196 | case HereMapsCONSTS.MODULES.UI: 197 | loader = _loadUIModule; 198 | break; 199 | case HereMapsCONSTS.MODULES.EVENTS: 200 | loader = _loadEventsModule; 201 | break; 202 | default: 203 | throw new Error('Unknown module', attr); 204 | } 205 | 206 | return loader; 207 | } 208 | 209 | function _loadUIModule() { 210 | if (!_isLoaded(CONFIG.UI.src)) { 211 | var link = HereMapsUtilsService.createLinkTag({ 212 | rel: 'stylesheet', 213 | type: 'text/css', 214 | href: _getURL(CONFIG.UI.href) 215 | }); 216 | 217 | link && head.appendChild(link); 218 | } 219 | 220 | return _getLoader(CONFIG.UI.src); 221 | } 222 | 223 | function _loadEventsModule() { 224 | return _getLoader(CONFIG.EVENTS); 225 | } 226 | 227 | /** 228 | * @param {String} sourceName 229 | * return {String} e.g http://js.api.here.com/v{VER}/{SUBVERSION}/{SOURCE} 230 | */ 231 | function _getURL(sourceName) { 232 | return [ 233 | protocol, 234 | CONFIG.BASE, 235 | API_VERSION.V, 236 | "/", 237 | API_VERSION.SUB, 238 | "/", 239 | sourceName 240 | ].join(""); 241 | } 242 | 243 | function _getLoader(sourceName) { 244 | var defer = $q.defer(), src, script; 245 | 246 | if (_isLoaded(sourceName)) { 247 | defer.resolve(); 248 | } else { 249 | src = _getURL(sourceName); 250 | script = HereMapsUtilsService.createScriptTag({ src: src }); 251 | 252 | script && head.appendChild(script); 253 | 254 | API_DEFERSQueue[sourceName].push(defer); 255 | 256 | script.onload = _onLoad.bind(null, sourceName); 257 | script.onerror = _onError.bind(null, sourceName); 258 | } 259 | 260 | return defer.promise; 261 | } 262 | 263 | function _isLoaded(sourceName) { 264 | var checker = null; 265 | 266 | switch (sourceName) { 267 | case CONFIG.CORE: 268 | checker = _isCoreLoaded; 269 | break; 270 | case CONFIG.SERVICE: 271 | checker = _isServiceLoaded; 272 | break; 273 | case CONFIG.UI.src: 274 | checker = _isUILoaded; 275 | break; 276 | case CONFIG.EVENTS: 277 | checker = _isEventsLoaded; 278 | break; 279 | default: 280 | checker = function () { return false }; 281 | } 282 | 283 | return checker(); 284 | } 285 | 286 | function _isCoreLoaded() { 287 | return !!window.H; 288 | } 289 | 290 | function _isServiceLoaded() { 291 | return !!(window.H && window.H.service); 292 | } 293 | 294 | function _isUILoaded() { 295 | return !!(window.H && window.H.ui); 296 | } 297 | 298 | function _isEventsLoaded() { 299 | return !!(window.H && window.H.mapevents); 300 | } 301 | 302 | function _onLoad(sourceName) { 303 | var deferQueue = API_DEFERSQueue[sourceName]; 304 | for (var i = 0, l = deferQueue.length; i < l; ++i) { 305 | var defer = deferQueue[i]; 306 | defer.resolve(); 307 | } 308 | 309 | API_DEFERSQueue[sourceName] = []; 310 | } 311 | 312 | function _onError(sourceName) { 313 | var deferQueue = API_DEFERSQueue[sourceName]; 314 | for (var i = 0, l = deferQueue.length; i < l; ++i) { 315 | var defer = deferQueue[i]; 316 | defer.reject(); 317 | } 318 | 319 | API_DEFERSQueue[sourceName] = []; 320 | } 321 | }; 322 | -------------------------------------------------------------------------------- /src/providers/consts.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | UPDATE_MAP_RESIZE_TIMEOUT: 500, 3 | ANIMATION_ZOOM_STEP: .05, 4 | MODULES: { 5 | UI: 'controls', 6 | EVENTS: 'events', 7 | PANO: 'pano' 8 | }, 9 | DEFAULT_MAP_OPTIONS: { 10 | height: 480, 11 | width: 640, 12 | zoom: 12, 13 | maxZoom: 2, 14 | resize: false, 15 | draggable: false, 16 | coords: { 17 | longitude: 0, 18 | latitude: 0 19 | } 20 | }, 21 | MARKER_TYPES: { 22 | DOM: "DOM", 23 | SVG: "SVG" 24 | }, 25 | CONTROLS: { 26 | NAMES: { 27 | SCALE: 'scalebar', 28 | SETTINGS: 'mapsettings', 29 | ZOOM: 'zoom', 30 | USER: 'userposition' 31 | }, 32 | POSITIONS: [ 33 | 'top-right', 34 | 'top-center', 35 | 'top-left', 36 | 'left-top', 37 | 'left-middle', 38 | 'left-bottom', 39 | 'right-top', 40 | 'right-middle', 41 | 'right-bottom', 42 | 'bottom-right', 43 | 'bottom-center', 44 | 'bottom-left' 45 | ] 46 | }, 47 | INFOBUBBLE: { 48 | STATE: { 49 | OPEN: 'open', 50 | CLOSED: 'closed' 51 | }, 52 | DISPLAY_EVENT: { 53 | pointermove: 'onHover', 54 | tap: 'onClick' 55 | } 56 | }, 57 | USER_EVENTS: { 58 | tap: 'click', 59 | pointermove: 'mousemove', 60 | pointerleave: 'mouseleave', 61 | pointerenter: 'mouseenter', 62 | drag: 'drag', 63 | dragstart: 'dragstart', 64 | dragend: 'dragend', 65 | mapviewchange: 'mapviewchange', 66 | mapviewchangestart: 'mapviewchangestart', 67 | mapviewchangeend: 'mapviewchangeend' 68 | } 69 | } -------------------------------------------------------------------------------- /src/providers/map-modules/events/events.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsEventsFactory; 2 | 3 | HereMapsEventsFactory.$inject = [ 4 | 'HereMapsUtilsService', 5 | 'HereMapsMarkerService', 6 | 'HereMapsCONSTS', 7 | 'HereMapsInfoBubbleFactory' 8 | ]; 9 | function HereMapsEventsFactory(HereMapsUtilsService, HereMapsMarkerService, HereMapsCONSTS, HereMapsInfoBubbleFactory) { 10 | function Events(platform, Injector, listeners) { 11 | this.map = platform.map; 12 | this.listeners = listeners; 13 | this.inject = new Injector(); 14 | this.events = platform.events = new H.mapevents.MapEvents(this.map); 15 | this.behavior = platform.behavior = new H.mapevents.Behavior(this.events); 16 | this.bubble = HereMapsInfoBubbleFactory.create(); 17 | 18 | this.setupEventListeners(); 19 | } 20 | 21 | var proto = Events.prototype; 22 | 23 | proto.setupEventListeners = setupEventListeners; 24 | proto.setupOptions = setupOptions; 25 | proto.triggerUserListener = triggerUserListener; 26 | proto.infoBubbleHandler = infoBubbleHandler; 27 | 28 | return { 29 | start: function(args) { 30 | if (!(args.platform.map instanceof H.Map)) 31 | return console.error('Missed required map instance'); 32 | 33 | var events = new Events(args.platform, args.injector, args.listeners); 34 | 35 | args.options && events.setupOptions(args.options); 36 | } 37 | } 38 | 39 | function setupEventListeners() { 40 | var self = this; 41 | 42 | HereMapsUtilsService.addEventListener(this.map, 'tap', this.infoBubbleHandler.bind(this)); 43 | 44 | HereMapsUtilsService.addEventListener(this.map, 'pointermove', this.infoBubbleHandler.bind(this)); 45 | 46 | HereMapsUtilsService.addEventListener(this.map, 'dragstart', function(e) { 47 | if (HereMapsMarkerService.isMarkerInstance(e.target)) { 48 | self.behavior.disable(); 49 | } 50 | 51 | self.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 52 | }); 53 | 54 | HereMapsUtilsService.addEventListener(this.map, 'drag', function(e) { 55 | var pointer = e.currentPointer, 56 | target = e.target; 57 | 58 | if (HereMapsMarkerService.isMarkerInstance(target)) { 59 | target.setPosition(self.map.screenToGeo(pointer.viewportX, pointer.viewportY)); 60 | } 61 | 62 | self.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 63 | }); 64 | 65 | HereMapsUtilsService.addEventListener(this.map, 'dragend', function(e) { 66 | if (HereMapsMarkerService.isMarkerInstance(e.target)) { 67 | self.behavior.enable(); 68 | } 69 | 70 | self.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 71 | }); 72 | 73 | HereMapsUtilsService.addEventListener(this.map, 'mapviewchangestart', function(e) { 74 | self.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 75 | }); 76 | 77 | HereMapsUtilsService.addEventListener(this.map, 'mapviewchange', function(e) { 78 | self.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 79 | }); 80 | 81 | HereMapsUtilsService.addEventListener(this.map, 'mapviewchangeend', function(e) { 82 | self.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 83 | }); 84 | } 85 | 86 | function setupOptions(options) { 87 | if (!options) 88 | return; 89 | 90 | this.map.draggable = !!options.draggable; 91 | } 92 | 93 | function triggerUserListener(eventName, e) { 94 | if (!this.listeners) 95 | return; 96 | 97 | var callback = this.listeners[eventName]; 98 | 99 | callback && callback(e); 100 | } 101 | 102 | function infoBubbleHandler(e){ 103 | var ui = this.inject('ui'); 104 | 105 | if(ui) 106 | this.bubble.toggle(e, ui); 107 | 108 | this.triggerUserListener(HereMapsCONSTS.USER_EVENTS[e.type], e); 109 | } 110 | 111 | }; -------------------------------------------------------------------------------- /src/providers/map-modules/events/infobubble.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsInfoBubbleFactory; 2 | 3 | HereMapsInfoBubbleFactory.$inject = [ 4 | 'HereMapsMarkerService', 5 | 'HereMapsUtilsService', 6 | 'HereMapsCONSTS' 7 | ]; 8 | function HereMapsInfoBubbleFactory(HereMapsMarkerService, HereMapsUtilsService, HereMapsCONSTS) { 9 | function InfoBubble() {} 10 | 11 | var proto = InfoBubble.prototype; 12 | 13 | proto.create = create; 14 | proto.update = update; 15 | proto.toggle = toggle; 16 | proto.show = show; 17 | proto.close = close; 18 | 19 | return { 20 | create: function(){ 21 | return new InfoBubble(); 22 | } 23 | } 24 | 25 | function toggle(e, ui) { 26 | if (HereMapsMarkerService.isMarkerInstance(e.target)) 27 | this.show(e, ui); 28 | else 29 | this.close(e, ui); 30 | } 31 | 32 | function update(bubble, data) { 33 | bubble.display = data.display; 34 | 35 | bubble.setPosition(data.position); 36 | bubble.setContent(data.markup); 37 | 38 | bubble.setState(HereMapsCONSTS.INFOBUBBLE.STATE.OPEN); 39 | } 40 | 41 | function create(source) { 42 | var bubble = new H.ui.InfoBubble(source.position, { 43 | content: source.markup 44 | }); 45 | 46 | bubble.display = source.display; 47 | bubble.addClass(HereMapsCONSTS.INFOBUBBLE.STATE.OPEN) 48 | 49 | HereMapsUtilsService.addEventListener(bubble, 'statechange', function(e) { 50 | var state = this.getState(), 51 | el = this.getElement(); 52 | if (state === HereMapsCONSTS.INFOBUBBLE.STATE.CLOSED) { 53 | el.classList.remove(HereMapsCONSTS.INFOBUBBLE.STATE.OPEN); 54 | } else 55 | this.addClass(state) 56 | }); 57 | 58 | return bubble; 59 | } 60 | 61 | function show(e, ui, data) { 62 | var target = e.target, 63 | data = target.getData(), 64 | el = null; 65 | 66 | if (!data || !data.display || !data.markup || data.display !== HereMapsCONSTS.INFOBUBBLE.DISPLAY_EVENT[e.type]) 67 | return; 68 | 69 | var source = { 70 | position: target.getPosition(), 71 | markup: data.markup, 72 | display: data.display 73 | }; 74 | 75 | if (!ui.bubble) { 76 | ui.bubble = this.create(source); 77 | ui.addBubble(ui.bubble); 78 | 79 | return; 80 | } 81 | 82 | this.update(ui.bubble, source); 83 | } 84 | 85 | function close(e, ui) { 86 | if (!ui.bubble || ui.bubble.display !== HereMapsCONSTS.INFOBUBBLE.DISPLAY_EVENT[e.type]) { 87 | return; 88 | } 89 | 90 | ui.bubble.setState(HereMapsCONSTS.INFOBUBBLE.STATE.CLOSED); 91 | } 92 | } -------------------------------------------------------------------------------- /src/providers/map-modules/index.js: -------------------------------------------------------------------------------- 1 | angular.module('heremaps-events-module', []) 2 | .factory('HereMapsEventsFactory', require('./events/events.js')) 3 | .factory('HereMapsInfoBubbleFactory', require('./events/infobubble.js')); 4 | 5 | angular.module('heremaps-ui-module', []) 6 | .factory('HereMapsUiFactory', require('./ui/ui.js')) 7 | 8 | module.exports = angular.module('heremaps-map-modules', [ 9 | 'heremaps-events-module', 10 | 'heremaps-ui-module' 11 | ]); -------------------------------------------------------------------------------- /src/providers/map-modules/ui/ui.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsUiFactory; 2 | 3 | HereMapsUiFactory.$inject = [ 4 | 'HereMapsAPIService', 5 | 'HereMapsMarkerService', 6 | 'HereMapsUtilsService', 7 | 'HereMapsCONSTS' 8 | ]; 9 | function HereMapsUiFactory(HereMapsAPIService, HereMapsMarkerService, HereMapsUtilsService, HereMapsCONSTS) { 10 | function UI(platform, alignment) { 11 | this.map = platform.map; 12 | this.layers = platform.layers; 13 | this.alignment = alignment; 14 | this.ui = platform.ui = H.ui.UI.createDefault(this.map, this.layers); 15 | 16 | this.setupControls(); 17 | } 18 | 19 | UI.isValidAlignment = isValidAlignment; 20 | 21 | var proto = UI.prototype; 22 | 23 | proto.setupControls = setupControls; 24 | proto.createUserControl = createUserControl; 25 | proto.setControlsAlignment = setControlsAlignment; 26 | 27 | return { 28 | start: function(args) { 29 | if (!(args.platform.map instanceof H.Map) && !(args.platform.layers)) 30 | return console.error('Missed ui module dependencies'); 31 | 32 | var ui = new UI(args.platform, args.alignment); 33 | } 34 | } 35 | 36 | function setupControls() { 37 | var NAMES = HereMapsCONSTS.CONTROLS.NAMES, 38 | userControl = this.createUserControl(); 39 | 40 | this.ui.getControl(NAMES.SETTINGS).setIncidentsLayer(false); 41 | this.ui.addControl(NAMES.USER, userControl); 42 | this.setControlsAlignment(NAMES); 43 | } 44 | 45 | function createUserControl() { 46 | var self = this, 47 | userControl = new H.ui.Control(), 48 | markup = ''; 49 | 50 | var userControlButton = new H.ui.base.Button({ 51 | label: markup, 52 | onStateChange: function(evt) { 53 | if (userControlButton.getState() === H.ui.base.Button.State.DOWN) 54 | return; 55 | 56 | HereMapsAPIService.getPosition().then(function(response) { 57 | var position = { 58 | lng: response.coords.longitude, 59 | lat: response.coords.latitude 60 | }; 61 | 62 | self.map.setCenter(position); 63 | 64 | HereMapsUtilsService.zoom(self.map, 17, .08); 65 | 66 | if (self.userMarker) { 67 | self.userMarker.setPosition(position); 68 | return; 69 | } 70 | 71 | self.userMarker = HereMapsMarkerService.addUserMarker(self.map, { 72 | pos: position 73 | }); 74 | }); 75 | } 76 | }); 77 | 78 | userControl.addChild(userControlButton); 79 | 80 | return userControl; 81 | } 82 | 83 | function setControlsAlignment(NAMES) { 84 | if (!UI.isValidAlignment(this.alignment)) 85 | return; 86 | 87 | for (var id in NAMES) { 88 | var control = this.ui.getControl(NAMES[id]); 89 | 90 | if (!NAMES.hasOwnProperty(id) || !control) 91 | continue; 92 | 93 | control.setAlignment(this.alignment); 94 | } 95 | } 96 | 97 | function isValidAlignment(alignment) { 98 | return !!(HereMapsCONSTS.CONTROLS.POSITIONS.indexOf(alignment) + 1); 99 | } 100 | 101 | }; -------------------------------------------------------------------------------- /src/providers/mapconfig.provider.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | var options = {}; 3 | var DEFAULT_API_VERSION = "3.0"; 4 | 5 | this.$get = function(){ 6 | return { 7 | app_id: options.app_id, 8 | app_code: options.app_code, 9 | apiVersion: options.apiVersion || DEFAULT_API_VERSION, 10 | useHTTPS: options.useHTTPS, 11 | useCIT: !!options.useCIT, 12 | mapTileConfig: options.mapTileConfig 13 | } 14 | }; 15 | 16 | this.setOptions = function(opts){ 17 | options = opts; 18 | }; 19 | }; -------------------------------------------------------------------------------- /src/providers/maputils.service.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = HereMapsUtilsService; 3 | 4 | HereMapsUtilsService.$inject = [ 5 | '$rootScope', 6 | '$timeout', 7 | 'HereMapsCONSTS' 8 | ]; 9 | function HereMapsUtilsService($rootScope, $timeout, HereMapsCONSTS) { 10 | return { 11 | throttle: throttle, 12 | createScriptTag: createScriptTag, 13 | createLinkTag: createLinkTag, 14 | runScopeDigestIfNeed: runScopeDigestIfNeed, 15 | isValidCoords: isValidCoords, 16 | addEventListener: addEventListener, 17 | zoom: zoom, 18 | getBoundsRectFromPoints: getBoundsRectFromPoints, 19 | generateId: generateId, 20 | getMapFactory: getMapFactory 21 | }; 22 | 23 | //#region PUBLIC 24 | function throttle(fn, period) { 25 | var timeout = null; 26 | 27 | return function () { 28 | if ($timeout) 29 | $timeout.cancel(timeout); 30 | 31 | timeout = $timeout(fn, period); 32 | } 33 | } 34 | 35 | function addEventListener(obj, eventName, listener, useCapture) { 36 | obj.addEventListener(eventName, listener, !!useCapture); 37 | } 38 | 39 | function runScopeDigestIfNeed(scope, cb) { 40 | if (scope.$root && scope.$root.$$phase !== '$apply' && scope.$root.$$phase !== '$digest') { 41 | scope.$digest(cb || angular.noop); 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | function createScriptTag(attrs) { 48 | var script = document.getElementById(attrs.src); 49 | 50 | if (script) 51 | return false; 52 | 53 | script = document.createElement('script'); 54 | script.type = 'text/javascript'; 55 | script.id = attrs.src; 56 | _setAttrs(script, attrs); 57 | 58 | return script; 59 | } 60 | 61 | function createLinkTag(attrs) { 62 | var link = document.getElementById(attrs.href); 63 | 64 | if (link) 65 | return false; 66 | 67 | link = document.createElement('link'); 68 | link.id = attrs.href; 69 | _setAttrs(link, attrs); 70 | 71 | return link; 72 | } 73 | 74 | function isValidCoords(coords) { 75 | return coords && 76 | (typeof coords.latitude === 'string' || typeof coords.latitude === 'number') && 77 | (typeof coords.longitude === 'string' || typeof coords.longitude === 'number') 78 | } 79 | 80 | function zoom(map, value, step) { 81 | var currentZoom = map.getZoom(), 82 | _step = step || HereMapsCONSTS.ANIMATION_ZOOM_STEP, 83 | factor = currentZoom >= value ? -1 : 1, 84 | increment = step * factor; 85 | 86 | return (function zoom() { 87 | if (!step || Math.floor(currentZoom) === Math.floor(value)) { 88 | map.setZoom(value); 89 | return; 90 | } 91 | 92 | currentZoom += increment; 93 | map.setZoom(currentZoom); 94 | 95 | requestAnimationFrame(zoom); 96 | })(); 97 | } 98 | 99 | function getMapFactory(){ 100 | return H; 101 | } 102 | 103 | /** 104 | * @method getBoundsRectFromPoints 105 | * 106 | * @param {Object} topLeft 107 | * @property {Number|String} lat 108 | * @property {Number|String} lng 109 | * @param {Object} bottomRight 110 | * @property {Number|String} lat 111 | * @property {Number|String} lng 112 | * 113 | * @return {H.geo.Rect} 114 | */ 115 | function getBoundsRectFromPoints(topLeft, bottomRight) { 116 | return H.geo.Rect.fromPoints(topLeft, bottomRight, true); 117 | } 118 | 119 | function generateId() { 120 | var mask = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', 121 | regexp = /[xy]/g, 122 | d = new Date().getTime(), 123 | uuid = mask.replace(regexp, function (c) { 124 | var r = (d + Math.random() * 16) % 16 | 0; 125 | d = Math.floor(d / 16); 126 | return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16); 127 | }); 128 | 129 | return uuid; 130 | } 131 | 132 | //#endregion PUBLIC 133 | 134 | function _setAttrs(el, attrs) { 135 | if (!el || !attrs) 136 | throw new Error('Missed attributes'); 137 | 138 | for (var key in attrs) { 139 | if (!attrs.hasOwnProperty(key)) 140 | continue; 141 | 142 | el[key] = attrs[key]; 143 | } 144 | } 145 | }; -------------------------------------------------------------------------------- /src/providers/markers/default.marker.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsDefaultMarker; 2 | 3 | HereMapsDefaultMarker.$inject = ['HereMapsMarkerInterface']; 4 | function HereMapsDefaultMarker(HereMapsMarkerInterface){ 5 | function DefaultMarker(place){ 6 | this.place = place; 7 | this.setCoords(); 8 | } 9 | 10 | var proto = DefaultMarker.prototype = new HereMapsMarkerInterface(); 11 | proto.constructor = DefaultMarker; 12 | 13 | proto.create = create; 14 | 15 | return DefaultMarker; 16 | 17 | function create(){ 18 | var marker = new H.map.Marker(this.coords); 19 | 20 | this.addInfoBubble(marker); 21 | 22 | return marker; 23 | } 24 | } -------------------------------------------------------------------------------- /src/providers/markers/dom.marker.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsDOMMarker; 2 | 3 | HereMapsDOMMarker.$inject = ['HereMapsMarkerInterface']; 4 | function HereMapsDOMMarker(HereMapsMarkerInterface){ 5 | function DOMMarker(place){ 6 | this.place = place; 7 | this.setCoords(); 8 | } 9 | 10 | var proto = DOMMarker.prototype = new HereMapsMarkerInterface(); 11 | proto.constructor = DOMMarker; 12 | 13 | proto.create = create; 14 | proto.getIcon = getIcon; 15 | proto.setupEvents = setupEvents; 16 | 17 | return DOMMarker; 18 | 19 | function create(){ 20 | var marker = new H.map.DomMarker(this.coords, { 21 | icon: this.getIcon() 22 | }); 23 | 24 | this.addInfoBubble(marker); 25 | 26 | return marker; 27 | } 28 | 29 | function getIcon(){ 30 | var icon = this.place.markup; 31 | if(!icon) 32 | throw new Error('markup missed'); 33 | 34 | return new H.map.DomIcon(icon); 35 | } 36 | 37 | function setupEvents(el, events, remove){ 38 | var method = remove ? 'removeEventListener' : 'addEventListener'; 39 | 40 | for(var key in events) { 41 | if(!events.hasOwnProperty(key)) 42 | continue; 43 | 44 | el[method].call(null, key, events[key]); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/providers/markers/index.js: -------------------------------------------------------------------------------- 1 | module.exports = angular.module('heremaps-markers-module', []) 2 | .factory('HereMapsMarkerInterface', require('./marker.js')) 3 | .factory('HereMapsDefaultMarker', require('./default.marker.js')) 4 | .factory('HereMapsDOMMarker', require('./dom.marker.js')) 5 | .factory('HereMapsSVGMarker', require('./svg.marker.js')) 6 | .service('HereMapsMarkerService', require('./markers.service.js')); -------------------------------------------------------------------------------- /src/providers/markers/marker.js: -------------------------------------------------------------------------------- 1 | module.exports = function(){ 2 | function MarkerInterface(){ 3 | throw new Error('Abstract class! The Instance should be created'); 4 | } 5 | 6 | var proto = MarkerInterface.prototype; 7 | 8 | proto.create = create; 9 | proto.setCoords = setCoords; 10 | proto.addInfoBubble = addInfoBubble; 11 | 12 | function Marker(){} 13 | 14 | Marker.prototype = proto; 15 | 16 | return Marker; 17 | 18 | function create(){ 19 | throw new Error('create:: not implemented'); 20 | } 21 | 22 | function setCoords(){ 23 | this.coords = { 24 | lat: this.place.pos.lat, 25 | lng: this.place.pos.lng 26 | } 27 | } 28 | 29 | function addInfoBubble(marker){ 30 | if(!this.place.popup) 31 | return; 32 | 33 | marker.setData(this.place.popup) 34 | } 35 | } -------------------------------------------------------------------------------- /src/providers/markers/markers.service.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsMarkerService; 2 | 3 | HereMapsMarkerService.$inject = [ 4 | 'HereMapsDefaultMarker', 5 | 'HereMapsDOMMarker', 6 | 'HereMapsSVGMarker', 7 | 'HereMapsCONSTS' 8 | ]; 9 | function HereMapsMarkerService(HereMapsDefaultMarker, HereMapsDOMMarker, HereMapsSVGMarker, HereMapsCONSTS) { 10 | var MARKER_TYPES = HereMapsCONSTS.MARKER_TYPES; 11 | 12 | return { 13 | addMarkersToMap: addMarkersToMap, 14 | addUserMarker: addUserMarker, 15 | updateMarkers: updateMarkers, 16 | isMarkerInstance: isMarkerInstance, 17 | setViewBounds: setViewBounds 18 | } 19 | 20 | function isMarkerInstance(target) { 21 | return target instanceof H.map.Marker || target instanceof H.map.DomMarker; 22 | } 23 | 24 | function addUserMarker(map, place) { 25 | if (map.userMarker) 26 | return map.userMarker; 27 | 28 | place.markup = '' + 29 | '' + 30 | '' + 31 | '' + 32 | '' + 33 | '' + 34 | '' + 35 | '' + 36 | ''; 37 | 38 | map.userMarker = new HereMapsSVGMarker(place).create(); 39 | 40 | map.addObject(map.userMarker); 41 | 42 | return map.userMarker; 43 | } 44 | 45 | function addMarkersToMap(map, places, refreshViewbounds) { 46 | if (!places || !places.length) 47 | return; 48 | 49 | if (!(map instanceof H.Map)) 50 | throw new Error('Unsupported map instance'); 51 | 52 | if (!map.markersGroup) 53 | map.markersGroup = new H.map.Group(); 54 | 55 | places.forEach(function (place, i) { 56 | var creator = _getMarkerCreator(place), 57 | marker = place.draggable ? _draggableMarkerMixin(creator.create()) : creator.create(); 58 | 59 | map.markersGroup.addObject(marker); 60 | }); 61 | 62 | map.addObject(map.markersGroup); 63 | 64 | if (refreshViewbounds) { 65 | setViewBounds(map, map.markersGroup.getBounds()); 66 | } 67 | } 68 | 69 | function setViewBounds(map, bounds, opt_animate) { 70 | map.setViewBounds(bounds, !!opt_animate); 71 | } 72 | 73 | function updateMarkers(map, places, refreshViewbounds) { 74 | if (map.markersGroup) { 75 | map.markersGroup.removeAll(); 76 | map.removeObject(map.markersGroup); 77 | map.markersGroup = null; 78 | } 79 | 80 | addMarkersToMap.apply(null, arguments); 81 | } 82 | 83 | function _getMarkerCreator(place) { 84 | var ConcreteMarker, 85 | type = place.type ? place.type.toUpperCase() : null; 86 | 87 | switch (type) { 88 | case MARKER_TYPES.DOM: 89 | ConcreteMarker = HereMapsDOMMarker; 90 | break; 91 | case MARKER_TYPES.SVG: 92 | ConcreteMarker = HereMapsSVGMarker; 93 | break; 94 | default: 95 | ConcreteMarker = HereMapsDefaultMarker; 96 | } 97 | 98 | return new ConcreteMarker(place); 99 | } 100 | 101 | function _draggableMarkerMixin(marker) { 102 | marker.draggable = true; 103 | 104 | return marker; 105 | } 106 | }; 107 | -------------------------------------------------------------------------------- /src/providers/markers/svg.marker.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsSVGMarker; 2 | 3 | HereMapsSVGMarker.$inject = ['HereMapsMarkerInterface']; 4 | function HereMapsSVGMarker(HereMapsMarkerInterface){ 5 | function SVGMarker(place){ 6 | this.place = place; 7 | this.setCoords(); 8 | } 9 | 10 | var proto = SVGMarker.prototype = new HereMapsMarkerInterface(); 11 | proto.constructor = SVGMarker; 12 | 13 | proto.create = create; 14 | proto.getIcon = getIcon; 15 | 16 | return SVGMarker; 17 | 18 | function create(){ 19 | var marker = new H.map.Marker(this.coords, { 20 | icon: this.getIcon(), 21 | }); 22 | 23 | this.addInfoBubble(marker); 24 | 25 | return marker; 26 | } 27 | 28 | function getIcon(){ 29 | var icon = this.place.markup; 30 | if(!icon) 31 | throw new Error('markup missed'); 32 | 33 | return new H.map.Icon(icon); 34 | } 35 | } -------------------------------------------------------------------------------- /src/providers/routes/index.js: -------------------------------------------------------------------------------- 1 | module.exports = angular.module('heremaps-routes-module', []) 2 | .service('HereMapsRoutesService', require('./routes.service.js')); -------------------------------------------------------------------------------- /src/providers/routes/routes.service.js: -------------------------------------------------------------------------------- 1 | module.exports = HereMapsRoutesService; 2 | 3 | HereMapsRoutesService.$inject = ['$q', 'HereMapsMarkerService']; 4 | function HereMapsRoutesService($q, HereMapsMarkerService) { 5 | return { 6 | calculateRoute: calculateRoute, 7 | addRouteToMap: addRouteToMap, 8 | cleanRoutes: cleanRoutes 9 | } 10 | 11 | function calculateRoute(heremaps, config) { 12 | var platform = heremaps.platform, 13 | map = heremaps.map, 14 | router = platform.getRoutingService(), 15 | dir = config.direction, 16 | waypoints = dir.waypoints; 17 | 18 | var mode = '{{MODE}};{{VECHILE}}' 19 | .replace(/{{MODE}}/, dir.mode || 'fastest') 20 | .replace(/{{VECHILE}}/, config.driveType); 21 | 22 | var routeRequestParams = { 23 | mode: mode, 24 | representation: dir.representation || 'display', 25 | language: dir.language || 'en-gb' 26 | }; 27 | 28 | waypoints.forEach(function (waypoint, i) { 29 | routeRequestParams["waypoint" + i] = [waypoint.lat, waypoint.lng].join(','); 30 | }); 31 | 32 | _setAttributes(routeRequestParams, dir.attrs); 33 | 34 | var deferred = $q.defer(); 35 | 36 | router.calculateRoute(routeRequestParams, function (result) { 37 | deferred.resolve(result); 38 | }, function (error) { 39 | deferred.reject(error); 40 | }); 41 | 42 | return deferred.promise; 43 | } 44 | 45 | function cleanRoutes(map) { 46 | var group = map.routesGroup; 47 | 48 | if (!group) 49 | return; 50 | 51 | group.removeAll(); 52 | map.removeObject(group); 53 | map.routesGroup = null; 54 | } 55 | 56 | function addRouteToMap(map, routeData, clean) { 57 | if (clean) 58 | cleanRoutes(map); 59 | 60 | var route = routeData.route; 61 | 62 | if (!map || !route || !route.shape) 63 | return; 64 | 65 | var strip = new H.geo.Strip(), polyline = null; 66 | 67 | route.shape.forEach(function (point) { 68 | var parts = point.split(','); 69 | strip.pushLatLngAlt(parts[0], parts[1]); 70 | }); 71 | 72 | var style = routeData.style || {}; 73 | 74 | polyline = new H.map.Polyline(strip, { 75 | style: { 76 | lineWidth: style.lineWidth || 4, 77 | strokeColor: style.color || 'rgba(0, 128, 255, 0.7)' 78 | } 79 | }); 80 | 81 | var group = map.routesGroup; 82 | 83 | if (!group) { 84 | group = map.routesGroup = new H.map.Group(); 85 | map.addObject(group); 86 | } 87 | 88 | group.addObject(polyline); 89 | 90 | if(routeData.zoomToBounds) { 91 | HereMapsMarkerService.setViewBounds(map, polyline.getBounds(), true); 92 | } 93 | } 94 | 95 | //#region PRIVATE 96 | 97 | function _setAttributes(params, attrs) { 98 | var _key = 'attributes'; 99 | for (var key in attrs) { 100 | if (!attrs.hasOwnProperty(key)) 101 | continue; 102 | 103 | params[key + _key] = attrs[key]; 104 | } 105 | } 106 | 107 | /** 108 | * Creates a series of H.map.Marker points from the route and adds them to the map. 109 | * @param {Object} route A route as received from the H.service.RoutingService 110 | */ 111 | function addManueversToMap(map, route) { 112 | var svgMarkup = '' + 114 | '' + 116 | '', 117 | dotIcon = new H.map.Icon(svgMarkup, { anchor: { x: 8, y: 8 } }), 118 | group = new H.map.Group(), i, j; 119 | 120 | // Add a marker for each maneuver 121 | for (i = 0; i < route.leg.length; i += 1) { 122 | for (j = 0; j < route.leg[i].maneuver.length; j += 1) { 123 | // Get the next maneuver. 124 | maneuver = route.leg[i].maneuver[j]; 125 | // Add a marker to the maneuvers group 126 | var marker = new H.map.Marker({ 127 | lat: maneuver.position.latitude, 128 | lng: maneuver.position.longitude 129 | }, 130 | { icon: dotIcon } 131 | ); 132 | 133 | marker.instruction = maneuver.instruction; 134 | group.addObject(marker); 135 | } 136 | } 137 | 138 | group.addEventListener('tap', function (evt) { 139 | map.setCenter(evt.target.getPosition()); 140 | openBubble(evt.target.getPosition(), evt.target.instruction); 141 | }, false); 142 | 143 | // Add the maneuvers group to the map 144 | map.addObject(group); 145 | } 146 | 147 | 148 | /** 149 | * Creates a series of H.map.Marker points from the route and adds them to the map. 150 | * @param {Object} route A route as received from the H.service.RoutingService 151 | */ 152 | function addWaypointsToPanel(waypoints) { 153 | var nodeH3 = document.createElement('h3'), 154 | waypointLabels = [], 155 | i; 156 | 157 | for (i = 0; i < waypoints.length; i += 1) { 158 | waypointLabels.push(waypoints[i].label) 159 | } 160 | 161 | nodeH3.textContent = waypointLabels.join(' - '); 162 | 163 | routeInstructionsContainer.innerHTML = ''; 164 | routeInstructionsContainer.appendChild(nodeH3); 165 | } 166 | 167 | /** 168 | * Creates a series of H.map.Marker points from the route and adds them to the map. 169 | * @param {Object} route A route as received from the H.service.RoutingService 170 | */ 171 | function addSummaryToPanel(summary) { 172 | var summaryDiv = document.createElement('div'), 173 | content = ''; 174 | 175 | content += 'Total distance: ' + summary.distance + 'm.
'; 176 | content += 'Travel Time: ' + summary.travelTime.toMMSS() + ' (in current traffic)'; 177 | 178 | 179 | summaryDiv.style.fontSize = 'small'; 180 | summaryDiv.style.marginLeft = '5%'; 181 | summaryDiv.style.marginRight = '5%'; 182 | summaryDiv.innerHTML = content; 183 | routeInstructionsContainer.appendChild(summaryDiv); 184 | } 185 | 186 | /** 187 | * Creates a series of H.map.Marker points from the route and adds them to the map. 188 | * @param {Object} route A route as received from the H.service.RoutingService 189 | */ 190 | function addManueversToPanel(route) { 191 | var nodeOL = document.createElement('ol'), i, j; 192 | 193 | nodeOL.style.fontSize = 'small'; 194 | nodeOL.style.marginLeft = '5%'; 195 | nodeOL.style.marginRight = '5%'; 196 | nodeOL.className = 'directions'; 197 | 198 | // Add a marker for each maneuver 199 | for (i = 0; i < route.leg.length; i += 1) { 200 | for (j = 0; j < route.leg[i].maneuver.length; j += 1) { 201 | // Get the next maneuver. 202 | maneuver = route.leg[i].maneuver[j]; 203 | 204 | var li = document.createElement('li'), 205 | spanArrow = document.createElement('span'), 206 | spanInstruction = document.createElement('span'); 207 | 208 | spanArrow.className = 'arrow ' + maneuver.action; 209 | spanInstruction.innerHTML = maneuver.instruction; 210 | li.appendChild(spanArrow); 211 | li.appendChild(spanInstruction); 212 | 213 | nodeOL.appendChild(li); 214 | } 215 | } 216 | 217 | routeInstructionsContainer.appendChild(nodeOL); 218 | } 219 | 220 | }; 221 | --------------------------------------------------------------------------------