domingo, 14 de diciembre de 2008

Mysql Y google maps, retornar puntos dentro de el area visible(BOUNDS)

En mi caso tengo una base de datos con alrededor de 25.000 lugares georeferenciados, de ellos alrededor de 500 estan sin latitud y longitud.

Inicialmente hice un sistema que recogia datos a partir de un radio determinado y lo dibujaba en google maps, afortunadamente me "Hackearon ese sitio", aprovechando el metodo put de apache y mi descuido en los permisos de una carpeta, lo que me llevo a replantearme la forma de hacer las cosas.

Ahora pensaba en algo mas automatizado, que fuera como panoramio por ejemplo, el problema es que yo no cuento con una base de datos geoespacial, solo cuento con Postgresql y Mysql en mi hosting y ambos estan sin extensiones GIS(Postgis por ejemplo).

Asi que me puse a investigar aquello de los Bounds o limites que maneja google, y me di cuenta que se basa solo en 2 referencia, una esquina sud oeste y una esquina Sudeste.

Asi que primero probe un codigo HTML de ejemeplo sacado de la pagina de google maps y le agregue esto:

var bounds = map.getBounds();

var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();

document.write("NORESTE"+northEast+"
Sudoeste" +southWest);

De este modo logre imprimir en pantalla:

NORESTE(-37.429069455303306, -72.27424621582031)
Sudoeste(-37.510815198076536, -72.44590759277344)

Y como yo sabia que en ese lugar tenia aprox 120 lugares georeferenciados hice la consulta correspondiente:

select titulo, latitud, longitud from lugares where latitud BETWEEN '-37.429069455303306' and '-37.510815198076536' AND longitud between '-72.27424621582031' and '-72.44590759277344'

primero le digo que latitud este entrela latitud del noreste y la latitud del sudoeste, luego le digo que la longitud debe estar entre las longitude del noreste y sudoeste, bueno si no tuviera between, podria usar < >, pero creo que BETWEEN era lo que necesitaba.

Teniendo esto, es solo cuestion de programar la aplicacion JS/Ajax que pida los datos a un archivo php que genere un kml, json o lo que prefieran con el listado de latitud y longitud de cada lugar que quieran mostrar en el mapa.

Pero y si tienen 25.000 lugares como yo?

y alguien pone el mapa en zoom 0 ?

ahi lo que queda es manejar clusters, definir que cosas mostrar o cuantas segun el nivel de zoom que nos indique la api de google.

Cuando tenga un codigo funcional con todo esto implementado lo publicare

miércoles, 30 de julio de 2008

Manual en castellano sobre Webservices, excelente

Luego de pasar mucho tiempo buscando informacion sobre los webservices di con este manual, un tanto antiguo pero que deja las cosas bien claras, es parte de un magister de Software libre de la unviersidad UOL

El manual para descarga puede ser encontrado en este lugar:

http://www.uoc.edu/masters/oficiales/master_oficial_software_libre/master_oficial_software_libre_materiales.htm



Mas adelante creare una version reducida del manual y la forma de crearlos de forma exitosa ya que la mayorai de los manuales no son muy detallados y siempre dejan vacios, por mientras pueden visitar el manual que di antes el cual posee aproximado 350 paginas.

miércoles, 20 de febrero de 2008

Hack the "autoReCenterZoom" function of Mike Williams fix 'sorry' message/Hack a la funcion de Mike Williams para evitar el mensaje de error zoom

Mike Williams es sin duda una de las personas que mas ejemplos para google maps ha dado, de hecho mis comiensos fueron leyendolo a el.

Pero sus ejemplos no son perfectos en uno de ellos se proponia establecer un autozoom a partir de los datos cargados desde xml, pero si en lugar de tener 10 puntos tenemos 2 0 1 y separados a corta distancia lo mas probable es que el zoom se establesca al maximo que da google maps, pero con el mensaje de error, sobre todo cuando se trata de zonas deshabitadas en donde los niveles de zoom son menores.

Por eso modifique un script hecho por el, me base en otro que encontre en la red, pero lamentablemente no recuerdo quien fue el autor:

El resultado final seria esto:

if (GBrowserIsCompatible()) {
var side_bar_html = "";
var gmarkers = [];
var htmls = [];
var polys = [];
var labels = [];
var i = 0;

// === Specifiy Icons ====
var gicons = new GIcon();
GIcon.iconSize=new GSize(12,20);
GIcon.shadow = "img/mm_20_shadow.png";
GIcon.shadowSize=new GSize(22,20);
GIcon.iconAnchor=new GPoint(6,20);
GIcon.infoWindowAnchor=new GPoint(5,1);
GIcon.infowindowanchor=new GPoint(18,25);
GIcon.transparent = "img/mm_20_transparent.png";

// === Create an associative array of GIcons() ===
var gicons = [];
gicons["0"] = new GIcon(GIcon, "img/mm_20_3d_red.png");
gicons["1"] = new GIcon(GIcon, "img/mm_20_3d_blue.png");
gicons["2"] = new GIcon(GIcon, "img/mm_20_3d_yellow.png");
gicons["4"] = new GIcon(GIcon, "img/mm_20_3d_blueyellow.png");

// Function to specify the ZIndex of each marker according to the "importance" specified later.
// This is called in the function that creates the marker. The importance value is set during
// the loop through the points after the marker creation call is made, but before it is added to the map.
function setZIndex(marker,b) {
return marker.importance;
}

// the icon information is passed to this function
function createMarker(point,name,html,icontype,categoria) {
var marker = new GMarker(point, {icon: gicons[icontype], zIndexProcess:setZIndex});
marker.tooltip = '
'+name+'
'; // store the tooltip text
marker.micategoria = categoria;
marker.elnombre=name;
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);

});






// ==== save the info we need to use later for the side_bar
gmarkers[i] = marker;
htmls[i] = html;
var i2=i+1;
// ==== add a line to the side_bar html
if (name!="") side_bar_html += ''+i2+' '+name+'
';
i++;
// ====== The new marker "mouseover" and "mouseout" listeners ======
GEvent.addListener(marker,"mouseover", function() {
showTooltip(marker);
});
GEvent.addListener(marker,"mouseout", function() {
tooltip.style.visibility="hidden"
});
return marker;
}

// ====== This function displays the tooltip ======
// it can be called from an icon mousover or a side_bar mouseover
function showTooltip(marker) {
// only generate tooltip display if it contains real data (null value is
)
if (marker.tooltip.length > 27) {
tooltip.innerHTML = marker.tooltip;
var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.fromDivPixelToLatLng(new GPoint(0,0),true),map.getZoom());
var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),map.getZoom());
var anchor=marker.getIcon().iconAnchor;
var width=marker.getIcon().iconSize.width;
var height=tooltip.clientHeight;
var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(offset.x - point.x - anchor.x + width, offset.y - point.y -anchor.y -height));
pos.apply(tooltip);
tooltip.style.visibility="visible";
} // end if
} //end of functionshowTooltip

// ===== This function is invoked when the mouse goes over an entry in the side_bar =====
// It launches the tooltip on the icon
function mymouseover(i) {
showTooltip(gmarkers[i]);
}

// ===== This function is invoked when the mouse leaves an entry in the side_bar =====
// It hides the tooltip
function mymouseout() {
tooltip.style.visibility="hidden";
}


function myclick(i) {
gmarkers[i].openInfoWindowHtml(htmls[i]);
}


// set up for auto bounds calculation (bounds get extended as each point is read in)
var bounds = new GLatLngBounds();

var map = new GMap2(document.getElementById("map"));
// Put the loading message underneath the tiles
document.getElementById("map").style.backgroundImage = "url(515-500loading.jpg)";




var arribaDerecha = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,30));
var arribaDerecha2 = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(110,60));





map.addControl(new GLargeMapControl(), arribaDerecha2);
map.addControl(new GMapTypeControl(), arribaDerecha);
map.setCenter(new GLatLng(-33.1423258088452,-71.5579196742649),12);


map.setMapType(G_HYBRID_TYPE)

// ====== set up marker mouseover tooltip div ======
var tooltip = document.createElement("div");
map.getPane(G_MAP_FLOAT_PANE).appendChild(tooltip);
tooltip.style.visibility="hidden";


// ======== Add a scale in km, upper bar only
var _mPreferMetric = true;
var scale = new GScaleControl();
map.addControl(scale);
scale.fpsLbl.style.visibility="hidden";
scale.fpsBar.style.visibility="hidden";


// ========= cargar postes
var request = GXmlHttp.create();
request.open("GET", elservidor+"/xml/xml_pol_lineas.php?accion=postes&id_empresa="+id_empresa+"&periodo_star="+periodo_star+"&concesion_id="+concesion_id+"&poligonal_id="+poligonal_id+"&proyecto_id="+proyecto_id+"&linea_id="+linea_id, true);
request.onreadystatechange = function() {
if (request.readyState == 4) {
var xmlDoc = request.responseXML;
// ========= obtain the array of markers and loop through it
var postes = xmlDoc.documentElement.getElementsByTagName("poste");
var markerlengthss=postes.length;

if(markerlengthss>0){
for (var i = postes.length-1; i >=0; i--) {
// for (var i = 0; i < markers.length; i++) {
// =========obtain the attribues of each marker
var lat = parseFloat(postes[i].getAttribute("lat"));
var lng = parseFloat(postes[i].getAttribute("lng"));
var point = new GLatLng(lat,lng);
var html = postes[i].getAttribute("html");
var label = postes[i].getAttribute("label");
//mp var icontype = parseInt(markers[i].getAttribute("icontype"));
var icontype = postes[i].getAttribute("icontype");
// ======== create the marker
var poste = createMarker(point,label,html,icontype,'postes');
poste.importance = i;
if (icontype > 0) poste.importance = i+10000;
map.addOverlay(poste);

// ==== Each time a point is found, extend the bounds to include it =====




bounds.extend(point);

}

}







function autoReCenterZoom2 (bounds){

// Some map center and zoom must have been specified already - i.e. this does a re-center/zoom
// uses built-in bounds function
// Map center is average of max/min lat & long
var centerlat = (bounds.getNorthEast().lat() + bounds.getSouthWest().lat()) /2;
var centerlng = (bounds.getNorthEast().lng() + bounds.getSouthWest().lng()) /2;





// adjust if some points are across the dateline (i.e. >0 longitude) so the center point isn't in Africa
if (centerlng > -45) centerlng=centerlng+180;
map.setCenter(new GLatLng(centerlat,centerlng));

//built-in function to calc zoom
// set zoom out by 1 so points are not hidden by controls
var zoomb=map.getBoundsZoomLevel(bounds)-0;



var maptype = map.getCurrentMapType();
var nombredelmapa=maptype.getName(false);

switch(nombredelmapa)
{
case "Híbrido":
var laresolucion=G_HYBRID_MAP.getMaximumResolution();
break;
case "Satélite":
var laresolucion=G_SATELLITE_MAP.getMaximumResolution();
break;
case "Terreno":
var laresolucion=G_PHYSICAL_MAP.getMaximumResolution();
break;
case "Mapa":
var laresolucion=G_MAP_TYPE.getMaximumResolution();
break;
default : var laresolucion=G_MAP_TYPE.getMaximumResolution();

}
if(zoomb>laresolucion){
var resta=zoomb-laresolucion;
var newzoomb=zoomb-resta;
map.setZoom(newzoomb-1);
//alert(newzoomb);
}else{
map.setZoom(zoomb);
}


} //end of function autoCenterZoom





// ======== Add a map overview ==========
map.addControl(new GOverviewMapControl(new GSize(150,150)));

// ======== A function to adjust the positioning of the overview ========
function positionOverview(x,y) {
var omap=document.getElementById("map_overview");
omap.style.left = x+"px";
omap.style.top = y+"px";

// == restyling ==
omap.firstChild.style.border = "1px solid gray";

omap.firstChild.firstChild.style.left="2px";
omap.firstChild.firstChild.style.top="2px";
omap.firstChild.firstChild.style.width="145px";
omap.firstChild.firstChild.style.height="145px";
}

// ======== Cause the overview to be positioned AFTER IE sets its initial position ========
//setTimeout("positionOverview(558,254)",1);



// ========= Now process the polylines ===========
// var lines = xmlDoc.documentElement.getElementsByTagName("line");
// read each line
// for (var a = 0; a < lines.length; a++) {
// get any line attributes
// var colour = lines[a].getAttribute("colour");
// var width = parseFloat(lines[a].getAttribute("width"));
// read each point on that line
// var points = lines[a].getElementsByTagName("point");
// var pts = [];
// for (var i = 0; i < points.length; i++) {
// pts[i] = new GLatLng(parseFloat(points[i].getAttribute("lat")),
//// parseFloat(points[i].getAttribute("lng")));
// bounds.extend(pts[i]);
// }
// map.addOverlay(new GPolyline(pts,colour,width));

//}
// ================================================

// ========== Rellena la barra de contenidos con los datos de los postes
document.getElementById("side_bar").innerHTML = side_bar_html;
if(bounds.getSouthWest().lng()<180){
autoReCenterZoom2(bounds);
}
// map.setCenter(new GLatLng(-29.867, -71.241),12);
map.savePosition(); //store center/zoom for use by "return to last result" button




}
}
request.send(null);
}




// ==== fin de los postes
// == mostrar todos los puntos de una categoria determinada ==
function muestra(category) {
for (var i=0; i if (gmarkers[i].micategoria == category) {
gmarkers[i].show();
}
}
// == check the checkbox ==
document.getElementById(category+"box").checked = true;
}

// == hides all markers of a particular category, and ensures the checkbox is cleared ==
function esconde(category) {
for (var i=0; i if (gmarkers[i].micategoria == category) {
gmarkers[i].hide();
}
}
// == clear the checkbox ==
//document.getElementById(category+"box").checked = false;
// == close the info window, in case its open on a marker that we just hid
map.closeInfoWindow();

}

// == a checkbox has been clicked ==
function boxclick(box,category) {
if (box.checked) {

muestra(category);
} else {
esconde(category);

}
// == rebuild the side bar
makeSidebar();
}


function makeSidebar() {

var html = "";
for (var i=0; i var i2=i+1;
if (!gmarkers[i].isHidden()) {
html += ''+i2+' '+gmarkers[i].elnombre+'
';
}
}
document.getElementById("side_bar").innerHTML = html;
}


/* // ==== save the info we need to use later for the side_bar
gmarkers[i] = marker;
htmls[i] = html;
var i2=i+1;
// ==== add a line to the side_bar html
if (name!="") side_bar_html += ''+i2+' '+name+'
';
i++;
// ====== The new marker "mouseover" and "mouseout" listeners ======*/

sábado, 5 de enero de 2008

Ejemplos de usos de las api de google maps

Quiero comenzar con un listado de ejemplos utiles para google maps, al menos yo soy de los que aprenden mirando codigo fuente, asi entiendo mejor que leyendo explicaciones largas y aburridas, en los proximos post dedicare mas tiempo a explicar lo que expongo aqui:

Apuntes de Mike Williams: Muchos ejemplos para google maps, utiles para principiantes de google maps, siempre es bueno tener algo de conocimiento GIS para hacer mejor las cosas o comprender mas rapido lo que mike williams enseña, eso si deben tener cierto dominio del ingles escrito para entenderlo, pero para los que no saben, mas adelante explicare cada ejemplo en castellano y con algunas mejoras.

Existen muchas extensiones para las api de google maps, a continuacion listare algunas, lo que hacen y su url.

Llenar Poligonos: Permite dibujar poligonos, con colores de relleno, util para marcar areas geograficas o realizar mapas estadisticos o de cambios demograficos, etc.
Autor goldnbr1.
Visitar pagina de ejemplo


Visitar pagina Informativa

Cluster de Markers: Permite utilizar un gran numero de Markers, pero con el beneficio de reunirlos segun el nivel de zoom en un cluster o grupo de markers, por ejemplo si entramos en un zoom de nivel 2 veremos solo iconos grandes que representen el cluster de markers para esa region, ya que con un nivel de zoom 2 una ciudad entera puede verse en un area de 4 pixel con suerte, es asi como un cluster nos permite agrupar markers y mostrarlos todos segun el nivel de zoom en que nos encontremos, ademas permite evitar los desbordes de memoria en algunos navegadores.

Autor:Jef Poskanzer
Visitar pagina de ejemplo
Visitar ejemplo de Mike williams

.....
Continuara, proximamente editare este mismo post para dejarlo con el maximo de informacion util.

jueves, 3 de enero de 2008

Aprendiendo sobre google maps y otras hierbas

Debido a mi actual situacion profesional, trabajando para una entidad estatal, he tenido que aprender a fondo sobre google maps y GIS en general, aunque con anterioridad ya habia desarrollado un software de caracteristicas GIS( http://www.geoturismo.cl y www.renthouse.cl) nunca habia trabajado con tal densidad de informacion, mi costumbre era solo trabajar con miles de datos, pero ahora trabajo con millones de datos.

Este blog lo dejare para mis anotaciones sobre lo que he aprendido y lo que aprenda en el futuro, espero que sea de utilidad a todos ya que hay nula informacion al respecto en castellano, y todo se remite a burdas copias de los ejemplos basicos disponibles en la web de google maps.

Es asi como pretendo abarcar cosas mas complejas con google maps., como por ejemplo cargar capas wms, pero a su vez darles un limite en los zooms a utilizar, tambien intentare modificar o crear nuevas librerias javascripts para trabajar con google maps.

Me basare en la version 2 de la api, porque ya he probado que hay mayor compatibilidad entre scripts para esta version, que en versiones superiores.


Un saludo y a divertirese aprendiendo!!!