Abbiamo già visto in un articolo precedente come interagire con Google Maps. In questo articolo ripercorriamo alcuni passi e vediamo come sfruttare l'interazione con la nostra applicazione aggingendo dei marker personalizzati.
Per utilizzare le Google Maps Api è necessaria una API Key ottenibile solo dai possessori di un account Google: l'api key è completamente gratuita e serve come identificativo per interfacciarsi con il sistema di mappe.
In fase di richiesta della chiave bisogna specificare l'indirizzo di un sito web: nel caso in cui stiamo sviluppando una web application dobbiamo specificare l'indirizzo del sito dove pubblicheremo l'applicazione; se stiamo sviluppando un'applicazione desktop (con Adobe AIR) dobbiamo specificare l'indirizzo del sito da cui sarà possibile scaricare l'applicazione.
Introdurre le mappe nell'applicazione
Per aggiungere una mappa alla nostra applicazione, per prima cosa dobbiamo scaricare l'SDK con le librerie per ActionScript e Flex dalla sezione del sito alle api per Flash.
Una volta scaricato il file sdk.zip
, lo estraiamo e aggiungiamo al build path del nostro progetto la libreria map_flex_1_18.swc
presente nella cartella lib/
.
Possiamo aggiungere la libreria al build path sia tramite la finestra di gestione delle proprietà del progetto (come mostrato in figura), sia copiando il file SWC all'interno della cartella libs/
del nostro progetto.
Iniziamo a sviluppare, quindi, una semplice applicazione che permette di ricercare un indirizzo e di centrare la mappa sulla relativa posizione. Il component che conterrà la mappa è un semplice contenitore di tipo UIComponent
:
<mx:UIComponent id="mapContainer"
width="100%" height="100%"
resize="mapContainerResize(event);" y="75" />
Il component di Google per gestire la mappa ha necessità di essere inizializzato: è necessario specificare l'Api Key, aggiungere i controlli per lo zoom o per selezionare la tipologia di mappa (stradale, satellite, ibrida) e bisogna registrare l'event listener sull'evento MapEvent.MAP_READY
.
Di seguito è riportato il codice del metodo che si preoccupa di effettuale l'inizializzazione dell'oggetto Map
e di aggiungere la mappa al contenitore mapContainer
. Il metodo deve essere invocato quando l'applicazione termina il caricamento (si può sfruttare l'evento CreationComplete
). Da notare anche l'aggiunta dei controlli per lo Zoom e il MapType
.
private function init() : void { googleMap = new Map(); googleMap.key = APIKEY; googleMap.addEventListener(MapEvent.MAP_READY, onGMapReady); googleMap.setSize(new Point(mapContainer.width, mapContainer.height)); googleMap.addControl(new ZoomControl()); googleMap.addControl(new MapTypeControl()); mapContainer.addChild(googleMap); }
Sull'oggetto Map
abbiamo dichiarato un eventListener
per l'evento MapEvent.MAP_READY
necessario per renderci conto dell'effettivo caricamento del component per la gestione della mappa.
Infatti, quando il component ha terminato il caricamento dobbiamo instanziare un oggetto di tipo ClientGeocoder che è fornito dalla libreria che stiamo utilizzando e che serve ad effettuare la traduzione di un dato geografico (come ad esempio il nome di una strada) in coordinate geografiche (latitudine e longitudine).
Per inizializzare l'oggetto che si deve preoccupare di effettuare il geocoding è necessario dichiarare due event listener, uno per gestire i risultati positivi delle richieste e uno per gestirne gli errori.
private function onGMapReady(evt:MapEvent) : void { geocoder = new ClientGeocoder(); geocoder.addEventListener(GeocodingEvent.GEOCODING_SUCCESS, geocoderResult); geocoder.addEventListener(GeocodingEvent.GEOCODING_FAILURE, geocoderFault); }
Quindi scriviamo i due event listener: per l'evento che gestisce i risultati del geocoding dobbiamo centrare la mappa nel punto che otteniamo come risultato della richiesta, mentre per l'evento che gestisce gli errori facciamo visualizzare un popup con un messaggio di errore.
private function geocoderResult(evt:GeocodingEvent):void { var result:Placemark = GeocodingResponse(evt.response).placemarks[0]; googleMap.setCenter(result.point, 16); } private function geocoderFault(evt:GeocodingEvent):void { Alert.show("Si è verificato un errore durante la ricerca: " + evt.name); }
A questo punto, possiamo gestire la ricerca di una città o di un indirizzo: siccome abbiamo già dichiarato gli event listener per gestire i risultati di una richiesta di geocoding dobbiamo solo implementare il metodo che effettua la richiesta.
Effettuare un richiesta di geocoding è molto semplice: bisogna soltanto invocare il metodo geocode()
dell'oggetto geocoder, che è di tipo ClientGeocoder
, passandogli come parametro la stringa da ricercare, come mostrato nel codice seguente.
private function onBtnGoToClick(evt:MouseEvent) : void { geocoder.geocode(tiAddress.text); }
Di seguito è riportato il codice completo dell'esempio. Tra i tag <fx:Declarations>
abbiamo l'istruzione fx:String
che legge il contenuto del file apikey.txt
(dove dobbiamo inserire l'api key che abbiamo attenuto da Google) e lo assegna alla variabile APIKEY
(che abbiamo utilizzato per l'inizializzazione dell'oggetto Map()
).
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init();">
<fx:Declarations>
<fx:String id="APIKEY" source="apikey.txt" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.google.maps.LatLng;
import com.google.maps.Map;
import com.google.maps.MapEvent;
import com.google.maps.controls.MapTypeControl;
import com.google.maps.controls.PositionControl;
import com.google.maps.controls.ZoomControl;
import com.google.maps.services.ClientGeocoder;
import com.google.maps.services.GeocodingEvent;
import com.google.maps.services.GeocodingResponse;
import com.google.maps.services.Placemark;
import mx.controls.Alert;
import mx.events.ResizeEvent;
private var googleMap:Map;
private var geocoder:ClientGeocoder;
private function init() : void {
googleMap = new Map();
googleMap.key = APIKEY;
googleMap.addEventListener(MapEvent.MAP_READY, onGMapReady);
googleMap.setSize(new Point(mapContainer.width, mapContainer.height));
googleMap.addControl(new ZoomControl());
googleMap.addControl(new MapTypeControl());
mapContainer.addChild(googleMap);
}
private function onGMapReady(evt:MapEvent) : void {
geocoder = new ClientGeocoder();
geocoder.addEventListener(GeocodingEvent.GEOCODING_SUCCESS, geocoderResult);
geocoder.addEventListener(GeocodingEvent.GEOCODING_FAILURE, geocoderFault);
}
private function geocoderResult(evt:GeocodingEvent):void {
var result:Placemark = GeocodingResponse(evt.response).placemarks[0];
googleMap.setCenter(result.point, 16);
}
private function geocoderFault(evt:GeocodingEvent):void {
Alert.show("Si è verificato un errore durante la ricerca: " + evt.name);
}
private function onBtnGoToClick(evt:MouseEvent) : void {
geocoder.geocode(tiAddress.text);
}
private function mapContainerResize(evt:ResizeEvent):void {
if (googleMap) {
googleMap.setSize(new Point(mapContainer.width, mapContainer.height));
}
}
]]>
</fx:Script>
<mx:ApplicationControlBar dock="true" width="100%" x="0" y="0">
<mx:Form styleName="plain">
<mx:FormItem label="Address:" direction="horizontal">
<mx:TextInput id="tiAddress" text="" />
<mx:Button id="btnGoTo" label="Vai a" click="onBtnGoToClick(event);" />
</mx:FormItem>
</mx:Form>
</mx:ApplicationControlBar>
<mx:UIComponent id="mapContainer" width="100%" height="100%"
resize="mapContainerResize(event);" y="73"/>
</s:Application>
Nell'esempio completo possiamo notare, oltre alle dichiarazioni degli oggetti di tipo Map
e ClientGeocoder
, la presenza di un metodo mapContainerResize
che serve ad aggiornare le dimensioni della mappa se la finestra viene ridimensionata. Inoltre è presente un component di tipo ApplicationControlBar
che contiene al suo interno il TextInput utilizzato per effettuare la ricerca di un indirizzo.
Posizionare i marker sulla mappa
Dopo aver realizzato la prima modalità di interazione con le Google Maps, ci focalizziamo sulla possibilità di posizionare dei marker sulle mappe. Partendo dall'esempio che abbiamo appena terminato di sviluppare, vogliamo posizionare il marker nel punto esatto che riceviamo come risultato della richiesta di geocoding.
Modifichiamo il metodo geocoderResult
aggiungendo il codice necessario al posizionamento del marker. Di seguito è riportato il codice modificato.
private function geocoderResult(evt:GeocodingEvent):void { var result:Placemark = GeocodingResponse(evt.response).placemarks[0]; googleMap.setCenter(result.point, 16); var marker:Marker = new Marker(result.point, new MarkerOptions({ fillStyle: new FillStyle({color: 0xFF3300, alpha: 0.8}), radius: 12, hasShadow: true }) ); marker.addEventListener(MapMouseEvent.CLICK, function(event:Event):void { marker.openInfoWindow(new InfoWindowOptions({content: result.address})); }); googleMap.addOverlay(marker); }
Quando riceviamo il risultato della richiesta di geocoding, dopo aver posizionato il centro della mappa, creiamo un marker. Il costruttore della classe Marker
riceve come parametri il punto (oggetto di tipo LatLng
) e le opzioni da associare al marker.
Successivamente dichiariamo l'event listener sul click del marker per poter gestire l'apertura di una "nuvoletta" (InfoWindow
) che contiene un testo (o anche uno o più component) associato al marker.
Alla fine dobbiamo aggiungere il marker alla mappa e lo facciamo invocando il metodo addOverlay(marker)
del nostro oggetto googleMap
.