OLD | NEW |
1 <!-- Copyright (c) 2015 Google Inc. All rights reserved. --> | 1 <!-- Copyright (c) 2015 Google Inc. All rights reserved. --> |
2 | 2 |
3 <link rel="import" href="../polymer/polymer.html"> | 3 <link rel="import" href="../polymer/polymer.html"> |
4 <link rel="import" href="../google-apis/google-maps-api.html"> | 4 <link rel="import" href="../google-apis/google-maps-api.html"> |
5 <link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html
"> | 5 <link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html
"> |
| 6 <link rel="import" href="../iron-selector/iron-selector.html"> |
6 <link rel="import" href="google-map-marker.html"> | 7 <link rel="import" href="google-map-marker.html"> |
7 <!-- | 8 <!-- |
8 The `google-map` element renders a Google Map. | 9 The `google-map` element renders a Google Map. |
9 | 10 |
10 <b>Example</b>: | 11 <b>Example</b>: |
11 | 12 |
12 <style> | 13 <style> |
13 google-map { | 14 google-map { |
14 height: 600px; | 15 height: 600px; |
15 } | 16 } |
(...skipping 15 matching lines...) Expand all Loading... |
31 var map = document.querySelector('google-map'); | 32 var map = document.querySelector('google-map'); |
32 map.latitude = 37.77493; | 33 map.latitude = 37.77493; |
33 map.longitude = -122.41942; | 34 map.longitude = -122.41942; |
34 map.addEventListener('google-map-ready', function(e) { | 35 map.addEventListener('google-map-ready', function(e) { |
35 alert('Map loaded!'); | 36 alert('Map loaded!'); |
36 }); | 37 }); |
37 </script> | 38 </script> |
38 | 39 |
39 <b>Example</b> - with Google directions, using data-binding inside another Polym
er element | 40 <b>Example</b> - with Google directions, using data-binding inside another Polym
er element |
40 | 41 |
41 <google-map map="{{map}}" libraries="places"></google-map> | 42 <google-map map="{{map}}"></google-map> |
42 <google-map-directions map="{{map}}" | 43 <google-map-directions map="{{map}}" |
43 start-address="San Francisco" end-address="Mountain View"> | 44 start-address="San Francisco" end-address="Mountain View"> |
44 </google-map-directions> | 45 </google-map-directions> |
45 | 46 |
46 @demo | 47 @demo |
47 --> | 48 --> |
48 | 49 |
49 <dom-module id="google-map"> | 50 <dom-module id="google-map"> |
50 | 51 |
51 <style> | 52 <style> |
(...skipping 10 matching lines...) Expand all Loading... |
62 bottom: 0; | 63 bottom: 0; |
63 left: 0; | 64 left: 0; |
64 } | 65 } |
65 | 66 |
66 </style> | 67 </style> |
67 <template> | 68 <template> |
68 <google-maps-api id="api" | 69 <google-maps-api id="api" |
69 api-key="[[apiKey]]" | 70 api-key="[[apiKey]]" |
70 client-id="[[clientId]]" | 71 client-id="[[clientId]]" |
71 version="[[version]]" | 72 version="[[version]]" |
72 libraries="[[libraries]]" | |
73 signed-in="[[signedIn]]" | 73 signed-in="[[signedIn]]" |
74 language="[[language]]" | 74 language="[[language]]" |
75 on-api-load="_mapApiLoaded"></google-maps-api> | 75 on-api-load="_mapApiLoaded"></google-maps-api> |
76 | 76 |
77 <div id="map"></div> | 77 <div id="map"></div> |
78 | 78 |
79 <content id="markers" select="google-map-marker"></content> | 79 <iron-selector id="selector" multi="[[!singleInfoWindow]]" selected-attribut
e="open" activate-event="google-map-marker-open" on-google-map-marker-close="_de
selectMarker"> |
80 | 80 <content id="markers" select="google-map-marker"></content> |
| 81 </iron-selector> |
| 82 <content id="objects" select="*"></content> |
81 </template> | 83 </template> |
82 </dom-module> | 84 </dom-module> |
83 | 85 |
84 <script> | 86 <script> |
85 | 87 |
86 Polymer({ | 88 Polymer({ |
87 | 89 |
88 is: 'google-map', | 90 is: 'google-map', |
89 | 91 |
90 | 92 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 /** | 165 /** |
164 * A Maps API object. | 166 * A Maps API object. |
165 */ | 167 */ |
166 map: { | 168 map: { |
167 type: Object, | 169 type: Object, |
168 notify: true, | 170 notify: true, |
169 value: null | 171 value: null |
170 }, | 172 }, |
171 | 173 |
172 /** | 174 /** |
173 * A comma separated list (e.g. "places,geometry") of libraries to load | |
174 * with this map. Defaults to "". For more information see | |
175 * https://developers.google.com/maps/documentation/javascript/libraries. | |
176 */ | |
177 libraries: { | |
178 type: String, | |
179 value: '' | |
180 }, | |
181 | |
182 /** | |
183 * A longitude to center the map on. | 175 * A longitude to center the map on. |
184 */ | 176 */ |
185 longitude: { | 177 longitude: { |
186 type: Number, | 178 type: Number, |
187 value: -122.41942, | 179 value: -122.41942, |
188 notify: true, | 180 notify: true, |
189 reflectToAttribute: true | 181 reflectToAttribute: true |
190 }, | 182 }, |
191 | 183 |
192 /** | 184 /** |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 value: function() { return {}; } | 336 value: function() { return {}; } |
345 }, | 337 }, |
346 | 338 |
347 /** | 339 /** |
348 * The markers on the map. | 340 * The markers on the map. |
349 */ | 341 */ |
350 markers: { | 342 markers: { |
351 type: Array, | 343 type: Array, |
352 value: function() { return []; }, | 344 value: function() { return []; }, |
353 readOnly: true | 345 readOnly: true |
| 346 }, |
| 347 |
| 348 /** |
| 349 * The non-marker objects on the map. |
| 350 */ |
| 351 objects: { |
| 352 type: Array, |
| 353 value: function() { return []; }, |
| 354 readOnly: true |
| 355 }, |
| 356 |
| 357 /** |
| 358 * If set, all other info windows on markers are closed when opening a new
one. |
| 359 */ |
| 360 singleInfoWindow: { |
| 361 type: Boolean, |
| 362 value: false |
354 } | 363 } |
355 | |
356 }, | 364 }, |
357 | 365 |
358 behaviors: [ | 366 behaviors: [ |
359 Polymer.IronResizableBehavior | 367 Polymer.IronResizableBehavior |
360 ], | 368 ], |
361 | 369 |
362 listeners: { | 370 listeners: { |
363 'iron-resize': 'resize' | 371 'iron-resize': 'resize' |
364 }, | 372 }, |
365 | 373 |
366 observers: [ | 374 observers: [ |
367 '_debounceUpdateCenter(latitude, longitude)' | 375 '_debounceUpdateCenter(latitude, longitude)' |
368 ], | 376 ], |
369 | 377 |
370 attached: function() { | 378 attached: function() { |
371 this._initGMap(); | 379 this._initGMap(); |
372 }, | 380 }, |
373 | 381 |
374 detached: function() { | 382 detached: function() { |
375 if (this._mutationObserver) { | 383 if (this._mutationObserver) { |
376 this._mutationObserver.disconnect(); | 384 this._mutationObserver.disconnect(); |
377 this._mutationObserver = null; | 385 this._mutationObserver = null; |
378 } | 386 } |
| 387 if (this._objectsMutationObserver) { |
| 388 this._objectsMutationObserver.disconnect(); |
| 389 this._objectsMutationObserver = null; |
| 390 } |
379 }, | 391 }, |
380 | 392 |
381 _initGMap: function() { | 393 _initGMap: function() { |
382 if (this.map) { | 394 if (this.map) { |
383 return; // already initialized | 395 return; // already initialized |
384 } | 396 } |
385 if (this.$.api.libraryLoaded !== true) { | 397 if (this.$.api.libraryLoaded !== true) { |
386 return; // api not loaded | 398 return; // api not loaded |
387 } | 399 } |
388 if (!this.isAttached) { | 400 if (!this.isAttached) { |
389 return; // not attached | 401 return; // not attached |
390 } | 402 } |
391 | 403 |
392 this.map = new google.maps.Map(this.$.map, this._getMapOptions()); | 404 this.map = new google.maps.Map(this.$.map, this._getMapOptions()); |
393 this._listeners = {}; | 405 this._listeners = {}; |
394 this._updateCenter(); | 406 this._updateCenter(); |
395 this._loadKml(); | 407 this._loadKml(); |
396 this._updateMarkers(); | 408 this._updateMarkers(); |
| 409 this._updateObjects(); |
397 this._addMapListeners(); | 410 this._addMapListeners(); |
398 this.fire('google-map-ready'); | 411 this.fire('google-map-ready'); |
399 }, | 412 }, |
400 | 413 |
401 _mapApiLoaded: function() { | 414 _mapApiLoaded: function() { |
402 this._initGMap(); | 415 this._initGMap(); |
403 }, | 416 }, |
404 | 417 |
405 _getMapOptions: function() { | 418 _getMapOptions: function() { |
406 var mapOptions = { | 419 var mapOptions = { |
(...skipping 12 matching lines...) Expand all Loading... |
419 // We use getAttribute here because the default value of this.draggable =
false even when not set. | 432 // We use getAttribute here because the default value of this.draggable =
false even when not set. |
420 if (this.getAttribute('draggable') != null) { | 433 if (this.getAttribute('draggable') != null) { |
421 mapOptions.draggable = this.draggable | 434 mapOptions.draggable = this.draggable |
422 } | 435 } |
423 for (var p in this.additionalMapOptions) | 436 for (var p in this.additionalMapOptions) |
424 mapOptions[p] = this.additionalMapOptions[p]; | 437 mapOptions[p] = this.additionalMapOptions[p]; |
425 | 438 |
426 return mapOptions; | 439 return mapOptions; |
427 }, | 440 }, |
428 | 441 |
429 // watch for future updates | 442 _attachChildrenToMap: function(children) { |
| 443 if (this.map) { |
| 444 for (var i = 0, child; child = children[i]; ++i) { |
| 445 child.map = this.map; |
| 446 } |
| 447 } |
| 448 }, |
| 449 |
| 450 // watch for future updates to marker objects |
430 _observeMarkers: function() { | 451 _observeMarkers: function() { |
431 // Watch for future updates. | 452 // Watch for future updates. |
432 if (this._mutationObserver) { | 453 if (this._mutationObserver) { |
433 return; | 454 return; |
434 } | 455 } |
435 this._mutationObserver = new MutationObserver( this._updateMarkers.bind(th
is)); | 456 this._mutationObserver = new MutationObserver(this._updateMarkers.bind(thi
s)); |
436 this._mutationObserver.observe(this, { | 457 this._mutationObserver.observe(this.$.selector, { |
437 childList: true | 458 childList: true |
438 }); | 459 }); |
439 }, | 460 }, |
440 | 461 |
441 _updateMarkers: function() { | 462 _updateMarkers: function() { |
442 var newMarkers = Array.prototype.slice.call( | 463 var newMarkers = Array.prototype.slice.call( |
443 Polymer.dom(this.$.markers).getDistributedNodes()); | 464 Polymer.dom(this.$.markers).getDistributedNodes()); |
444 | 465 |
445 // do not recompute if markers have not been added or removed | 466 // do not recompute if markers have not been added or removed |
446 if (newMarkers.length === this.markers.length) { | 467 if (newMarkers.length === this.markers.length) { |
447 var added = newMarkers.filter(function(m) { | 468 var added = newMarkers.filter(function(m) { |
448 return this.markers && this.markers.indexOf(m) === -1; | 469 return this.markers && this.markers.indexOf(m) === -1; |
449 }.bind(this)); | 470 }.bind(this)); |
450 if (added.length === 0) { | 471 if (added.length === 0) { |
451 // set up observer first time around | 472 // set up observer first time around |
452 if (!this._mutationObserver) { | 473 if (!this._mutationObserver) { |
453 this._observeMarkers(); | 474 this._observeMarkers(); |
454 } | 475 } |
455 return; | 476 return; |
456 } | 477 } |
457 } | 478 } |
458 | 479 |
459 this._observeMarkers(); | 480 this._observeMarkers(); |
460 | 481 |
461 this.markers = this._setMarkers(newMarkers); | 482 this.markers = this._setMarkers(newMarkers); |
462 | 483 |
463 // Set the map on each marker and zoom viewport to ensure they're in view. | 484 // Set the map on each marker and zoom viewport to ensure they're in view. |
464 if (this.markers.length && this.map) { | 485 this._attachChildrenToMap(this.markers); |
465 for (var i = 0, m; m = this.markers[i]; ++i) { | |
466 m.map = this.map; | |
467 } | |
468 } | |
469 if (this.fitToMarkers) { | 486 if (this.fitToMarkers) { |
470 this._fitToMarkersChanged(); | 487 this._fitToMarkersChanged(); |
471 } | 488 } |
472 }, | 489 }, |
473 | 490 |
| 491 // watch for future updates to non-marker objects |
| 492 _observeObjects: function() { |
| 493 if (this._objectsMutationObserver) { |
| 494 return; |
| 495 } |
| 496 this._objectsMutationObserver = new MutationObserver(this._updateObjects.b
ind(this)); |
| 497 this._objectsMutationObserver.observe(this, { |
| 498 childList: true |
| 499 }); |
| 500 }, |
| 501 |
| 502 _updateObjects: function() { |
| 503 var newObjects = Array.prototype.slice.call( |
| 504 Polymer.dom(this.$.objects).getDistributedNodes()); |
| 505 |
| 506 // Do not recompute if objects have not been added or removed. |
| 507 if (newObjects.length === this.objects.length) { |
| 508 var added = newObjects.filter(function(o) { |
| 509 return this.objects.indexOf(o) === -1; |
| 510 }.bind(this)); |
| 511 if (added.length === 0) { |
| 512 // Set up observer first time around. |
| 513 this._observeObjects(); |
| 514 return; |
| 515 } |
| 516 } |
| 517 |
| 518 this._observeObjects(); |
| 519 this._setObjects(newObjects); |
| 520 this._attachChildrenToMap(this.objects); |
| 521 }, |
| 522 |
474 /** | 523 /** |
475 * Clears all markers from the map. | 524 * Clears all markers from the map. |
476 * | 525 * |
477 * @method clear | 526 * @method clear |
478 */ | 527 */ |
479 clear: function() { | 528 clear: function() { |
480 for (var i = 0, m; m = this.markers[i]; ++i) { | 529 for (var i = 0, m; m = this.markers[i]; ++i) { |
481 m.marker.setMap(null); | 530 m.marker.setMap(null); |
482 } | 531 } |
483 }, | 532 }, |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 switch (attrName) { | 689 switch (attrName) { |
641 case 'draggable': | 690 case 'draggable': |
642 this.map.setOptions({draggable: this.draggable}); | 691 this.map.setOptions({draggable: this.draggable}); |
643 break; | 692 break; |
644 } | 693 } |
645 }, | 694 }, |
646 | 695 |
647 _fitToMarkersChanged: function() { | 696 _fitToMarkersChanged: function() { |
648 // TODO(ericbidelman): respect user's zoom level. | 697 // TODO(ericbidelman): respect user's zoom level. |
649 | 698 |
650 if (this.map && this.fitToMarkers) { | 699 if (this.map && this.fitToMarkers && this.markers.length > 0) { |
651 var latLngBounds = new google.maps.LatLngBounds(); | 700 var latLngBounds = new google.maps.LatLngBounds(); |
652 for (var i = 0, m; m = this.markers[i]; ++i) { | 701 for (var i = 0, m; m = this.markers[i]; ++i) { |
653 latLngBounds.extend( | 702 latLngBounds.extend( |
654 new google.maps.LatLng(m.latitude, m.longitude)); | 703 new google.maps.LatLng(m.latitude, m.longitude)); |
655 } | 704 } |
656 | 705 |
657 // For one marker, don't alter zoom, just center it. | 706 // For one marker, don't alter zoom, just center it. |
658 if (this.markers.length > 1) { | 707 if (this.markers.length > 1) { |
659 this.map.fitBounds(latLngBounds); | 708 this.map.fitBounds(latLngBounds); |
660 } | 709 } |
661 | 710 |
662 this.map.setCenter(latLngBounds.getCenter()); | 711 this.map.setCenter(latLngBounds.getCenter()); |
663 } | 712 } |
664 }, | 713 }, |
665 | 714 |
666 _addMapListeners: function() { | 715 _addMapListeners: function() { |
667 google.maps.event.addListener(this.map, 'center_changed', function() { | 716 google.maps.event.addListener(this.map, 'center_changed', function() { |
668 var center = this.map.getCenter(); | 717 var center = this.map.getCenter(); |
669 this.latitude = center.lat(); | 718 this.latitude = center.lat(); |
670 this.longitude = center.lng(); | 719 this.longitude = center.lng(); |
671 }.bind(this)); | 720 }.bind(this)); |
672 | 721 |
673 google.maps.event.addListener(this.map, 'zoom_changed', function() { | 722 google.maps.event.addListener(this.map, 'zoom_changed', function() { |
674 this.zoom = this.map.getZoom(); | 723 this.zoom = this.map.getZoom(); |
675 }.bind(this)); | 724 }.bind(this)); |
676 | 725 |
677 google.maps.event.addListener(this.map, 'maptypeid_changed', function() { | 726 google.maps.event.addListener(this.map, 'maptypeid_changed', function() { |
678 this.mapType = this.map.getMapTypeId(); | 727 this.mapType = this.map.getMapTypeId(); |
679 }.bind(this)); | 728 }.bind(this)); |
680 | 729 |
681 this._clickEventsChanged(); | 730 this._clickEventsChanged(); |
682 this._dragEventsChanged(); | 731 this._dragEventsChanged(); |
683 this._mouseEventsChanged(); | 732 this._mouseEventsChanged(); |
684 }, | 733 }, |
685 | 734 |
686 _clearListener: function(name) { | 735 _clearListener: function(name) { |
687 if (this._listeners[name]) { | 736 if (this._listeners[name]) { |
688 google.maps.event.removeListener(this._listeners[name]); | 737 google.maps.event.removeListener(this._listeners[name]); |
689 this._listeners[name] = null; | 738 this._listeners[name] = null; |
690 } | 739 } |
691 }, | 740 }, |
692 | 741 |
693 _forwardEvent: function(name) { | 742 _forwardEvent: function(name) { |
694 this._listeners[name] = google.maps.event.addListener(this.map, name, func
tion(event) { | 743 this._listeners[name] = google.maps.event.addListener(this.map, name, func
tion(event) { |
695 this.fire('google-map-' + name, event); | 744 this.fire('google-map-' + name, event); |
696 }.bind(this)); | 745 }.bind(this)); |
697 } | 746 }, |
| 747 |
| 748 _deselectMarker: function(e, detail) { |
| 749 // If singleInfoWindow is set, update iron-selector's selected attribute to
be null. |
| 750 // Else remove the marker from iron-selector's selected array. |
| 751 var markerIndex = this.$.selector.indexOf(e.target); |
| 752 |
| 753 if (this.singleInfoWindow) { |
| 754 this.$.selector.selected = null; |
| 755 } else if (this.$.selector.selectedValues) { |
| 756 this.$.selector.selectedValues = this.$.selector.selectedValues.filter(fun
ction(i) {return i !== markerIndex}); |
| 757 } |
| 758 } |
698 | 759 |
699 }); | 760 }); |
700 | 761 |
701 </script> | 762 </script> |
OLD | NEW |