Aquest article ens mostrarà com utilitzar Google Maps per escollir el lloc en l'aplicació per saber l'hora de sortida i posta de sol.
Fins ara hem vist:
- En la primera part vàrem preparar el projecte inicial.
- En la segona part vàrem crear l'aplicació, fixant el lloc.
- En la tercera part vàrem afegir-hi geolocalització.
- En la quarta part vàrem afegir-hi un calendari.
Ara utilitzarem Google Maps per poder escollir el lloc. Tot i que hi ha molta informació sobre com utilitzar Google Maps, la informació sol estar incompleta o no acabar-se d'adaptar a les nostres necessitats concretes.
En general, una de les meves primeres fonts d'informació són els articles de Josh Morony. Són acurats i força actualitzats. Tota una referència. I just podem trobar-hi el que busquem: "com fer una pàgina de selecció de lloc amb Google Maps i Ionic". Seguirem el tutorial i fem els canvis necessaris per afegir la funcionalitat a la nostra aplicació.
Afegim el mòdul de xarxa, que permetrà verificar quan tenim connexió de dades, i les definicions de tipus per Google Maps:
$ ionic cordova plugin add cordova-plugin-network-information $ npm install --save @ionic-native/network $ npm install @types/google-maps --save
Seguint el tutorial, afegim la pàgina nova (LocationSelect) i els nous proveïdors a app.module.ts:
...
import { CalendarModule } from "ion2-calendar";
import { LocationSelect } from '../pages/location-select/location-select';
import { Connectivity } from '../providers/connectivity-service';
import { GoogleMapsService } from '../providers/google-maps-service';
import { Network } from '@ionic-native/network';
...
declarations: [
...
HomePage,
LocationSelect,
TabsPage
],
...
entryComponents: [
...
HomePage,
LocationSelect,
TabsPage
],
providers: [
...
Geolocation,
Connectivity,
GoogleMapsService,
Network
]
...
Ara afegim les pàgines dels proveïdors de servei, segons el tutorial. En primer lloc, providers/connectivity-service.ts:
import { Injectable } from '@angular/core';
import { Network } from '@ionic-native/network';
import { Platform } from 'ionic-angular';
@Injectable()
export class Connectivity {
onDevice: boolean;
constructor(public platform: Platform, public network: Network) {
this.onDevice = this.platform.is('cordova');
}
isOnline(): boolean {
if(this.onDevice && this.network.type){
return this.network.type != 'none';
} else {
return navigator.onLine;
}
}
isOffline(): boolean {
if(this.onDevice && this.network.type){
return this.network.type == 'none';
} else {
return !navigator.onLine;
}
}
watchOnline(): any { return this.network.onConnect(); }
watchOffline(): any { return this.network.onDisconnect(); }
}
I tot seguit, providers/google-maps-service.ts:
import { Injectable } from '@angular/core';
import { Connectivity } from './connectivity-service';
import { Geolocation } from '@ionic-native/geolocation';
@Injectable()
export class GoogleMapsService {
mapElement: any;
pleaseConnect: any;
map: any;
mapInitialised: boolean = false;
mapLoaded: any;
mapLoadedObserver: any;
currentMarker: any;
apiKey: string; // = "YOUR_API_KEY";
lat: number = null;
lon: number = null;
constructor( public connectivityService: Connectivity,
public geolocation: Geolocation )
{
}
init( mapElement: any, pleaseConnect: any,
lat: number, lon: number
): Promise
{
this.mapElement = mapElement;
this.pleaseConnect = pleaseConnect;
this.lat = lat;
this.lon = lon;
return this.loadGoogleMaps();
}
loadGoogleMaps(): Promise {
return new Promise((resolve) => {
if(typeof google=="undefined" || typeof google.maps=="undefined") {
console.log("Google maps JavaScript needs to be loaded.");
this.disableMap();
if(this.connectivityService.isOnline()){
window['mapInit'] = () => {
this.initMap().then(() => {
resolve(true);
});
this.enableMap();
}
let script = document.createElement("script");
script.id = "googleMaps";
if(this.apiKey){
script.src = 'http://maps.google.com/maps/api/js?key=' +
this.apiKey + '&callback=mapInit&libraries=places';
} else {
script.src = 'http://maps.google.com/maps/api/js' +
'?callback=mapInit&libraries=places';
}
document.body.appendChild(script);
}
} else {
if(this.connectivityService.isOnline()){
this.initMap();
this.enableMap();
} else {
this.disableMap();
}
resolve(true);
}
this.addConnectivityListeners();
});
}
initMap(): Promise {
this.mapInitialised = true;
return new Promise((resolve) => {
if(this.lat && this.lon) {
this.initMapPos(this.lat, this.lon);
resolve(true);
} else {
this.geolocation.getCurrentPosition().then((pos) => {
this.initMapPos(pos.coords.latitude, pos.coords.longitude);
resolve(true);
}).catch((error) => {
console.log('Error getting location'+JSON.stringify(error));
return Promise.reject("Unable to get location");
});
}
});
}
initMapPos(lat: number, lon: number) {
let latLng = new google.maps.LatLng(lat, lon);
let mapOptions = {
center: latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
this.map = new google.maps.Map(this.mapElement, mapOptions);
}
disableMap(): void {
if(this.pleaseConnect){
this.pleaseConnect.style.display = "block";
}
}
enableMap(): void {
if(this.pleaseConnect){
this.pleaseConnect.style.display = "none";
}
}
addConnectivityListeners(): void {
this.connectivityService.watchOnline().subscribe(() => {
setTimeout(() => {
if(typeof google=="undefined" || typeof google.maps=="undefined") {
this.loadGoogleMaps();
} else {
if(!this.mapInitialised) {
this.initMap();
}
this.enableMap();
}
}, 2000);
});
this.connectivityService.watchOffline().subscribe(() => {
this.disableMap();
});
}
}
En aquest fitxer hem fet alguns canvis:
- [6] Hem canviat el nom de la classe a GoogleMapsService.
- [14] Hem eliminat l'apiKey. Se n'hauria de generar una per poder-la utilitzar en l'aplicació però, per fer proves, podem treballar sense.
- [15-16] Declarem les variables per poder inicialitzar el mapa a partir d'una posició concreta, enlloc de la posició del nostre dispositiu.
- [24-31] Afegim paràmetres per la posició desitjada a la funció init i els traslladem als corresponents camps de la classe.
- [59] Hem afegit el paràmetre que faltava a la petició: '&libraries=places'.
- [79-109] En la funció initMap, utilitzem la posició obtinguda durant la inicialització, o si està buida, usem el servei de geolocalització. També hem separat el codi d'inicialització de Google Maps en una nova funció initMapPos per no repetir codi.
Pel que fa a la pàgina LocationSelect, el fitxer d'estils location-select/location-select.scss no s'ha modificat, en el fitxer location-select/location-select.html només s'han traduït els textos al català, i el fitxer controlador location-select/location-select.ts s'ha modificat per poder passar la localització actual al servei GoogleMapsService:
...
import { NavParams } from 'ionic-angular';
import { GoogleMapsService } from '../../providers/google-maps-service';
...
export class LocationSelect {
...
location: any;
lat: number = 42.582104;
lon: number = 1.0008419;
constructor( public navCtrl: NavController,
public params: NavParams,
public maps: GoogleMapsService,
public platform: Platform,
public geolocation: Geolocation,
public viewCtrl: ViewController)
{
this.searchDisabled = true;
this.saveDisabled = true;
this.lat = params.get('lat');
this.lon = params.get('lon');
}
ionViewDidLoad(): void {
this.maps.init( this.mapElement.nativeElement,
this.pleaseConnect.nativeElement,
this.lat, this.lon).then(() => {
this.autocompleteService =
new google.maps.places.AutocompleteService();
this.placesService =
new google.maps.places.PlacesService(this.maps.map);
this.searchDisabled = false;
});
}
...
On:
- [2] S'ha afegit la classe NavParams per poder passar paràmetres a la pàgina.
- [8-9] S'han afegit membres a la classe per a guardar la posició inicial.
- [12] S'utilitza el controlador NavParams en la classe, per a rebre els paràmetres.
- [21-22] Es llegeixen i es guarden els paràmetres relacionats amb la posició.
- [28] Els paràmetres de la posició s'utilitzen en la crida init del servei GoogleMapsService.
I finalment només ens queda modificar la pàgina HomePage per afegir la funcionalitat. En el controlador home.ts:
...
import { LocationSelect } from '../location-select/location-select';
...
export class HomePage {
...
launchLocationPage() {
let modal = this.modalCtrl.create( LocationSelect,
{lat: this.lat, lon: this.lon});
modal.onDidDismiss((location) => {
if(location) {
console.log("Nou lloc: ", location);
this.lat = location.lat;
this.lon = location.lng;
this.posMsg = location.name;
this.posError = false;
this.getSunriseSunsetFromApi();
}
});
modal.present();
}
}
Hem afegit:
- [2] La importació de la nova pàgina per a seleccionar el lloc.
- [6-22] La funció launchLocationPage per mostrar la finestra de selecció de lloc. Observem com passem els paràmetres de la posició actual a la nova pàgina [8], i com s'actualitzen les dades i missatges en cas d'haver escollit un lloc, en el retorn de la pàgina [13-17].
En la part de visualització home.html, simplement activem la crida a la funció anterior:
...
<ion-item color="light" *ngIf="posError" (click)="launchLocationPage()">
<h2 text-wrap>No s'ha pogut obtenir la posició actual.</h2>
<p text-wrap>Verifica el GPS i/o els permisos.</p>
<ion-icon name="warning" color="danger" item-left></ion-icon>
</ion-item>
<ion-item (click)="launchLocationPage()">
<ion-label>Latitud</ion-label>
<ion-note item-right>{{ lat | number: "1.1-7" }}</ion-note>
</ion-item>
<ion-item (click)="launchLocationPage()">
<ion-label>Longitud</ion-label>
<ion-note item-right>{{ lon | number: "1.1-7" }}</ion-note>
</ion-item>
...
I ja ho tenim tot a punt ! Provem de seguida la nova funcionalitat:
Podem veure com el mapa s'obre en una nova finestra superposada, si té prou espai, i com permet escollir un lloc, auto-completant les opcions. En escollir-ne una, el mapa es posició en ella i, en guardar-la, s'utilitza per calcular les hores de sortida/posta del sol en la nostra aplicació:
Podem veure en la consola l'objecte retornat pel servei de Google Maps. Les seves propietats s'utilitzen per actualitzar les dades en la pàgina principal.
Com sempre, teniu tot el codi a la vostre disposició en el Github: v0.4 (amb Google Maps).
Ara ja tenim una aplicació funcional, però encara la podem completar en alguns aspectes. Per exemple, podríem afegir-hi traducció a diversos idiomes; també es poden fer alguns canvis estètics, amb icones personalitzades i tipus de lletra diferents; i finalment, completar el projecte donant les dades de contacte i afegint una pàgina per donar crèdit als projectes i persones que l'han fet possible.
Seguiu l'evolució de l'aplicació:
- En la sisena part afegirem traduccions a diversos idiomes.
- En la setena part personalitzarem icones i tipus de lletra.
Cap comentari:
Publica un comentari a l'entrada