1var ngMap = angular.module('ngMap', []); 2 3/** 4 * @ngdoc service 5 * @name Attr2Options 6 * @description 7 * Converts tag attributes to options used by google api v3 objects, map, marker, polygon, circle, etc. 8 */ 9/* global google */ 10(function() { 11 'use strict'; 12 13 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; 14 var MOZ_HACK_REGEXP = /^moz([A-Z])/; 15 16 function camelCase(name) { 17 return name. 18 replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { 19 return offset ? letter.toUpperCase() : letter; 20 }). 21 replace(MOZ_HACK_REGEXP, 'Moz$1'); 22 } 23 24 function JSONize(str) { 25 try { // if parsable already, return as it is 26 JSON.parse(str); 27 return str; 28 } catch(e) { // if not parsable, change little 29 return str 30 // wrap keys without quote with valid double quote 31 .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'}) 32 // replacing single quote wrapped ones to double quote 33 .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'}) 34 } 35 } 36 37 var Attr2Options = function($parse, $timeout, NavigatorGeolocation, GeoCoder) { 38 39 /** 40 * Returns the attributes of an element as hash 41 * @memberof Attr2Options 42 * @param {HTMLElement} el html element 43 * @returns {Hash} attributes 44 */ 45 var orgAttributes = function(el) { 46 (el.length > 0) && (el = el[0]); 47 var orgAttributes = {}; 48 for (var i=0; i<el.attributes.length; i++) { 49 var attr = el.attributes[i]; 50 orgAttributes[attr.name] = attr.value; 51 } 52 return orgAttributes; 53 }; 54 55 var toOptionValue = function(input, options) { 56 var output, key=options.key, scope=options.scope; 57 try { // 1. Number? 58 var num = Number(input); 59 if (isNaN(num)) { 60 throw "Not a number"; 61 } else { 62 output = num; 63 } 64 } catch(err) { 65 try { // 2.JSON? 66 if (input.match(/^[\+\-]?[0-9\.]+,[ ]*\ ?[\+\-]?[0-9\.]+$/)) { // i.e "-1.0, 89.89" 67 input = "["+input+"]"; 68 } 69 output = JSON.parse(JSONize(input)); 70 if (output instanceof Array) { 71 var t1stEl = output[0]; 72 if (t1stEl.constructor == Object) { // [{a:1}] : not lat/lng ones 73 } else if (t1stEl.constructor == Array) { // [[1,2],[3,4]] 74 output = output.map(function(el) { 75 return new google.maps.LatLng(el[0], el[1]); 76 }); 77 } else if(!isNaN(parseFloat(t1stEl)) && isFinite(t1stEl)) { 78 return new google.maps.LatLng(output[0], output[1]); 79 } 80 } 81 } catch(err2) { 82 // 3. Object Expression. i.e. LatLng(80,-49) 83 if (input.match(/^[A-Z][a-zA-Z0-9]+\(.*\)$/)) { 84 try { 85 var exp = "new google.maps."+input; 86 output = eval(exp); // TODO, still eval 87 } catch(e) { 88 output = input; 89 } 90 // 4. Object Expression. i.e. MayTypeId.HYBRID 91 } else if (input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/)) { 92 try { 93 var matches = input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/); 94 output = google.maps[matches[1]][matches[2]]; 95 } catch(e) { 96 output = input; 97 } 98 // 5. Object Expression. i.e. HYBRID 99 } else if (input.match(/^[A-Z]+$/)) { 100 try { 101 var capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1); 102 if (key.match(/temperatureUnit|windSpeedUnit|labelColor/)) { 103 capitalizedKey = capitalizedKey.replace(/s$/,""); 104 output = google.maps.weather[capitalizedKey][input]; 105 } else { 106 output = google.maps[capitalizedKey][input]; 107 } 108 } catch(e) { 109 output = input; 110 } 111 } else { 112 output = input; 113 } 114 } // catch(err2) 115 } // catch(err) 116 return output; 117 }; 118 119 var getAttrsToObserve = function(attrs) { 120 var attrsToObserve = []; 121 if (attrs["ng-repeat"] || attrs.ngRepeat) { // if element is created by ng-repeat, don't observe any 122 void(0); 123 } else { 124 for (var attrName in attrs) { 125 var attrValue = attrs[attrName]; 126 if (attrValue && attrValue.match(/\{\{.*\}\}/)) { // if attr value is {{..}} 127 void 0; 128 attrsToObserve.push(camelCase(attrName)); 129 } 130 } 131 } 132 return attrsToObserve; 133 }; 134 135 /** 136 * filters attributes by skipping angularjs methods $.. $$.. 137 * @memberof Attr2Options 138 * @param {Hash} attrs tag attributes 139 * @returns {Hash} filterd attributes 140 */ 141 var filter = function(attrs) { 142 var options = {}; 143 for(var key in attrs) { 144 if (key.match(/^\$/) || key.match(/^ng[A-Z]/)) { 145 void(0); 146 } else { 147 options[key] = attrs[key]; 148 } 149 } 150 return options; 151 }; 152 153 /** 154 * converts attributes hash to Google Maps API v3 options 155 * ``` 156 * . converts numbers to number 157 * . converts class-like string to google maps instance 158 * i.e. `LatLng(1,1)` to `new google.maps.LatLng(1,1)` 159 * . converts constant-like string to google maps constant 160 * i.e. `MapTypeId.HYBRID` to `google.maps.MapTypeId.HYBRID` 161 * i.e. `HYBRID"` to `google.maps.MapTypeId.HYBRID` 162 * ``` 163 * @memberof Attr2Options 164 * @param {Hash} attrs tag attributes 165 * @param {scope} scope angularjs scope 166 * @returns {Hash} options converted attributess 167 */ 168 var getOptions = function(attrs, scope) { 169 var options = {}; 170 for(var key in attrs) { 171 if (attrs[key]) { 172 if (key.match(/^on[A-Z]/)) { //skip events, i.e. on-click 173 continue; 174 } else if (key.match(/ControlOptions$/)) { // skip controlOptions 175 continue; 176 } else { 177 options[key] = toOptionValue(attrs[key], {scope:scope, key: key}); 178 } 179 } // if (attrs[key]) 180 } // for(var key in attrs) 181 return options; 182 }; 183 184 /** 185 * converts attributes hash to scope-specific event function 186 * @memberof Attr2Options 187 * @param {scope} scope angularjs scope 188 * @param {Hash} attrs tag attributes 189 * @returns {Hash} events converted events 190 */ 191 var getEvents = function(scope, attrs) { 192 var events = {};
vendor: 6,172 bytes, lines 193-374
193 var toLowercaseFunc = function($1){ 194 return "_"+$1.toLowerCase(); 195 }; 196 var eventFunc = function(attrValue) { 197 var matches = attrValue.match(/([^\(]+)\(([^\)]*)\)/); 198 var funcName = matches[1]; 199 var argsStr = matches[2].replace(/event[ ,]*/,''); //remove string 'event' 200 var argsExpr = $parse("["+argsStr+"]"); //for perf when triggering event 201 return function(event) { 202 var args = argsExpr(scope); //get args here to pass updated model values 203 function index(obj,i) {return obj[i];} 204 var f = funcName.split('.').reduce(index, scope); 205 f && f.apply(this, [event].concat(args)); 206 $timeout( function() { 207 scope.$apply(); 208 }); 209 }; 210 }; 211 212 for(var key in attrs) { 213 if (attrs[key]) { 214 if (!key.match(/^on[A-Z]/)) { //skip if not events 215 continue; 216 } 217 218 //get event name as underscored. i.e. zoom_changed 219 var eventName = key.replace(/^on/,''); 220 eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1); 221 eventName = eventName.replace(/([A-Z])/g, toLowercaseFunc); 222 223 var attrValue = attrs[key]; 224 events[eventName] = new eventFunc(attrValue); 225 } 226 } 227 return events; 228 }; 229 230 /** 231 * control means map controls, i.e streetview, pan, etc, not a general control 232 * @memberof Attr2Options 233 * @param {Hash} filtered filtered tag attributes 234 * @returns {Hash} Google Map options 235 */ 236 var getControlOptions = function(filtered) { 237 var controlOptions = {}; 238 if (typeof filtered != 'object') { 239 return false; 240 } 241 242 for (var attr in filtered) { 243 if (filtered[attr]) { 244 if (!attr.match(/(.*)ControlOptions$/)) { 245 continue; // if not controlOptions, skip it 246 } 247 248 //change invalid json to valid one, i.e. {foo:1} to {"foo": 1} 249 var orgValue = filtered[attr]; 250 var newValue = orgValue.replace(/'/g, '"'); 251 newValue = newValue.replace(/([^"]+)|("[^"]+")/g, function($0, $1, $2) { 252 if ($1) { 253 return $1.replace(/([a-zA-Z0-9]+?):/g, '"$1":'); 254 } else { 255 return $2; 256 } 257 }); 258 try { 259 var options = JSON.parse(newValue); 260 for (var key in options) { //assign the right values 261 if (options[key]) { 262 var value = options[key]; 263 if (typeof value === 'string') { 264 value = value.toUpperCase(); 265 } else if (key === "mapTypeIds") { 266 value = value.map( function(str) { 267 if (str.match(/^[A-Z]+$/)) { // if constant 268 return google.maps.MapTypeId[str.toUpperCase()]; 269 } else { // else, custom map-type 270 return str; 271 } 272 }); 273 } 274 275 if (key === "style") { 276 var str = attr.charAt(0).toUpperCase() + attr.slice(1); 277 var objName = str.replace(/Options$/,'')+"Style"; 278 options[key] = google.maps[objName][value]; 279 } else if (key === "position") { 280 options[key] = google.maps.ControlPosition[value]; 281 } else { 282 options[key] = value; 283 } 284 } 285 } 286 controlOptions[attr] = options; 287 } catch (e) { 288 void 0; 289 } 290 } 291 } // for 292 293 return controlOptions; 294 }; 295 296 return { 297 camelCase: camelCase, 298 filter: filter, 299 getOptions: getOptions, 300 getEvents: getEvents, 301 getControlOptions: getControlOptions, 302 toOptionValue: toOptionValue, 303 getAttrsToObserve: getAttrsToObserve, 304 orgAttributes: orgAttributes 305 }; // return 306 307 }; 308 309 angular.module('ngMap').service('Attr2Options', ['$parse', '$timeout', 'NavigatorGeolocation', 'GeoCoder', Attr2Options]); 310})(); 311 312/** 313 * @ngdoc service 314 * @name GeoCoder 315 * @description 316 * Provides [defered/promise API](https://docs.angularjs.org/api/ng/service/$q) service for Google Geocoder service 317 */ 318/* global google */ 319(function() { 320 'use strict'; 321 var GeoCoder = function($q) { 322 return { 323 /** 324 * @memberof GeoCoder 325 * @param {Hash} options https://developers.google.com/maps/documentation/geocoding/#geocoding 326 * @example 327 * ``` 328 * GeoCoder.geocode({address: 'the cn tower'}).then(function(result) { 329 * //... do something with result 330 * }); 331 * ``` 332 * @returns {HttpPromise} Future object 333 */ 334 geocode : function(options) { 335 var deferred = $q.defer(); 336 var geocoder = new google.maps.Geocoder(); 337 geocoder.geocode(options, function (results, status) { 338 if (status == google.maps.GeocoderStatus.OK) { 339 deferred.resolve(results); 340 } else { 341 deferred.reject('Geocoder failed due to: '+ status); 342 } 343 }); 344 return deferred.promise; 345 } 346 } 347 }; 348 349 angular.module('ngMap').service('GeoCoder', ['$q', GeoCoder]); 350})(); 351 352/** 353 * @ngdoc service 354 * @name NavigatorGeolocation 355 * @description 356 * Provides [defered/promise API](https://docs.angularjs.org/api/ng/service/$q) service for navigator.geolocation methods 357 */ 358/* global google */ 359(function() { 360 'use strict'; 361 362 var NavigatorGeolocation = function($q) { 363 return { 364 /** 365 * @memberof NavigatorGeolocation 366 * @param {function} success success callback function 367 * @param {function} failure failure callback function 368 * @example 369 * ``` 370 * NavigatorGeolocation.getCurrentPosition() 371 * .then(function(position) { 372 * var lat = position.coords.latitude, lng = position.coords.longitude; 373 * .. do something lat and lng 374 * });
375 * ``` 376 * @returns {HttpPromise} Future object 377 */ 378 getCurrentPosition: function() { 379 var deferred = $q.defer(); 380 if (navigator.geolocation) { 381 navigator.geolocation.getCurrentPosition( 382 function(position) { 383 deferred.resolve(position); 384 }, function(evt) { 385 void 0; 386 deferred.reject(evt); 387 } 388 ); 389 } else { 390 deferred.reject("Browser Geolocation service failed."); 391 } 392 return deferred.promise; 393 }, 394 395 watchPosition: function() { 396 return "TODO"; 397 }, 398 399 clearWatch: function() { 400 return "TODO"; 401 } 402 }; 403 }; 404 405 angular.module('ngMap').service('NavigatorGeolocation', ['$q', NavigatorGeolocation]); 406})(); 407 408/** 409 * @ngdoc service 410 * @name StreetView 411 * @description 412 * Provides [defered/promise API](https://docs.angularjs.org/api/ng/service/$q) service 413 * for [Google StreetViewService](https://developers.google.com/maps/documentation/javascript/streetview) 414 */ 415/* global google */ 416(function() { 417 'use strict'; 418 419 var StreetView = function($q) { 420 421 /** 422 * Retrieves panorama id from the given map (and or position) 423 * @memberof StreetView 424 * @param {map} map Google map instance 425 * @param {LatLng} latlng Google LatLng instance 426 * default: the center of the map 427 * @example 428 * StreetView.getPanorama(map).then(function(panoId) { 429 * $scope.panoId = panoId; 430 * }); 431 * @returns {HttpPromise} Future object 432 */ 433 var getPanorama = function(map, latlng) { 434 latlng = latlng || map.getCenter(); 435 var deferred = $q.defer(); 436 var svs = new google.maps.StreetViewService(); 437 svs.getPanoramaByLocation( (latlng||map.getCenter), 100, function (data, status) { 438 // if streetView available 439 if (status === google.maps.StreetViewStatus.OK) { 440 deferred.resolve(data.location.pano); 441 } else { 442 // no street view available in this range, or some error occurred 443 deferred.resolve(false); 444 //deferred.reject('Geocoder failed due to: '+ status); 445 } 446 }); 447 return deferred.promise; 448 }; 449 450 /** 451 * Set panorama view on the given map with the panorama id 452 * @memberof StreetView 453 * @param {map} map Google map instance 454 * @param {String} panoId Panorama id fro getPanorama method 455 * @example 456 * StreetView.setPanorama(map, panoId); 457 */ 458 var setPanorama = function(map, panoId) { 459 var svp = new google.maps.StreetViewPanorama(map.getDiv(), {enableCloseButton: true}); 460 svp.setPano(panoId); 461 }; 462 463 return { 464 getPanorama: getPanorama, 465 setPanorama: setPanorama 466 }; // return 467 468 }; 469 470 angular.module('ngMap').service('StreetView', ['$q', StreetView]); 471})(); 472 473/** 474 * @ngdoc directive 475 * @name bicycling-layer 476 * @requires Attr2Options 477 * @description 478 * Requires: map directive 479 * Restrict To: Element 480 * 481 * @example 482 * Example: 483 * 484 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 485 * <bicycling-layer></bicycling-layer> 486 * </map> 487 */ 488/*jshint -W089*/ 489ngMap.directive('bicyclingLayer', ['Attr2Options', function(Attr2Options) { 490 var parser = Attr2Options; 491 492 var getLayer = function(options, events) { 493 var layer = new google.maps.BicyclingLayer(options); 494 for (var eventName in events) { 495 google.maps.event.addListener(layer, eventName, events[eventName]); 496 } 497 return layer; 498 }; 499 500 return { 501 restrict: 'E', 502 require: '^map', 503 504 link: function(scope, element, attrs, mapController) { 505 var orgAttrs = parser.orgAttributes(element); 506 var filtered = parser.filter(attrs); 507 var options = parser.getOptions(filtered); 508 var events = parser.getEvents(scope, filtered); 509 510 void 0; 511 512 var layer = getLayer(options, events); 513 mapController.addObject('bicyclingLayers', layer); 514 mapController.observeAttrSetObj(orgAttrs, attrs, layer); //observers 515 element.bind('$destroy', function() { 516 mapController.deleteObject('bicyclingLayers', layer); 517 }); 518 } 519 }; // return 520}]); 521 522/** 523 * @ngdoc directive 524 * @name cloud-layer 525 * @requires Attr2Options 526 * @description 527 * Requires: map directive 528 * Restrict To: Element 529 * 530 * @example 531 * Example: 532 * 533 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 534 * <cloud-layer></cloud-layer> 535 * </map> 536 */ 537/*jshint -W089*/ 538ngMap.directive('cloudLayer', ['Attr2Options', function(Attr2Options) { 539 var parser = Attr2Options; 540 541 var getLayer = function(options, events) { 542 var layer = new google.maps.weather.CloudLayer(options); 543 for (var eventName in events) { 544 google.maps.event.addListener(layer, eventName, events[eventName]); 545 } 546 return layer; 547 }; 548 549 return { 550 restrict: 'E', 551 require: '^map', 552 553 link: function(scope, element, attrs, mapController) { 554 var orgAttrs = parser.orgAttributes(element); 555 var filtered = parser.filter(attrs); 556 var options = parser.getOptions(filtered); 557 var events = parser.getEvents(scope, filtered); 558 void 0; 559 560 var layer = getLayer(options, events); 561 mapController.addObject('cloudLayers', layer); 562 mapController.observeAttrSetObj(orgAttrs, attrs, layer); //observers 563 element.bind('$destroy', function() { 564 mapController.deleteObject('cloudLayers', layer); 565 }); 566 } 567 }; // return 568}]); 569 570/*jshint -W030*/ 571/* global google, ngMap */ 572/** 573 * @ngdoc directive 574 * @name custom-control 575 * @requires Attr2Options 576 * @requires $compile 577 * @description 578 * Build custom control and set to the map with position 579 * 580 * Requires: map directive 581 * 582 * Restrict To: Element 583 * 584 * @param {String} position position of this control 585 * i.e. TOP_RIGHT 586 * @param {Number} index index of the control 587 * @example 588 * 589 * Example: 590 * <map center="41.850033,-87.6500523" zoom="3"> 591 * <custom-control id="home" position="TOP_LEFT" index="1"> 592 * <div style="background-color: white;"> 593 * <b>Home</b> 594 * </div> 595 * </custom-control> 596 * </map> 597 * 598 */ 599/*jshint -W089*/ 600ngMap.directive('customControl', ['Attr2Options', '$compile', function(Attr2Options, $compile) { 601 'use strict'; 602 var parser = Attr2Options; 603 604 return { 605 restrict: 'E', 606 require: '^map', 607 link: function(scope, element, attrs, mapController) { 608 var orgAttrs = parser.orgAttributes(element); 609 var filtered = parser.filter(attrs); 610 var options = parser.getOptions(filtered, scope); 611 var events = parser.getEvents(scope, filtered); 612 void 0; 613 614 /** 615 * build a custom control element 616 */ 617 var customControlEl = element[0].parentElement.removeChild(element[0]); 618 $compile(customControlEl.innerHTML.trim())(scope); 619 620 /** 621 * set events 622 */ 623 for (var eventName in events) { 624 google.maps.event.addDomListener(customControlEl, eventName, events[eventName]); 625 } 626 627 mapController.addObject('customControls', customControlEl); 628 scope.$on('mapInitialized', function(evt, map) { 629 var position = options.position; 630 map.controls[google.maps.ControlPosition[position]].push(customControlEl); 631 }); 632 633 } //link 634 }; // return 635}]);// function 636 637/** 638 * @ngdoc directive 639 * @name directions 640 * @description 641 * Enable directions on map. e.g., origin, destination, draggable, waypoints, etc 642 * 643 * Requires: map directive 644 * 645 * Restrict To: Element 646 * 647 * @param {String} <DirectionsRendererOptions> Any DirectionsRendererOptions, 648 * https://developers.google.com/maps/documentation/javascript/reference#DirectionsRendererOptions 649 * @param {String} <DirectionsRequest Options> Any DirectionsRequest options, 650 * https://developers.google.com/maps/documentation/javascript/reference#DirectionsRequest 651 * @example 652 * Example: 653 * <map zoom="14" center="37.7699298, -122.4469157"> 654 * <directions 655 * draggable="true" 656 * panel="directions-panel" 657 * travel-mode="{{travelMode}}" 658 * waypoints="[{location:'kingston', stopover:true}]" 659 * origin="{{origin}}" 660 * destination="{{destination}}">
661 * </directions> 662 * </map> 663 */ 664/* global google */ 665(function() { 666 'use strict'; 667 668 var getDirectionsRenderer = function(options, events) { 669 if (options.panel) { 670 options.panel = document.getElementById(options.panel) || document.querySelector(options.panel); 671 } 672 var renderer = new google.maps.DirectionsRenderer(options); 673 for (var eventName in events) { 674 google.maps.event.addListener(renderer, eventName, events[eventName]); 675 } 676 return renderer; 677 }; 678 679 var directions = function(Attr2Options, $timeout) { 680 var parser = Attr2Options; 681 var directionsService = new google.maps.DirectionsService(); 682 683 var updateRoute = function(renderer, options) { 684 /* filter out valid keys only for DirectionsRequest object*/ 685 var request = options; 686 request.travelMode = request.travelMode || 'DRIVING'; 687 var validKeys = [ 688 'origin', 'destination', 'travelMode', 'transitOptions', 'unitSystem', 689 'durationInTraffic', 'waypoints', 'optimizeWaypoints', 690 'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region' 691 ]; 692 for(var key in request){ 693 (validKeys.indexOf(key) === -1) && (delete request[key]); 694 } 695 696 if (request.origin && request.destination) { 697 void 0; 698 directionsService.route(request, function(response, status) { 699 if (status == google.maps.DirectionsStatus.OK) { 700 $timeout(function() { 701 renderer.setDirections(response); 702 }); 703 } 704 }); 705 } 706 }; 707 708 var linkFunc = function(scope, element, attrs, mapController) { 709 var orgAttrs = parser.orgAttributes(element); 710 var filtered = parser.filter(attrs); 711 var options = parser.getOptions(filtered); 712 var events = parser.getEvents(scope, filtered); 713 var attrsToObserve = parser.getAttrsToObserve(orgAttrs); 714 715 var renderer = getDirectionsRenderer(options, events); 716 mapController.addObject('directionsRenderers', renderer); 717 718 attrsToObserve.forEach(function(attrName) { 719 (function(attrName) { 720 attrs.$observe(attrName, function(val) { 721 if (options[attrName] !== val) { //apply only if changed 722 var optionValue = parser.toOptionValue(val, {key: attrName}); 723 void 0; 724 options[attrName] = optionValue; 725 updateRoute(renderer, options); 726 } 727 }); 728 })(attrName); 729 }); 730 731 scope.$on('mapInitialized', function(event, map) { 732 updateRoute(renderer, options); 733 }); 734 scope.$on('$destroy', function(event, map) { 735 mapController.deleteObject('directionsRenderers', renderer); 736 }); 737 }; 738 739 return { 740 restrict: 'E', 741 require: '^map', 742 link: linkFunc 743 } 744 }; // var directions 745 directions.$inject = ['Attr2Options', '$timeout']; 746 747 angular.module('ngMap').directive('directions', directions); 748})(); 749 750 751/** 752 * @ngdoc directive 753 * @name drawing-manager 754 * @requires Attr2Options 755 * @description 756 * Requires: map directive 757 * Restrict To: Element 758 * 759 * @example 760 * Example: 761 * 762 * <map zoom="13" center="37.774546, -122.433523" map-type-id="SATELLITE"> 763 * <drawing-manager on-overlaycomplete="onMapOverlayCompleted()" position="ControlPosition.TOP_CENTER" drawingModes="POLYGON,CIRCLE" drawingControl="true" circleOptions="fillColor: '#F
763FFF00';fillOpacity: 1;strokeWeight: 5;clickable: false;zIndex: 1;editable: true;" ></drawing-manager> 764 * </map> 765 * 766 * TODO: Add remove button. 767 * currently, for out solution, we have the shapes/markers in our own controller, and we use some css classes to change the shape button 768 * to a remove button (<div>X</div>) and have the remove operation in our own controller. 769 */ 770/*jshint -W089*/ 771ngMap.directive('drawingManager', ['Attr2Options', function(Attr2Options) { 772 var parser = Attr2Options; 773 774 return { 775 restrict: 'E', 776 require: '^map', 777 778 link: function(scope, element, attrs, mapController) { 779 var orgAttrs = parser.orgAttributes(element); 780 var filtered = parser.filter(attrs); 781 var options = parser.getOptions(filtered); 782 var controlOptions = parser.getControlOptions(filtered); 783 var events = parser.getEvents(scope, filtered); 784 785 void 0; 786 787 /** 788 * set options 789 */ 790 var drawingManager = new google.maps.drawing.DrawingManager({ 791 drawingMode: options.drawingmode, 792 drawingControl: options.drawingcontrol, 793 drawingControlOptions: controlOptions.drawingControlOptions, 794 circleOptions:options.circleoptions, 795 markerOptions:options.markeroptions, 796 polygonOptions:options.polygonoptions, 797 polylineOptions:options.polylineoptions, 798 rectangleOptions:options.rectangleoptions 799 }); 800 801 802 /** 803 * set events 804 */ 805 var events = parser.getEvents(scope, filtered); 806 for (var eventName in events) { 807 google.maps.event.addListener(drawingManager, eventName, events[eventName]); 808 } 809 810 mapController.addObject('mapDrawingManager', drawingManager); 811 } 812 }; // return 813}]); 814 815/** 816 * @ngdoc directive 817 * @name dynamic-maps-engine-layer 818 * @description 819 * Requires: map directive 820 * Restrict To: Element 821 * 822 * @example 823 * Example: 824 * <map zoom="14" center="[59.322506, 18.010025]"> 825 * <dynamic-maps-engine-layer layer-id="06673056454046135537-08896501997766553811"></dynamic-maps-engine-layer> 826 * </map> 827 */ 828/*jshint -W089*/ 829ngMap.directive('dynamicMapsEngineLayer', ['Attr2Options', function(Attr2Options) { 830 var parser = Attr2Options; 831 832 var getDynamicMapsEngineLayer = function(options, events) { 833 var layer = new google.maps.visualization.DynamicMapsEngineLayer(options); 834 835 for (var eventName in events) { 836 google.maps.event.addListener(layer, eventName, events[eventName]); 837 } 838 839 return layer; 840 }; 841 842 843 return { 844 restrict: 'E', 845 require: '^map', 846 847 link: function(scope, element, attrs, mapController) { 848 var filtered = parser.filter(attrs); 849 var options = parser.getOptions(filtered); 850 var events = parser.getEvents(scope, filtered, events); 851 void 0; 852 853 var layer = getDynamicMapsEngineLayer(options, events); 854 mapController.addObject('mapsEngineLayers', layer); 855 } 856 }; // return 857}]); 858 859/** 860 * @ngdoc directive 861 * @name fusion-tables-layer 862 * @description 863 * Requires: map directive 864 * Restrict To: Element 865 * 866 * @example 867 * Example: 868 * <map zoom="11" center="41.850033, -87.6500523"> 869 * <fusion-tables-layer query="{ 870 * select: 'Geocodable address', 871 * from: '1mZ53Z70NsChnBMm-qEYmSDOvLXgrreLTkQUvvg'}"> 872 * </fusion-tables-layer> 873 * </map> 874 */ 875/*jshint -W089*/ 876ngMap.directive('fusionTablesLayer', ['Attr2Options', function(Attr2Options) { 877 var parser = Attr2Options; 878 879 var getLayer = function(options, events) { 880 var layer = new google.maps.FusionTablesLayer(options); 881 882 for (var eventName in events) { 883 google.maps.event.addListener(layer, eventName, events[eventName]); 884 } 885 886 return layer; 887 }; 888 889 890 return { 891 restrict: 'E', 892 require: '^map', 893 894 link: function(scope, element, attrs, mapController) { 895 var filtered = parser.filter(attrs); 896 var options = parser.getOptions(filtered); 897 var events = parser.getEvents(scope, filtered, events); 898 void 0; 899 900 var layer = getLayer(options, events); 901 mapController.addObject('fusionTablesLayers', layer); 902 } 903 }; // return 904}]); 905 906/** 907 * @ngdoc directive 908 * @name heatmap-layer 909 * @requires Attr2Options 910 * @description 911 * Requires: map directive 912 * Restrict To: Element 913 * 914 * @example 915 * Example: 916 * 917 * <map zoom="11" center="[41.875696,-87.624207]"> 918 * <heatmap-layer data="taxiData"></heatmap-layer> 919 * </map> 920 */ 921/*jshint -W089*/ 922ngMap.directive('heatmapLayer', ['Attr2Options', '$window', function(Attr2Options, $window) { 923 var parser = Attr2Options; 924 925 return { 926 restrict: 'E', 927 require: '^map', 928 929 link: function(scope, element, attrs, mapController) { 930 var filtered = parser.filter(attrs); 931 932 /** 933 * set options 934 */ 935 var options = parser.getOptions(filtered); 936 options.data = $window[attrs.data] || scope[attrs.data]; 937 if (options.data instanceof Array) { 938 options.data = new google.maps.MVCArray(options.data); 939 } else {
940 throw "invalid heatmap data"; 941 } 942 var layer = new google.maps.visualization.HeatmapLayer(options); 943 944 /** 945 * set events 946 */ 947 var events = parser.getEvents(scope, filtered); 948 void 0; 949 950 mapController.addObject('heatmapLayers', layer); 951 } 952 }; // return 953}]); 954 955/** 956 * @ngdoc directive 957 * @name info-window 958 * @requires Attr2Options 959 * @requires $compile 960 * @description 961 * Defines infoWindow and provides compile method 962 * 963 * Requires: map directive 964 * 965 * Restrict To: Element 966 * 967 * @param {Boolean} visible Indicates to show it when map is initialized 968 * @param {Boolean} visible-on-marker Indicates to show it on a marker when map is initialized 969 * @param {Expression} geo-callback if position is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showDetail()" 970 * @param {String} <InfoWindowOption> Any InfoWindow options, 971 * https://developers.google.com/maps/documentation/javascript/reference?csw=1#InfoWindowOptions 972 * @param {String} <InfoWindowEvent> Any InfoWindow events, https://developers.google.com/maps/documentation/javascript/reference 973 * @example 974 * Usage: 975 * <map MAP_ATTRIBUTES> 976 * <info-window id="foo" ANY_OPTIONS ANY_EVENTS"></info-window> 977 * </map> 978 * 979 * Example: 980 * <map center="41.850033,-87.6500523" zoom="3"> 981 * <info-window id="1" position="41.850033,-87.6500523" > 982 * <div ng-non-bindable> 983 * Chicago, IL<br/> 984 * LatLng: {{chicago.lat()}}, {{chicago.lng()}}, <br/> 985 * World Coordinate: {{worldCoordinate.x}}, {{worldCoordinate.y}}, <br/> 986 * Pixel Coordinate: {{pixelCoordinate.x}}, {{pixelCoordinate.y}}, <br/> 987 * Tile Coordinate: {{tileCoordinate.x}}, {{tileCoordinate.y}} at Zoom Level {{map.getZoom()}} 988 * </div> 989 * </info-window> 990 * </map> 991 */ 992/* global google */ 993(function() { 994 'use strict'; 995 996 var infoWindow = function(Attr2Options, $compile, $timeout, $parse) { 997 var parser = Attr2Options; 998 999 var getInfoWindow = function(options, events, element) { 1000 var infoWindow; 1001 1002 /** 1003 * set options 1004 */ 1005 if (options.position && !(options.position instanceof google.maps.LatLng)) { 1006 delete options.position; 1007 } 1008 infoWindow = new google.maps.InfoWindow(options); 1009 1010 /** 1011 * set events 1012 */ 1013 if (Object.keys(events).length > 0) { 1014 void 0; 1015 } 1016 for (var eventName in events) { 1017 if (eventName) { 1018 google.maps.event.addListener(infoWindow, eventName, events[eventName]); 1019 } 1020 } 1021 1022 /** 1023 * set template ane template-relate functions 1024 * it must have a container element with ng-non-bindable 1025 */ 1026 var template = element.html().trim(); 1027 if (angular.element(template).length != 1) { 1028 throw "info-window working as a template must have a container"; 1029 } 1030 infoWindow.__template = template.replace(/\s?ng-non-bindable[='"]+/,""); 1031 1032 infoWindow.__compile = function(scope, anchor) { 1033 anchor && (scope['this'] = anchor); 1034 var el = $compile(infoWindow.__template)(scope); 1035 infoWindow.setContent(el[0]); 1036 scope.$apply(); 1037 }; 1038 1039 infoWindow.__open = function(map, scope, anchor) { 1040 $timeout(function() { 1041 infoWindow.__compile(scope, anchor); 1042 if (anchor && anchor.getPosition) { 1043 infoWindow.open(map, anchor); 1044 } else if (anchor && anchor instanceof google.maps.LatLng) { 1045 infoWindow.open(map); 1046 infoWindow.setPosition(anchor); 1047 } else { 1048 infoWindow.open(map); 1049 } 1050 }); 1051 }; 1052 1053 return infoWindow; 1054 }; 1055 1056 var linkFunc = function(scope, element, attrs, mapController) { 1057 element.css('display','none'); 1058 var orgAttrs = parser.orgAttributes(element); 1059 var filtered = parser.filter(attrs); 1060 var options = parser.getOptions(filtered, scope); 1061 var events = parser.getEvents(scope, filtered); 1062 void 0; 1063 1064 var address; 1065 if (options.position && !(options.position instanceof google.maps.LatLng)) { 1066 address = options.position; 1067 } 1068 var infoWindow = getInfoWindow(options, events, element); 1069 if (address) { 1070 mapController.getGeoLocation(address).then(function(latlng) { 1071 infoWindow.setPosition(latlng); 1072 infoWindow.__open(mapController.map, scope, latlng); 1073 var geoCallback = attrs.geoCallback; 1074 geoCallback && $parse(geoCallback)(scope); 1075 }); 1076 } 1077 1078 mapController.addObject('infoWindows', infoWindow); 1079 mapController.observeAttrSetObj(orgAttrs, attrs, infoWindow); /* observers */ 1080 1081 scope.$on('mapInitialized', function(evt, map) { 1082 infoWindow.visible && infoWindow.__open(map, scope); 1083 if (infoWindow.visibleOnMarker) { 1084 var markerId = infoWindow.visibleOnMarker; 1085 infoWindow.__open(map, scope, map.markers[markerId]); 1086 } 1087 }); 1088 1089 /** 1090 * provide showInfoWindow method to scope 1091 */ 1092 1093 scope.showInfoWindow = function(e, id, marker) { 1094 var infoWindow = mapController.map.infoWindows[id]; 1095 var anchor = marker ? marker : (this.getPosition ? this
1095: null); 1096 infoWindow.__open(mapController.map, scope, anchor); 1097 }; 1098 1099 /** 1100 * provide hideInfoWindow method to scope 1101 */ 1102 scope.hideInfoWindow = scope.hideInfoWindow || 1103 function(event, id) { 1104 var infoWindow = mapController.map.infoWindows[id]; 1105 infoWindow.close(); 1106 }; 1107 1108 }; //link 1109 1110 return { 1111 restrict: 'E', 1112 require: '^map', 1113 link: linkFunc 1114 }; 1115 1116 }; // infoWindow 1117 infoWindow.$inject = ['Attr2Options', '$compile', '$timeout', '$parse']; 1118 1119 angular.module('ngMap').directive('infoWindow', infoWindow); 1120})(); 1121 1122/** 1123 * @ngdoc directive 1124 * @name kml-layer 1125 * @requires Attr2Options 1126 * @description 1127 * renders Kml layer on a map 1128 * Requires: map directive 1129 * Restrict To: Element 1130 * 1131 * @param {Url} url url of the kml layer 1132 * @param {KmlLayerOptions} KmlLayerOptions 1133 * (https://developers.google.com/maps/documentation/javascript/reference#KmlLayerOptions) 1134 * @param {String} <KmlLayerEvent> Any KmlLayer events, https://developers.google.com/maps/documentation/javascript/reference 1135 * @example 1136 * Usage: 1137 * <map MAP_ATTRIBUTES> 1138 * <kml-layer ANY_KML_LAYER ANY_KML_LAYER_EVENTS"></kml-layer> 1139 * </map> 1140 * 1141 * Example: 1142 * 1143 * <map zoom="11" center="[41.875696,-87.624207]"> 1144 * <kml-layer url="https://gmaps-samples.googlecode.com/svn/trunk/ggeoxml/cta.kml" ></kml-layer> 1145 * </map> 1146 */ 1147/*jshint -W089*/ 1148ngMap.directive('kmlLayer', ['Attr2Options', function(Attr2Options) { 1149 var parser = Attr2Options; 1150 1151 var getKmlLayer = function(options, events) { 1152 var kmlLayer = new google.maps.KmlLayer(options); 1153 for (var eventName in events) { 1154 google.maps.event.addListener(kmlLayer, eventName, events[eventName]); 1155 } 1156 return kmlLayer; 1157 }; 1158 1159 return { 1160 restrict: 'E', 1161 require: '^map', 1162 1163 link: function(scope, element, attrs, mapController) { 1164 var orgAttrs = parser.orgAttributes(element); 1165 var filtered = parser.filter(attrs); 1166 var options = parser.getOptions(filtered); 1167 var events = parser.getEvents(scope, filtered); 1168 void 0; 1169 1170 var kmlLayer = getKmlLayer(options, events); 1171 mapController.addObject('kmlLayers', kmlLayer); 1172 mapController.observeAttrSetObj(orgAttrs, attrs, kmlLayer); //observers 1173 element.bind('$destroy', function() { 1174 mapController.deleteObject('kmlLayers', kmlLayer); 1175 }); 1176 } 1177 }; // return 1178}]); 1179 1180/** 1181 * @ngdoc directive 1182 * @name map-data 1183 * @description 1184 * set map data 1185 * Requires: map directive 1186 * Restrict To: Element 1187 * 1188 * @param {String} method-name, run map.data[method-name] with attribute value 1189 * @example 1190 * Example: 1191 * 1192 * <map zoom="11" center="[41.875696,-87.624207]"> 1193 * <map-data load-geo-json="https://storage.googleapis.com/maps-devrel/google.json"></map-data> 1194 * </map> 1195 */ 1196ngMap.directive('mapData', ['Attr2Options', function(Attr2Options) { 1197 var parser = Attr2Options; 1198 1199 return { 1200 restrict: 'E', 1201 require: '^map', 1202 1203 link: function(scope, element, attrs, mapController) { 1204 var filtered = parser.filter(attrs); 1205 var options = parser.getOptions(filtered); 1206 var events = parser.getEvents(scope, filtered, events); 1207 1208 void 0; 1209 scope.$on('mapInitialized', function(event, map) { 1210 /** 1211 * options 1212 */ 1213 for (var key in options) { 1214 if (key) { 1215 var val = options[key]; 1216 if (typeof scope[val] === "function") { 1217 map.data[key](scope[val]); 1218 } else { 1219 map.data[key](val); 1220 } 1221 } // if (key) 1222 } 1223 1224 /** 1225 * events 1226 */ 1227 for (var eventName in events) { 1228 if (events[eventName]) { 1229 map.data.addListener(eventName, events[eventName]); 1230 } 1231 } 1232 }); 1233 } 1234 }; // return 1235}]); 1236 1237/** 1238 * @ngdoc directive 1239 * @name lazy-load 1240 * @requires Attr2Options 1241 * @description 1242 * Requires: Delay the initialization of directive until required .js loads 1243 * Restrict To: Attribute 1244 * 1245 * @param {String} lazy-load 1246 script source file location 1247 * example: 1248 * 'http://maps.googlecom/maps/api/js' 1249 1250 * @example 1251 * Example: 1252 * 1253 * <div lazy-load="http://maps.google.com/maps/api/js"> 1254 * <map center="Brampton" zoom="10"> 1255 * <marker position="Brampton"></marker> 1256 * </map> 1257 * </div> 1258 */ 1259/*jshint -W089*/ 1260ngMap.directive('mapLazyLoad', ['$compile', '$timeout', function($compile, $timeout) { 1261 'use strict'; 1262 var directiveDefinitionObject = {
1263 compile: function(tElement, tAttrs) { 1264 (!tAttrs.mapLazyLoad) && void 0; 1265 var savedHtml = tElement.html(), src = tAttrs.mapLazyLoad; 1266 /** 1267 * if already loaded, stop processing it 1268 */ 1269 if (document.querySelector('script[src="'+src+'?callback=lazyLoadCallback"]')) { 1270 return false; 1271 } 1272 1273 tElement.html(''); // will compile again after script is loaded 1274 return { 1275 pre: function(scope, element, attrs) { 1276 window.lazyLoadCallback = function() { 1277 void 0; 1278 $timeout(function() { /* give some time to load */ 1279 element.html(savedHtml); 1280 $compile(element.contents())(scope); 1281 }, 100); 1282 }; 1283 if(window.google === undefined || window.google.maps === undefined) { 1284 var scriptEl = document.createElement('script'); 1285 scriptEl.src = src + (src.indexOf('?') > -1 ? '&' : '?') + 'callback=lazyLoadCallback'; 1286 document.body.appendChild(scriptEl); 1287 } else { 1288 element.html(savedHtml); 1289 $compile(element.contents())(scope); 1290 } 1291 } 1292 }; 1293 } 1294 }; 1295 return directiveDefinitionObject; 1296}]); 1297 1298/** 1299 * @ngdoc directive 1300 * @name map-type 1301 * @requires Attr2Options 1302 * @description 1303 * Requires: map directive 1304 * Restrict To: Element 1305 * 1306 * @example 1307 * Example: 1308 * 1309 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 1310 * <map-type name="coordinate" object="coordinateMapType"></map-type> 1311 * </map> 1312 */ 1313/*jshint -W089*/ 1314ngMap.directive('mapType', ['Attr2Options', '$window', function(Attr2Options, $window) { 1315 var parser = Attr2Options; 1316 1317 return { 1318 restrict: 'E', 1319 require: '^map', 1320 1321 link: function(scope, element, attrs, mapController) { 1322 var mapTypeName = attrs.name, mapTypeObject; 1323 if (!mapTypeName) { 1324 throw "invalid map-type name"; 1325 } 1326 if (attrs.object) { 1327 var __scope = scope[attrs.object] ? scope : $window; 1328 mapTypeObject = __scope[attrs.object]; 1329 if (typeof mapTypeObject == "function") { 1330 mapTypeObject = new mapTypeObject(); 1331 } 1332 } 1333 if (!mapTypeObject) { 1334 throw "invalid map-type object"; 1335 } 1336 1337 scope.$on('mapInitialized', function(evt, map) { 1338 map.mapTypes.set(mapTypeName, mapTypeObject); 1339 }); 1340 mapController.addObject('mapTypes', mapTypeObject); 1341 } 1342 }; // return 1343}]); 1344 1345/** 1346 * @ngdoc directive 1347 * @name map 1348 * @requires Attr2Options 1349 * @description 1350 * Implementation of {@link MapController} 1351 * Initialize a Google map within a `<div>` tag with given options and register events 1352 * It accepts children directives; marker, shape, or marker-clusterer 1353 * 1354 * It initialize map, children tags, then emits message as soon as the action is done 1355 * The message emitted from this directive is; 1356 * . mapInitialized 1357 * 1358 * Restrict To: 1359 * Element 1360 * 1361 * @param {Expression} geo-callback if center is an address or current location, the expression is will be executed when geo-lookup is successful. e.g., geo-callback="showMyStoreInfo()" 1362 * @param {Array} geo-fallback-center 1363 * The center of map incase geolocation failed. i.e. [0,0] 1364 * @param {String} init-event The name of event to initialize this map. 1365 * If this option is given, the map won't be initialized until the event is received. 1366 * To invoke the event, use $scope.$emit or $scope.$broacast. 1367 * i.e. <map init-event="init-map" ng-click="$emit('init-map')" center=... ></map> 1368 * @param {String} <MapOption> Any Google map options, 1369 * https://developers.google.com/maps/documentation/javascript/reference?csw=1#MapOptions 1370 * @param {String} <MapEvent> Any Google map events, 1371 * https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/map_events.html 1372 * @example 1373 * Usage: 1374 * <map MAP_OPTIONS_OR_MAP_EVENTS ..> 1375 * ... Any children directives 1376 * </map> 1377 * 1378 * Example: 1379 * <map center="[40.74, -74.18]" on-click="doThat()"> 1380 * </map> 1381 * 1382 * <map geo-fallback-center="[40.74, -74.18]"> 1383 * </map> 1384 */ 1385/* global google */ 1386(function() { 1387 'use strict'; 1388 1389 function getStyle(el,styleProp) { 1390 var y; 1391 if (el.currentStyle) { 1392 y = el.currentStyle[styleProp]; 1393 } else if (window.getComputedStyle) { 1394 y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp); 1395 } 1396 return y; 1397 } 1398 1399 var mapDirective = function(Attr2Options, $timeout, $parse) { 1400 var parser = Attr2Options; 1401 1402 /** 1403 * Initialize map and events 1404 * @memberof map 1405 * @param {$scope} scope 1406 * @param {angular.element} element 1407 * @param {Hash} attrs 1408 * @ctrl {MapController} ctrl 1409 */ 1410 var linkFunc = function(scope, element, attrs, ctrl) { 1411 var orgAttrs = parser.orgAttributes(element); 1412 1413 scope.google = google; //used by $scope.eval in Attr2Options to avoid eval() 1414 1415 /** 1416 * create a new `div` inside map tag, so that it does not touch map element 1417 * https://stackoverflow.com/questions/20955356 1418 */ 1419 var el = document.createElement("div"); 1420 el.style.width = "100%"; 1421 el.style.height = "100%";
1422 element.prepend(el); 1423 1424 /** 1425 * if style is not given to the map element, set display and height 1426 */ 1427 if (getStyle(element[0], 'display') != "block") { 1428 element.css('display','block'); 1429 } 1430 if (getStyle(element[0], 'height').match(/^(0|auto)/)) { 1431 element.css('height','300px'); 1432 } 1433 1434 /** 1435 * disable drag event 1436 */ 1437 element[0].addEventListener('dragstart', function(event) { 1438 event.preventDefault(); 1439 return false; 1440 }); 1441 1442 /** 1443 * initialize function 1444 */ 1445 var initializeMap = function(mapOptions, mapEvents) { 1446 var map = new google.maps.Map(el, {}); 1447 map.markers = {}; 1448 map.shapes = {}; 1449 1450 /** 1451 * resize the map to prevent showing partially, in case intialized too early 1452 */ 1453 $timeout(function() { 1454 google.maps.event.trigger(map, "resize"); 1455 }); 1456 1457 /** 1458 * set options 1459 */ 1460 mapOptions.zoom = mapOptions.zoom || 15; 1461 var center = mapOptions.center; 1462 if (!center) { 1463 mapOptions.center = new google.maps.LatLng(0,0); 1464 } else if (!(center instanceof google.maps.LatLng)) { 1465 delete mapOptions.center; 1466 ctrl.getGeoLocation(center).then(function(latlng) { 1467 map.setCenter(latlng); 1468 var geoCallback = attrs.geoCallback; 1469 geoCallback && $parse(geoCallback)(scope); 1470 }, function(error) { 1471 map.setCenter(options.geoFallbackCenter); 1472 }); 1473 } 1474 map.setOptions(mapOptions); 1475 1476 /** 1477 * set events 1478 */ 1479 for (var eventName in mapEvents) { 1480 if (eventName) { 1481 google.maps.event.addListener(map, eventName, mapEvents[eventName]); 1482 } 1483 } 1484 1485 /** 1486 * set observers 1487 */ 1488 ctrl.observeAttrSetObj(orgAttrs, attrs, map); 1489 1490 /** 1491 * set controller and set objects 1492 * so that map can be used by other directives; marker or shape 1493 * ctrl._objects are gathered when marker and shape are initialized before map is set 1494 */ 1495 ctrl.map = map; /* so that map can be used by other directives; marker or shape */ 1496 ctrl.addObjects(ctrl._objects); 1497 1498 // /* providing method to add a marker used by user scope */ 1499 // map.addMarker = ctrl.addMarker; 1500 1501 /** 1502 * set map for scope and controller and broadcast map event 1503 * scope.map will be overwritten if user have multiple maps in a scope, 1504 * thus the last map will be set as scope.map. 1505 * however an `mapInitialized` event will be emitted every time. 1506 */ 1507 scope.map = map; 1508 scope.map.scope = scope; 1509 google.maps.event.addListenerOnce(map, "idle", function() { 1510 scope.$emit('mapInitialized', map); 1511 }); 1512 1513 // the following lines will be deprecated on behalf of mapInitialized 1514 // to collect maps, we should use scope.maps in your own controller, i.e. MyCtrl 1515 scope.maps = scope.maps || {}; 1516 scope.maps[options.id||Object.keys(scope.maps).length] = map; 1517 scope.$emit('mapsInitialized', scope.maps); 1518 }; // function initializeMap() 1519 1520 /** 1521 * get map options and events 1522 */ 1523 var filtered = parser.filter(attrs); 1524 var options = parser.getOptions(filtered, scope); 1525 var controlOptions = parser.getControlOptions(filtered); 1526 var mapOptions = angular.extend(options, controlOptions); 1527 var mapEvents = parser.getEvents(scope, filtered); 1528 void 0; 1529 1530 if (attrs.initEvent) { // allows controlled initialization 1531 scope.$on(attrs.initEvent, function() { 1532 !ctrl.map && initializeMap(mapOptions, mapEvents); // init if not done 1533 }); 1534 } else { 1535 initializeMap(mapOptions, mapEvents); 1536 } // if 1537 }; 1538 1539 return { 1540 restrict: 'AE', 1541 controller: 'MapController', 1542 link: linkFunc 1543 }; 1544 }; 1545 1546 angular.module('ngMap').directive('map', ['Attr2Options', '$timeout', '$parse', mapDirective]); 1547})(); 1548 1549/* global google */ 1550(function() { 1551 'use strict'; 1552 1553 /** 1554 * @ngdoc controller 1555 * @name MapController 1556 * @requires $scope 1557 * @property {Hash} controls collection of Controls initiated within `map` directive 1558 * @property {Hash} markers collection of Markers initiated within `map` directive 1559 * @property {Hash} shapes collection of shapes initiated within `map` directive 1560 */ 1561 var MapController = function($q, NavigatorGeolocation, GeoCoder, Attr2Options) { 1562 var parser = Attr2Options; 1563 var _this = this; 1564 1565 var observeAndSet = function(attrs, attrName, object) { 1566 attrs.$observe(attrName, function(val) { 1567 if (val) { 1568 void 0; 1569 var setMethod = parser.camelCase('set-'+attrName); 1570 var optionValue = parser.toOptionValue(val, {key: attrName}); 1571 void 0; 1572 if (object[setMethod]) { //if set method does exist 1573 /* if an location is being observed */ 1574 if (attrName.match(/center|position/) && 1575 typeof optionValue == 'string') { 1576 _this.getGeoLocation(optionValue).then(function(latlng) { 1577 object[setMethod](latlng); 1578 }); 1579 } else { 1580 object[setMethod](optionValue); 1581 } 1582 } 1583 } 1584 }); 1585 }; 1586 1587 this.map = null; 1588 this._objects = []; /* temporary collection of map objects */ 1589 1590 /** 1591 * Add an object to the collection of group 1592 * @memberof MapController 1593 * @function addObject 1594 * @param groupName the name of collection that object belongs to 1595 * @param obj an object to add into a collection, i.e. marker, shape 1596 */ 1597 this.addObject = function(groupName, obj) { 1598 /** 1599 * objects, i.e. markers and shapes, are initialized before map is initialized 1600 * so, we collect those objects, then, we will add to map when map is initialized 1601 * However the case as in ng-repeat, we can directly add to map 1602 */ 1603 if (this.map) { 1604 this.map[groupName] = this.map[groupName] || {}; 1605 var len = Object.keys(this.map[groupName]).length; 1606 this.map[groupName][obj.id || len] = obj;
1607 if (groupName != "infoWindows" && obj.setMap) { //infoWindow.setMap works like infoWindow.open 1608 obj.setMap && obj.setMap(this.map); 1609 } 1610 if (obj.centered && obj.position) { 1611 this.map.setCenter(obj.position); 1612 } 1613 } else { 1614 obj.groupName = groupName; 1615 this._objects.push(obj); 1616 } 1617 }; 1618 1619 /** 1620 * Delete an object from the collection and remove from map 1621 * @memberof MapController 1622 * @function deleteObject 1623 * @param {Array} objs the collection of objects. i.e., map.markers 1624 * @param {Object} obj the object to be removed. i.e., marker 1625 */ 1626 this.deleteObject = function(groupName, obj) { 1627 /* delete from group */ 1628 var objs = obj.map[groupName]; 1629 for (var name in objs) { 1630 objs[name] === obj && (delete objs[name]); 1631 } 1632 1633 /* delete from map */ 1634 obj.map && obj.setMap && obj.setMap(null); 1635 }; 1636 1637 /** 1638 * Add collected objects to map 1639 * @memberof MapController 1640 * @function addObjects 1641 * @param {Array} objects the collection of objects. i.e., map.markers 1642 */ 1643 this.addObjects = function(objects) { 1644 for (var i=0; i<objects.length; i++) { 1645 var obj=objects[i]; 1646 if (obj instanceof google.maps.Marker) { 1647 this.addObject('markers', obj); 1648 } else if (obj instanceof google.maps.Circle || 1649 obj instanceof google.maps.Polygon || 1650 obj instanceof google.maps.Polyline || 1651 obj instanceof google.maps.Rectangle || 1652 obj instanceof google.maps.GroundOverlay) { 1653 this.addObject('shapes', obj); 1654 } else { 1655 this.addObject(obj.groupName, obj); 1656 } 1657 } 1658 }; 1659 1660 /** 1661 * returns the location of an address or 'current-location' 1662 * @memberof MapController 1663 * @function getGeoLocation 1664 * @param {String} string an address to find the location 1665 * @returns {Promise} latlng the location of the address 1666 */ 1667 this.getGeoLocation = function(string) { 1668 var deferred = $q.defer(); 1669 if (!string || string.match(/^current/i)) { // current location 1670 NavigatorGeolocation.getCurrentPosition().then( 1671 function(position) { 1672 var lat = position.coords.latitude; 1673 var lng = position.coords.longitude; 1674 var latLng = new google.maps.LatLng(lat,lng); 1675 deferred.resolve(latLng); 1676 }, 1677 function(error) { 1678 deferred.reject(error); 1679 } 1680 ); 1681 } else { 1682 GeoCoder.geocode({address: string}).then( 1683 function(results) { 1684 deferred.resolve(results[0].geometry.location); 1685 }, 1686 function(error) { 1687 deferred.reject(error); 1688 } 1689 ); 1690 } 1691 1692 return deferred.promise; 1693 }; 1694 1695 /** 1696 * watch changes of attribute values and do appropriate action based on attribute name 1697 * @memberof MapController 1698 * @function observeAttrSetObj 1699 * @param {Hash} orgAttrs attributes before its initialization 1700 * @param {Hash} attrs attributes after its initialization 1701 * @param {Object} obj map object that an action is to be done 1702 */ 1703 this.observeAttrSetObj = function(orgAttrs, attrs, obj) { 1704 var attrsToObserve = parser.getAttrsToObserve(orgAttrs); 1705 if (Object.keys(attrsToObserve).length) { 1706 void 0; 1707 } 1708 for (var i=0; i<attrsToObserve.length; i++) { 1709 observeAndSet(attrs, attrsToObserve[i], obj); 1710 } 1711 }; 1712 1713 1714 }; // MapController 1715 1716 MapController.$inject = ['$q', 'NavigatorGeolocation', 'GeoCoder', 'Attr2Options']; 1717 angular.module('ngMap').controller('MapController', MapController); 1718})(); 1719 1720/** 1721 * @ngdoc directive 1722 * @name maps-engine-layer 1723 * @description 1724 * Requires: map directive 1725 * Restrict To: Element 1726 * 1727 * @example 1728 * Example: 1729 * <map zoom="14" center="[59.322506, 18.010025]"> 1730 * <maps-engine-layer layer-id="06673056454046135537-08896501997766553811"></maps-engine-layer> 1731 * </map> 1732 */ 1733/*jshint -W089*/ 1734ngMap.directive('mapsEngineLayer', ['Attr2Options', function(Attr2Options) { 1735 var parser = Attr2Options; 1736 1737 var getMapsEngineLayer = function(options, events) { 1738 var layer = new google.maps.visualization.MapsEngineLayer(options); 1739 1740 for (var eventName in events) { 1741 google.maps.event.addListener(layer, eventName, events[eventName]); 1742 } 1743 1744 return layer; 1745 }; 1746 1747 1748 return { 1749 restrict: 'E', 1750 require: '^map', 1751 1752 link: function(scope, element, attrs, mapController) { 1753 var filtered = parser.filter(attrs); 1754 var options = parser.getOptions(filtered); 1755 var events = parser.getEvents(scope, filtered, events); 1756 void 0; 1757 1758 var layer = getMapsEngineLayer(options, events); 1759 mapController.addObject('mapsEngineLayers', layer); 1760 } 1761 }; // return 1762}]); 1763 1764/** 1765 * @ngdoc directive 1766 * @name marker 1767 * @requires Attr2Options 1768 * @requires NavigatorGeolocation 1769 * @description 1770 * Draw a Google map marker on a map with given options and register events 1771 * 1772 * Requires: map directive 1773 * 1774 * Restrict To: Element 1775 * 1776 * @param {String} position address, 'current', or [latitude, longitude] 1777 * example: 1778 * '1600 Pennsylvania Ave, 20500 Washingtion DC', 1779 * 'current position', 1780 * '[40.74, -74.18]' 1781 * @param {Boolean} centered if set, map will be centered with this marker 1782 * @param {Expression} geo-callback if position is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showStoreInfo()" 1783 * @param {String} <MarkerOption> Any Marker options, https://developers.google.com/maps/documentation/javascript/reference?csw=1#MarkerOptions 1784 * @param {String} <MapEvent> Any Marker events, https://developers.google.com/maps/documentation/javascript/reference 1785 * @example 1786 * Usage: 1787 * <map MAP_ATTRIBUTES> 1788 * <marker ANY_MARKER_OPTIONS ANY_MARKER_EVENTS"></MARKER> 1789 * </map> 1790 * 1791 * Example: 1792 * <map center="[40.74, -74.18]"> 1793 * <marker position="[40.74, -74.18]" on-click="myfunc()"></div> 1794 * </map> 1795 * 1796 * <map center="the cn tower"> 1797 * <marker position="the cn tower" on-click="myfunc()"></div> 1798 * </map> 1799 */ 1800/* global google */ 1801(function() { 1802 'use strict'; 1803 1804 var getMarker = function(options, events) { 1805 var marker; 1806 1807 /** 1808 * set options 1809 */ 1810 if (options.icon instanceof Object) { 1811 if ((""+options.icon.path).match(/^[A-Z_]+$/)) { 1812 options.icon.path = google.maps.SymbolPath[options.icon.path]; 1813 } 1814 for (var key in options.icon) { 1815 var arr = options.icon[key]; 1816 if (key == "anchor" || key == "origin") { 1817 options.icon[key] = new google.maps.Point(arr[0], arr[1]); 1818 } else if (key == "size" || key == "scaledSize") { 1819 options.icon[key] = new google.maps.Size(arr[0], arr[1]); 1820 } 1821 } 1822 } 1823 if (!(options.position instanceof google.maps.LatLng)) { 1824 options.position = new google.maps.LatLng(0,0); 1825 } 1826 marker = new google.maps.Marker(options); 1827 1828 /** 1829 * set events 1830 */ 1831 if (Object.keys(events).length > 0) { 1832 void 0; 1833 } 1834 for (var eventName in events) { 1835 if (eventName) { 1836 google.maps.event.addListener(marker, eventName, events[eventName]); 1837 } 1838 } 1839 1840 return marker; 1841 }; 1842 1843 var marker = function(Attr2Options, $parse) { 1844 var parser = Attr2Options; 1845 var linkFunc = function(scope, element, attrs, mapController) { 1846 var orgAttrs = parser.orgAttributes(element); 1847 var filtered = parser.filter(attrs); 1848 var markerOptions = parser.getOptions(filtered, scope); 1849 var markerEvents = parser.getEvents(scope, filtered); 1850 void 0; 1851 1852 var address; 1853 if (!(markerOptions.position instanceof google.maps.LatLng)) { 1854 address = markerOptions.position; 1855 } 1856 var marker = getMarker(markerOptions, markerEvents); 1857 mapController.addObject('markers', marker); 1858 if (address) { 1859 mapController.getGeoLocation(address).then(function(latlng) { 1860 marker.setPosition(latlng); 1861 markerOptions.centered && marker.map.setCenter(latlng); 1862 var geoCallback = attrs.geoCallback; 1863 geoCallback && $parse(geoCallback)(scope); 1864 }); 1865 } 1866 1867 /** 1868 * set observers 1869 */ 1870 mapController.observeAttrSetObj(orgAttrs, attrs, marker); /* observers */ 1871 element.bind('$destroy', function() { 1872 mapController.deleteObject('markers', marker); 1873 }); 1874 }; 1875 1876 return { 1877 restrict: 'E', 1878 require: '^map', 1879 link: linkFunc 1880 }; 1881 }; 1882 1883 marker.$inject = ['Attr2Options', '$parse']; 1884 angular.module('ngMap').directive('marker', marker); 1885 1886})(); 1887 1888/** 1889 * @ngdoc directive 1890 * @name overlay-map-type 1891 * @requires Attr2Options 1892 * @description 1893 * Requires: map directive 1894 * Restrict To: Element 1895 * 1896 * @example 1897 * Example: 1898 * 1899 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 1900 * <overlay-map-type index="0" object="coordinateMapType"></map-type> 1901 * </map> 1902 */ 1903/*jshint -W089*/ 1904ngMap.directive('overlayMapType', ['Attr2Options', '$window', function(Attr2Options, $window) { 1905 var parser = Attr2Options; 1906 1907 return { 1908 restrict: 'E', 1909 require: '^map', 1910 1911 link: function(scope, element, attrs, mapController) { 1912 var overlayMapTypeObject; 1913 var initMethod = attrs.initMethod || "insertAt"; 1914 if (attrs.object) { 1915 var __scope = scope[attrs.object] ? scope : $window; 1916 overlayMapTypeObject = __scope[attrs.object]; 1917 if (typeof overlayMapTypeObject == "function") { 1918 overlayMapTypeObject = new overlayMapTypeObject(); 1919 } 1920 } 1921 if (!overlayMapTypeObject) {
1922 throw "invalid map-type object"; 1923 } 1924 1925 scope.$on('mapInitialized', function(evt, map) { 1926 if (initMethod == "insertAt") { 1927 var index = parseInt(attrs.index, 10); 1928 map.overlayMapTypes.insertAt(index, overlayMapTypeObject); 1929 } else if (initMethod == "push") { 1930 map.overlayMapTypes.push(overlayMapTypeObject); 1931 } 1932 }); 1933 mapController.addObject('overlayMapTypes', overlayMapTypeObject); 1934 } 1935 }; // return 1936}]); 1937 1938/** 1939 * @ngdoc directive 1940 * @name places-auto-complete 1941 * @requires Attr2Options 1942 * @description 1943 * Provides address auto complete feature to an input element 1944 * Requires: input tag 1945 * Restrict To: Attribute 1946 * 1947 * @param {AutoCompleteOptions} Any AutocompleteOptions 1948 * https://developers.google.com/maps/documentation/javascript/3.exp/reference#AutocompleteOptions 1949 * 1950 * @example 1951 * Example: 1952 * <script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script> 1953 * <input places-auto-complete types="['geocode']" /> 1954 */ 1955/* global google */ 1956(function() { 1957 'use strict'; 1958 1959 var placesAutoComplete = function(Attr2Options, $timeout) { 1960 var parser = Attr2Options; 1961 1962 var linkFunc = function(scope, element, attrs, ngModelCtrl) { 1963 var filtered = parser.filter(attrs); 1964 var options = parser.getOptions(filtered); 1965 var events = parser.getEvents(scope, filtered); 1966 void 0; 1967 var autocomplete = new google.maps.places.Autocomplete(element[0], options); 1968 for (var eventName in events) { 1969 google.maps.event.addListener(autocomplete, eventName, events[eventName]); 1970 } 1971 element[0].addEventListener('change', function() { 1972 $timeout(function(){ 1973 ngModelCtrl && ngModelCtrl.$setViewValue(element.val()); 1974 },100); 1975 }); 1976 1977 attrs.$observe('types', function(val) { 1978 if (val) { 1979 void 0; 1980 var optionValue = parser.toOptionValue(val, {key: 'types'}); 1981 void 0; 1982 autocomplete.setTypes(optionValue); 1983 } 1984 }); 1985 }; 1986 1987 return { 1988 restrict: 'A', 1989 require: '?ngModel', 1990 link: linkFunc 1991 }; 1992 }; 1993 1994 placesAutoComplete.$inject = ['Attr2Options', '$timeout']; 1995 angular.module('ngMap').directive('placesAutoComplete', placesAutoComplete); 1996 1997})(); 1998 1999/** 2000 * @ngdoc directive 2001 * @name shape 2002 * @requires Attr2Options 2003 * @description 2004 * Initialize a Google map shape in map with given options and register events 2005 * The shapes are: 2006 * . circle 2007 * . polygon 2008 * . polyline 2009 * . rectangle 2010 * . groundOverlay(or image) 2011 * 2012 * Requires: map directive 2013 * 2014 * Restrict To: Element 2015 * 2016 * @param {Boolean} centered if set, map will be centered with this marker 2017 * @param {Expression} geo-callback if shape is a circle and the center is an address, the expression is will be performed when geo-lookup is successful. e.g., geo-callback="showDetail()" 2018 * @param {String} <OPTIONS> 2019 * For circle, [any circle options](https://developers.google.com/maps/documentation/javascript/reference#CircleOptions) 2020 * For polygon, [any polygon options](https://developers.google.com/maps/documentation/javascript/reference#PolygonOptions) 2021 * For polyline, [any polyline options](https://developers.google.com/maps/documentation/javascript/reference#PolylineOptions) 2022 * For rectangle, [any rectangle options](https://developers.google.com/maps/documentation/javascript/reference#RectangleOptions) 2023 * For image, [any groundOverlay options](https://developers.google.com/maps/documentation/javascript/reference#GroundOverlayOptions) 2024 * @param {String} <MapEvent> Any Shape events, https://developers.google.com/maps/documentation/javascript/reference 2025 * @example 2026 * Usage: 2027 * <map MAP_ATTRIBUTES> 2028 * <shape name=SHAPE_NAME ANY_SHAPE_OPTIONS ANY_SHAPE_EVENTS"></MARKER> 2029 * </map> 2030 * 2031 * Example: 2032 * 2033 * <map zoom="11" center="[40.74, -74.18]"> 2034 * <shape id="polyline" name="polyline" geodesic="true" stroke-color="#FF0000" stroke-opacity="1.0" stroke-weight="2" 2035 * path="[[40.74,-74.18],[40.64,-74.10],[40.54,-74.05],[40.44,-74]]" ></shape> 2036 * </map> 2037 * 2038 * <map zoom="11" center="[40.74, -74.18]"> 2039 * <shape id="polygon" name="polygon" stroke-color="#FF0000" stroke-opacity="1.0" stroke-weight="2" 2040 * paths="[[40.74,-74.18],[40.64,-74.18],[40.84,-74.08],[40.74,-74.18]]" ></shape> 2041 * </map> 2042 * 2043 * <map zoom="11" center="[40.74, -74.18]"> 2044 * <shape id="rectangle" name="rectangle" stroke-color='#FF0000' stroke-opacity="0.8" stroke-weight="2" 2045 * bounds="[[40.74,-74.18], [40.78,-74.14]]" editable="true" ></shape> 2046 * </map> 2047 * 2048 * <map zoom="11" center="[40.74, -74.18]"> 2049 * <shape id="circle" name="circle" stroke-color='#FF0000' stroke-opacity="0.8"stroke-weight="2" 2050 * center="[40.70,-74.14]" radius="4000" editable="true" ></shape> 2051 * </map> 2052 * 2053 * <map zoom="11" center="[40.74, -74.18]"> 2054 * <shape id="image" name="image" url="https://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg" 2055 * bounds="[[40.71,-74.22],[40.77,-74.12]]" opacity="0.7" clickable="true" ></shape> 2056 * </map> 2057 * 2058 * For full-working example, please visit 2059 * [shape example](https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/shape.html) 2060 */ 2061/* global google */ 2062(function() { 2063 'use strict'; 2064 2065 var getBounds = function(points) { 2066 return new google.maps.LatLngBounds(points[0], points[1]); 2067 }; 2068 2069 var getShape = function(options, events) { 2070 var shape; 2071 2072 var shapeName = options.name; 2073 delete options.name; //remove name bcoz it's not for options 2074 void 0; 2075 2076 /** 2077 * set options 2078 */ 2079 if (options.icons) { 2080 for (var i=0; i<options.icons.length; i++) { 2081 var el = options.icons[i]; 2082 if (el.icon.path.match(/^[A-Z_]+$/)) { 2083 el.icon.path = google.maps.SymbolPath[el.icon.path]; 2084 } 2085 } 2086 } 2087 switch(shapeName) { 2088 case "circle": 2089 if (!(options.center instanceof google.maps.LatLng)) { 2090 options.center = new google.maps.LatLng(0,0); 2091 } 2092 shape = new google.maps.Circle(options); 2093 break; 2094 case "polygon": 2095 shape = new google.maps.Polygon(options); 2096 break; 2097 case "polyline": 2098 shape = new google.maps.Polyline(options); 2099 break; 2100 case "rectangle": 2101 if (options.bounds) { 2102 options.bounds = getBounds(options.bounds); 2103 } 2104 shape = new google.maps.Rectangle(options); 2105 break; 2106 case "groundOverlay": 2107 case "image": 2108 var url = options.url; 2109 var bounds = getBounds(options.bounds); 2110 var opts = {opacity: options.opacity, clickable: options.clickable, id:options.id}; 2111 shape = new google.maps.GroundOverlay(url, bounds, opts); 2112 break; 2113 } 2114 2115 /** 2116 * set events 2117 */ 2118 for (var eventName in events) { 2119 if (events[eventName]) { 2120 google.maps.event.addListener(shape, eventName, events[eventName]); 2121 } 2122 } 2123 return shape; 2124 }; 2125 2126 var shape = function(Attr2Options, $parse) { 2127 var parser = Attr2Options; 2128 2129 var linkFunc = function(scope, element, attrs, mapController) { 2130 var orgAttrs = parser.orgAttributes(element); 2131 var filtered = parser.filter(attrs); 2132 var shapeOptions = parser.getOptions(filtered); 2133 var shapeEvents = parser.getEvents(scope, filtered); 2134 2135 var address, shapeType; 2136 shapeType = shapeOptions.name; 2137 if (!(shapeOptions.center instanceof google.maps.LatLng)) { 2138 address = shapeOptions.center; 2139 } 2140 var shape = getShape(shapeOptions, shapeEvents); 2141 mapController.addObject('shapes', shape); 2142 2143 if (address && shapeType == 'circle') { 2144 mapController.getGeoLocation(address).then(function(latlng) { 2145 shape.setCenter(latlng); 2146 shape.centered && shape.map.setCenter(latlng); 2147 var geoCallback = attrs.geoCallback; 2148 geoCallback && $parse(geoCallback)(scope); 2149 }); 2150 } 2151 2152 /** 2153 * set observers 2154 */ 2155 mapController.observeAttrSetObj(orgAttrs, attrs, shape); 2156 element.bind('$destroy', function() { 2157 mapController.deleteObject('shapes', shape); 2158 }); 2159 }; 2160 2161 return { 2162 restrict: 'E', 2163 require: '^map', 2164 link: linkFunc 2165 }; // return 2166 }; 2167 shape.$inject = ['Attr2Options', '$parse']; 2168 2169 angular.module('ngMap').directive('shape', shape); 2170 2171})(); 2172 2173/** 2174 * @ngdoc directive 2175 * @name streetview-panorama 2176 * @requires Attr2Options 2177 * @description 2178 * Requires: map directive 2179 * Restrict To: Element 2180 * 2181 * @param container Optional, id or css selector, if given, streetview will be in the given html element 2182 * @param {String} <StreetViewPanoramaOption> Any Google StreetViewPanorama options, 2183 * https://developers.google.com/maps/documentation/javascript/reference?csw=1#StreetViewPanoramaOptions 2184 * @param {String} <StreetViewPanoramaEvent> Any Google StreetViewPanorama events, 2185 * https://developers.google.com/maps/documentation/javascript/reference#StreetViewPanorama 2186 * 2187 * @example 2188 * <map zoom="11" center="[40.688738,-74.043871]" > 2189 * <street-view-panorama 2190 * click-to-go="true" 2191 * disable-default-ui="true" 2192 * disable-double-click-zoom="true" 2193 * enable-close-button="true" 2194 * pano="my-pano" 2195 * position="40.688738,-74.043871" 2196 * pov="{heading:0, pitch: 90}" 2197 * scrollwheel="false" 2198 * visible="true"> 2199 * </street-view-panorama> 2200 * </map> 2201 */ 2202/* global google */ 2203(function() { 2204 'use strict'; 2205 2206 var streetViewPanorama = function(Attr2Options) { 2207 var parser = Attr2Options; 2208 2209 var getStreetViewPanorama = function(map, options, events) { 2210 var svp, container; 2211 if (options.container) { 2212 container = document.getElementById(options.container); 2213 container = container || document.querySelector(options.container); 2214 } 2215 if (container) { 2216 svp = new google.maps.StreetViewPanorama(container, options); 2217 } else { 2218 svp = map.getStreetView(); 2219 svp.setOptions(options); 2220 } 2221 2222 for (var eventName in events) { 2223 eventName && 2224 google.maps.event.addListener(svp, eventName, events[eventName]); 2225 } 2226 return svp; 2227 }; 2228 2229 var linkFunc = function(scope, element, attrs, mapController) { 2230 var orgAttrs = parser.orgAttributes(element); 2231 var filtered = parser.filter(attrs); 2232 var options = parser.getOptions(filtered); 2233 var controlOptions = parser.getControlOptions(filtered); 2234 var svpOptions = angular.extend(options, controlOptions); 2235 2236 var svpEvents = parser.getEvents(scope, filtered); 2237 void 0; 2238 2239 scope.$on('mapInitialized', function(evt, map) { 2240 var svp = getStreetViewPanorama(map, svpOptions, svpEvents); 2241 2242 map.setStreetView(svp); 2243 (!svp.getPosition()) && svp.setPosition(map.getCenter()); 2244 google.maps.event.addListener(svp, 'position_changed', function() { 2245 if (svp.getPosition() !== map.getCenter()) { 2246 map.setCenter(svp.getPosition()); 2247 } 2248 }); 2249 //needed for geo-callback 2250 var listener = google.maps.event.addListener(map, 'center_changed', function() { 2251 svp.setPosition(map.getCenter()); 2252 google.maps.event.removeListener(listener); 2253 }); 2254 }); 2255 2256 }; //link 2257 2258 return { 2259 restrict: 'E', 2260 require: '^map', 2261 link: linkFunc 2262 }; 2263 2264 }; 2265 streetViewPanorama.$inject = ['Attr2Options']; 2266 2267 angular.module('ngMap').directive('streetViewPanorama', streetViewPanorama); 2268})(); 2269 2270/** 2271 * @ngdoc directive 2272 * @name traffic-layer 2273 * @requires Attr2Options 2274 * @description 2275 * Requires: map directive 2276 * Restrict To: Element 2277 * 2278 * @example 2279 * Example: 2280 * 2281 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 2282 * <traffic-layer></traffic-layer> 2283 * </map> 2284 */ 2285/*jshint -W089*/ 2286ngMap.directive('trafficLayer', ['Attr2Options', function(Attr2Options) { 2287 var parser = Attr2Options; 2288 2289 var getLayer = function(options, events) { 2290 var layer = new google.maps.TrafficLayer(options); 2291 for (var eventName in events) { 2292 google.maps.event.addListener(layer, eventName, events[eventName]); 2293 } 2294 return layer; 2295 }; 2296 2297 return { 2298 restrict: 'E', 2299 require: '^map', 2300 2301 link: function(scope, element, attrs, mapController) { 2302 var orgAttrs = parser.orgAttributes(element); 2303 var filtered = parser.filter(attrs); 2304 var options = parser.getOptions(filtered); 2305 var events = parser.getEvents(scope, filtered); 2306 void 0; 2307 2308 var layer = getLayer(options, events); 2309 mapController.addObject('trafficLayers', layer); 2310 mapController.observeAttrSetObj(orgAttrs, attrs, layer); //observers 2311 element.bind('$destroy', function() { 2312 mapController.deleteObject('trafficLayers', layer); 2313 }); 2314 } 2315 }; // return 2316}]); 2317 2318/** 2319 * @ngdoc directive 2320 * @name transit-layer 2321 * @requires Attr2Options 2322 * @description 2323 * Requires: map directive 2324 * Restrict To: Element 2325 * 2326 * @example 2327 * Example: 2328 * 2329 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 2330 * <transit-layer></transit-layer> 2331 * </map> 2332 */ 2333/*jshint -W089*/ 2334ngMap.directive('transitLayer', ['Attr2Options', function(Attr2Options) { 2335 var parser = Attr2Options; 2336 2337 var getLayer = function(options, events) { 2338 var layer = new google.maps.TransitLayer(options); 2339 for (var eventName in events) { 2340 google.maps.event.addListener(layer, eventName, events[eventName]); 2341 } 2342 return layer; 2343 }; 2344 2345 return { 2346 restrict: 'E', 2347 require: '^map', 2348 2349 link: function(scope, element, attrs, mapController) { 2350 var orgAttrs = parser.orgAttributes(element); 2351 var filtered = parser.filter(attrs); 2352 var options = parser.getOptions(filtered); 2353 var events = parser.getEvents(scope, filtered); 2354 void 0; 2355 2356 var layer = getLayer(options, events); 2357 mapController.addObject('transitLayers', layer); 2358 mapController.observeAttrSetObj(orgAttrs, attrs, layer); //observers 2359 element.bind('$destroy', function() { 2360 mapController.deleteObject('transitLayers', layer); 2361 }); 2362 } 2363 }; // return 2364}]); 2365 2366/** 2367 * @ngdoc directive 2368 * @name weather-layer 2369 * @requires Attr2Options 2370 * @description 2371 * Requires: map directive 2372 * Restrict To: Element 2373 * 2374 * @example 2375 * Example: 2376 * 2377 * <map zoom="13" center="34.04924594193164, -118.24104309082031"> 2378 * <weather-layer></weather-layer> 2379 * </map> 2380 */ 2381/*jshint -W089*/ 2382ngMap.directive('weatherLayer', ['Attr2Options', function(Attr2Options) { 2383 var parser = Attr2Options; 2384 2385 var getLayer = function(options, events) { 2386 var layer = new google.maps.weather.WeatherLayer(options); 2387 for (var eventName in events) { 2388 google.maps.event.addListener(layer, eventName, events[eventName]); 2389 } 2390 return layer; 2391 }; 2392 2393 return { 2394 restrict: 'E', 2395 require: '^map', 2396 2397 link: function(scope, element, attrs, mapController) { 2398 var orgAttrs = parser.orgAttributes(element); 2399 var filtered = parser.filter(attrs); 2400 var options = parser.getOptions(filtered); 2401 var events = parser.getEvents(scope, filtered); 2402 2403 void 0; 2404 2405 var layer = getLayer(options, events); 2406 mapController.addObject('weatherLayers', layer); 2407 mapController.observeAttrSetObj(orgAttrs, attrs, layer); //observers 2408 element.bind('$destroy', function() { 2409 mapController.deleteObject('weatherLayers', layer); 2410 }); 2411 } 2412 }; // return 2413}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.