$isBlue=rand(0,1); ?>
Posted at 29 March 2009 in RIA
Consumir los web services de Yahoo Maps (http://developer.yahoo.com/maps)

Los web services de Yahoo Maps permiten que se puedan integrar mapas interactivos en nuestras aplicaciones AIR y Flex. Mas especificamente, la API de Yahoo Maps permite que trabajemos con aplicaciones de mapas y todas sus funciones asociadas, lo cual agrega mucho valor a nuestras aplicaciones. Podemos encontrar una gran cantidad de servicios muy útiles en la web que consumen los web services de Yahoo! :
En este articulos vamos a ver como podemos consumir web services de Yahoo Maps desde HTML/Javascript y AIR.
Yahoo provee 2 APIs, de acuerdo al lenguaje de programación que usemos:
Esta doble posibilidad es perfecta cuando utilizamos la tecnología Adobe AIR, que permite integrar aplicaciones Ajax y ActionScript.
Antes de escribir código, registrense en http://developer.yahoo.com/wsregapp y obtengan un application ID.
Si usamos Ajax, el primer paso es importar la libreria “Yahoo Maps Ajax API” en nuestra pagina web:
<script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=YOUR-APP-ID"> </script>
Esta libreria no esta hosteada en nuestro server y no esta instalada. Recien cuando la pagina procesa el tag <script>, está lista para usar los mapas.
En este punto, podemos crear un contenedor en la página para mostrar el mapa:
<body>
<div id="Ymap"></div>
OTHER CONTENT
</body>
Lo único que hay que hacer ahora es agregar las funciones que controlan el objeto Map mediante JavaScript:
<style type="text/css"> #YMap { height: 400px; width: 500px; } </style> <script type="text/javascript"> var YMap function initYMap() { YMap = new YMap(document.getElementById('YMapDiv')); YMap.addPanControl(); YMap.addTypeControl(); YMap.addZoomLong(); YMap.drawZoomAndCenter("New York", 5); } window.onload = initYMap; </script> </head> <body> <div id="YMapDiv"></div> </body>
Este script, con algunas poquitas lineas de código, crea un mapa posicionado dentro de el div YMapDiv y agrega 3 controles del map:
"Pan" para poder movernos al norte, sur, este y oeste."Type” para poder cambiar entre satellite, hybrid y mapas normales."Zoom" para poder meternos y salir del mapa.Finalmente, drawZoomAndCenter especifica la posicion inicial del mapa (New York en el ejemplo) y el nivel inicial de zoom.
Si usamos el componente Yahoo Maps ActionScript 3, podemos embeber el mapa dentro de Flash, Flex, o AIR. Una vez que tenemos el application ID, en lugar de utilizar la API de Ajax, tendremos que bajarnos la librería de ActionScript (es un SWC) :
http://developer.yahoo.com/flash/maps/getLatest.php.
Los SWC son archivos que contienen componentes de Flash y Flex que facilitan el intercambio de componentes entre developers.
Luego de instalar el SWC, debemos instanciar un YahooMap para embeber un mapa:
import com.yahoo.maps.api.YahooMap; var mapContainer:UIComponent = new UIComponent(); Ymap.init("YOUR-APP-ID", stage.stageWidth, stage.stageHeight); mapContainer.addChild(Ymap); addChild(mapContainer);
En este punto tenemos que indagar un poco mas en las funcionalidades que nos brinda la API. Un buen paso para prepararnos, es mirar la documentacion de la API desde este link: http://developer.yahoo.com/flash/maps/classreference/index.html y el Reference Manual de Yahoo Maps Ajax API desde: http://developer.yahoo.com/maps/ajax/V3.8/index.html.
Otro buen recurso que nos va a ahorrar mucho tiempo, es aclarar los objetivos de nuestra integración. Deberíamos tener claro en este punto cual va a ser la utilidad del servicio que vamos a integrar y como el usuario lo va a utilizar. Para sacar ideas, es recomendable mirar la galeria publicada por Yahoo Maps: (http://gallery.yahoo.com/maps), que muestra ejemplos funcionales para utilizar como punto de partida para nuestra propia aplicación.
Este ejemplo usa la funcionalidad para controlar “markers” en los mapas y se guarda un search en un archivo XML local.
El primer paso es crear un MXML, llamado YMapsLocalSearch.as, para poder instanciar dentro de el un YahooMap :
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.controls.AdvancedDataGrid;
import com.yahoo.maps.api.intl.MapLocales;
import mx.collections.ArrayCollection;
import mx.events.ResizeEvent;
import com.yahoo.maps.webservices.geocoder.GeocoderResult;
import com.yahoo.maps.webservices.geocoder.GeocoderResultSet;
import com.yahoo.maps.webservices.geocoder.events.GeocoderEvent;
import com.yahoo.maps.api.core.location.Address;
import com.yahoo.maps.api.core.location.LatLon;
import com.yahoo.maps.api.YahooMapEvent;
import com.yahoo.maps.api.YahooMap;
import com.yahoo.maps.api.markers.SimpleMarker;
private const YAHOOID:String = " YOUR_APP_ID ";
private var _yahooMap:YahooMap;
private var _address:Address;
private var file:File;
private var stream:FileStream;
[Bindable] private var _geocoderResults:ArrayCollection;
private function init():void
{
// create YahooMap instance and listen for map initialize event
_yahooMap = new YahooMap();
_yahooMap.addEventListener(YahooMapEvent.MAP_INITIALIZE, handleMapInitialize);
_yahooMap.init(YAHOOID, mapContainer.width, mapContainer.height);
_yahooMap.addPanControl();
_yahooMap.addScaleBar();
_yahooMap.addTypeWidget();
_yahooMap.addZoomWidget();
mapContainer.addChild(_yahooMap);
_geocoderResults = new ArrayCollection();
gResultPanel.visible=false;
file = File.desktopDirectory.resolvePath("Ymarkers.xml");
stream = new FileStream();
if (file.exists)
{
stream.openAsync(file, FileMode.READ);
stream.addEventListener(ProgressEvent.PROGRESS,progressHandler);
stream.addEventListener(Event.COMPLETE, completeHandler);
return
}
}
El método addChild agrega el mapa al DisplayListde una instancia del UIComponent de nuestra aplicación:
<mx:UIComponent id="mapContainer" width="100%" bottom="0" top="35"/>
Un TextInput y un Button, que van a ser los principales elementos visuales de nuestro ejemplo, permiten al usuario insertar una direccion, verla en el mapa, y guardarla en un archivo loal. El handler del evento que responde al click es el siguiente:
private function getTextInput(evt:MouseEvent):void { var searchStr:String = searchInput.text; searchInput.text = "Looking up address..."; _address = new Address(searchStr); _address.addEventListener(GeocoderEvent.GEOCODER_SUCCESS, handleGeocodeSuccess); _address.geocode(); }
Cuando el evento GEOCODER_SUCCESS, contenido en la clase GeocoderEvent, se dispara, se hace una llamada al handler handleGeocodeSuccess , que recorre los resultados y los agrega al suggest list (nuestro TextInput en la pantalla:
private function handleGeocodeSuccess(event:GeocoderEvent):void { var geocoderResults:GeocoderResultSet = _address.geocoderResultSet; // if we only have one result, set the location right away. if(geocoderResults.found == 1) { setLocation(geocoderResults.firstResult); } else if(geocoderResults.found > 1) { // loop through each result and add an item to the suggest list. _geocoderResults = new ArrayCollection(); var len:int = results.length; for(var i:int=0; i<len; i++) { var result:GeocoderResult = results[i]; var data:Object = { label: result.getLineAddress(), data:result } _geocoderResults.addItem(data); } //show the suggestions panel gResultPanel.visible=true; }else{ // reset the text searchInput.text = ""; } }
Podemos especificar tambien el centro del mapa utilizando el metodo setLocation. Un marker se crea dinamicamente mediante la clase SimpleMarker , y es posicionado en la direccion especificada en el TextInput. Finalmente, el metodo saveMarker es inovado, que escribe en el archivo local:
private function setLocation(geocoderResult:GeocoderResult):void { _yahooMap.zoomLevel = geocoderResult.zoomLevel; _yahooMap.centerLatLon = geocoderResult.latlon; searchInput.text = geocoderResult.getLineAddress(); var marker:SimpleMarker = new SimpleMarker(); marker.address = new Address(geocoderResult.getLineAddress()); _yahooMap.markerManager.addMarker(marker); saveMarker(geocoderResult.getLineAddress()) }
El Geocoder permite que se pueda buscar una latitud y longitud específica para una direccion, mientras que la clase GeocoderEvent representa el objeto del evento que es pasado al listener para el evento que dispara el objeto Geocoder.
El código completo para la aplicación es el siguiente:
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" layout="absolute" showFlexChrome="false" showStatusBar="false"> <mx:Script> <![CDATA[ import mx.controls.Alert; import mx.controls.AdvancedDataGrid; import com.yahoo.maps.api.intl.MapLocales; import mx.collections.ArrayCollection; import mx.events.ResizeEvent; import com.yahoo.maps.webservices.geocoder.GeocoderResult; import com.yahoo.maps.webservices.geocoder.GeocoderResultSet; import com.yahoo.maps.webservices.geocoder.events.GeocoderEvent; import com.yahoo.maps.api.core.location.Address; import com.yahoo.maps.api.core.location.LatLon; import com.yahoo.maps.api.YahooMapEvent; import com.yahoo.maps.api.YahooMap; import com.yahoo.maps.api.markers.SimpleMarker; private const YAHOOID:String = " YOUR_APP_ID "; private var _yahooMap:YahooMap; private var _address:Address; private var file:File; private var stream:FileStream; [Bindable] private var _geocoderResults:ArrayCollection; private function init():void { // create YahooMap instance and listen for map initialize event _yahooMap = new YahooMap(); _yahooMap.addEventListener(YahooMapEvent.MAP_INITIALIZE, handleMapInitialize); _yahooMap.init(YAHOOID, mapContainer.width, mapContainer.height); _yahooMap.addPanControl(); _yahooMap.addScaleBar(); _yahooMap.addTypeWidget(); _yahooMap.addZoomWidget(); mapContainer.addChild(_yahooMap); _geocoderResults = new ArrayCollection(); gResultPanel.visible=false; file = File.desktopDirectory.resolvePath("Ymarkers.xml"); stream = new FileStream(); if (file.exists) { stream.openAsync(file, FileMode.READ); stream.addEventListener(ProgressEvent.PROGRESS,progressHandler); stream.addEventListener(Event.COMPLETE, completeHandler); return } } private function handleMapInitialize(event:YahooMapEvent):void { mapContainer.addEventListener(ResizeEvent.RESIZE, handleContainerResize); _yahooMap.zoomLevel = 13; _yahooMap.centerLatLon = new LatLon(40.81,-96.7); } private function handleContainerResize(event:ResizeEvent):void { _yahooMap.setSize( mapContainer.width, mapContainer.height ); } private function getTextInput():void { var searchStr:String = searchInput.text; searchInput.text = "Looking up address..."; _address = new Address(searchStr); _address.addEventListener(GeocoderEvent.GEOCODER_SUCCESS, handleGeocodeSuccess); _address.geocode(); } private function handleGeocodeSuccess(event:GeocoderEvent):void { var geocoderResults:GeocoderResultSet = _address.geocoderResultSet; var results:Array = geocoderResults.results; // if we only have one result, set the location right away. if(geocoderResults.found == 1) { setLocation(geocoderResults.firstResult); } else if(geocoderResults.found > 1) { // loop through each result and add an item to the suggest list. _geocoderResults = new ArrayCollection(); var len:int = results.length; for(var i:int=0; i<len; i++) { var result:GeocoderResult = results[i]; var data:Object = { label: result.getLineAddress(), data:result } _geocoderResults.addItem(data); } //show the suggestions panel gResultPanel.visible=true; }else{ // reset the text searchInput.text = ""; } } private function setLocation(geocoderResult:GeocoderResult):void { _yahooMap.zoomLevel = geocoderResult.zoomLevel; _yahooMap.centerLatLon = geocoderResult.latlon; searchInput.text = geocoderResult.getLineAddress(); var marker:SimpleMarker = new SimpleMarker(); marker.address = new Address(geocoderResult.getLineAddress()); /* marker.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); marker.addEventListener(Event.REMOVED_FROM_STAGE, onRemoved); */ _yahooMap.markerManager.addMarker(marker); saveMarker(geocoderResult.getLineAddress()) } private function handleListChange():void { // get the selected geocoder result object var selectedResult:GeocoderResult = geocoderResultsList.selectedItem.data as GeocoderResult; setLocation(selectedResult); _geocoderResults.removeAll(); gResultPanel.visible=false; } private function saveMarker(add:String):void { var xmlData:XML = <marker/>; xmlData.address = add; xmlData.saveDate = new Date().toString() var outputString:String = '<?xml version="1.0" encoding="utf-8"?>\n'; outputString += xmlData.toXMLString(); outputString = outputString.replace(/\n/g, File.lineEnding); stream.open(file, FileMode.WRITE); stream.writeUTFBytes(outputString); stream.close(); } private function progressHandler(event:ProgressEvent):void { // opening in progress .... } private function completeHandler(event:Event):void { var xmlData:XML = XML(stream.readUTFBytes(stream.bytesAvailable)); stream.close(); var searchStr:String = xmlData.address; searchInput.text = "Looking up address..."; _address = new Address(searchStr); _address.addEventListener(GeocoderEvent.GEOCODER_SUCCESS, handleGeocodeSuccess); _address.geocode(); } ]]> </mx:Script> <mx:UIComponent id="mapContainer" width="100%" bottom="0" top="35"/> <mx:Canvas id="header" width="100%" height="35" backgroundColor="#E5E5E5" backgroundAlpha="0.85"> <mx:TextInput id="searchInput" width="275" verticalCenter="0" left="15" enter="getTextInput();"/> <mx:Button label="Search and Save" cornerRadius="1" verticalCenter="0" left="288" click="getTextInput()"/> </mx:Canvas> <mx:Panel width="343" height="200" layout="absolute" id="gResultPanel" title="Results" left="35" top="45"> <mx:List left="0" right="0" top="0" bottom="0" id="geocoderResultsList" dataProvider="{_geocoderResults}" change="handleListChange();"/> </mx:Panel> </mx:WindowedApplication>
Espero que les sirva y hasta el próximo post!
Posted by Franco Breciano