Combinar Google Maps con jQuery Autocomplete en ASP.Net

Hola tyros!

En esta ocasión les voy a mostrar como combinar jQuery Autocomplete y Google Maps

Imagina que tienes un negocio con sucursales en varios puntos del planeta. Si conoces las coordenadas (Latitud y Longitud) puedes ponerlas en una base de datos y diseñar una pequeña aplicación que te permita mostrar sus posiciones en los mapas de Google, ¡Incluso trazar una ruta de como llegar!
El proceso es bastante sencillo, solo pon mucha atención en los detalles de éste tutorial y, en unos pocos minutos, serás capaz de tener tus sucursales, o lo que sea que desees, en los mapas de Google. Además, si es posible, también podrás mostrar la ruta de como llegar.

Requisitos previos:

1. Conocimientos básicos de ASP.Net, C# y SQL Server
2. Una clave de Google maps, consíguela aquí
3. Certificado SSL (Opcional si deseas publicar en internet)

Estas son las imágenes que utilizaremos para los marcadores:


En mi base de datos SQL Server tengo una tabla llamada "ubicaciones", con los siguientes datos:

Comencemos


Lo primero que haremos es agregar una página ASP.Net llamada "autocomplete-google-maps.aspx", con el siguiente código base:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="autocomplete-google-maps.aspx.cs" Inherits="examples_autocomplete_google_maps" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
        </div>
    </form>
</body>
</html>

Lo primero que haremos es agregar las referencias CSS y javascript. Agregamos las siguientes líneas en el head del documento:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=CLAVE_GOOGLEMAPS"></script>

Luego, modificamos el body, para que quede así:

<body>
    <form id="form1" runat="server">
        <div class="container">
            <h1>Google Maps y jQuery Autocomplete</h1>
            <hr />
            <div class="row">
                <div class="col-sm-12">
                    <div class="form-group">
                        <asp:TextBox ID="txtBuscar" placeholder="Lugar a buscar..." CssClass="form-control" runat="server"></asp:TextBox>
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-sm-12">
                    <div class="panel panel-primary">
                        <div class="panel-body">
                            <div id="map" style="width: 100%; height: 450px;"></div>
                            <div id="tdCursor">Lat: 0, Lng: 0</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </form>
</body>

Inmediatamente después de la etiqueta form, agregaremos un bloque script, como se muestra:

<body>
    <form id="form1" runat="server">
        ...
    </form>
 <script type="text/javascript">
 </script>
</body>

Ya dentro del script, declaramos las variables que vamos a utilizar:

//>>Inicia declaración de variables
var map; //Objeto MAPA
var infowindow; //Objeto para ventanas
var latitud = 23.743338; //Latitud inicial
var longitud = -99.143684; //Longitud Inicial
var directionsService; //Objeto para el servicio de instrucciones
var directionsDisplay; //Objeto para mostrar instrucciones
var myCurrentPosition; //Posición Actual
var markers = []; //Arreglo para agregar marcadores
//<<Termina declaración de variables

La primera parte de nuestro ejercicio consiste en mostrar nuestra posición en el mapa. Primero, agregamos dos funciones:

//Funcion para inicializar mapa
function initMap() {
    directionsDisplay = new google.maps.DirectionsRenderer();
    map = new google.maps.Map(document.getElementById('map'), {
        center: { lat: latitud, lng: longitud },
        scrollwheel: false,
        zoom: 13
    });
    directionsDisplay.setMap(map);
    map.addListener("mousemove", function (event) {
        displayCoordinates(event.latLng);
    });
}
//Función para desplegar coordenadas del mouse
function displayCoordinates(pnt) {
    var coordsLabel = document.getElementById("tdCursor");
    var lat = pnt.lat();
    lat = lat.toFixed(4);
    var lng = pnt.lng();
    lng = lng.toFixed(4);
    coordsLabel.innerHTML = "Lat: " + String(lat) + "  Lng: " + String(lng);
}

Luego, el código que muestra el mapa y nuestra ubicación:

//Mostramos el mapa y marcamos nuestra posición
$(document).ready(function () {
    $(window).load(function () {
        //Inicializar variables
        infowindow = new google.maps.InfoWindow({});
        directionsService = new google.maps.DirectionsService();
        //Inicializar mapa
        initMap();
        //Obtener la posición actual
        /*
        Nota Importante: Esta funcionalidad solo funciona de manera local.
        Para poder utilizarla en una página web se requiere conexión segura;
        es decir, se requiere la utiliación de un certificado SSL.
        */
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(
                function (position) {
                    /*Obtener coordenadas*/
                    console.log("Obteniendo coordenadas...");
                    var point = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
                    myCurrentPosition = point;
                    map.setZoom(16);
                    map.setCenter(point);
                    google.maps.event.trigger(map, "resize");//actualizar mapa
                    var myPos = new google.maps.Marker({
                        position: point,
                        map: map,
                        icon: "../img/ico_green.png",
                        title: "Mi posición actual"
                    });
                    myPos.addListener('click', function () {
                        infowindow.setContent("<i class='glyphicon glyphicon-home'></i>" +
                            "<h3>Esta es mi posición actual</h3>" +
                            "<small><a href='www.tyrodeveloper.com'>www.tyrodeveloper.com</a></small>");
                        infowindow.open(map, myPos);
                    });
                },
                function (err) {
                    /*En caso de fallar al obtener las coordenadas*/
                    console.log('GPS Desactivado.');
                    /*Establecer la posición predeterminada*/
                    myCurrentPosition = new google.maps.LatLng(latitud, longitud);
                }
            );
        }

    });
});

Hasta este punto, nuestra página debe mostrar algo parecido a los siguiente:

Te recomiendo no continuar, hasta que hayas conseguido visualizar el mapa.

Ahora, haremos funcionar el jQuery autocomplete.

En el código C#, de las siguientes directivas using, agregamos la que haga falta:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Web.Script.Serialization;
using System.Web.Script.Services;
using System.Web.Services;

Primero, declaramos una estructura, a cual nos servirá como base para generar un resultado Json:

struct Result
{
    public string id;
    public string value;
}

Luego, agregamos un WebMethod, el cual se encargará de generar la información que se va a mostrar cuando escribamos algo en el TextBox:

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static String BuscarLugar(String textoBuscar)
{
    SqlConnection cnn = new SqlConnection("Data Source=.;Initial Catalog = ejemplos; User Id=sa;Password = db9921868");
    try
    {
        cnn.Open();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = cnn;
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = @"select id_ubicacion, nombre 
            from ubicaciones 
            where nombre like '%' + @nombre + '%'";
        cmd.Parameters.Add("@nombre", SqlDbType.NVarChar, 50).Value = textoBuscar;
        SqlDataReader dr = cmd.ExecuteReader();
        List<Result> result = new List<Result>();
        while (dr.Read())
        {
            result.Add(new Result()
            {
                id = dr["id_ubicacion"].ToString(),
                value = dr["nombre"].ToString()
            });
        }

        dr.Close();
        return new JavaScriptSerializer().Serialize(result);
    }
    catch (Exception ex) { throw (ex); }
    finally { cnn.Close(); cnn.Dispose(); }
}

Ahora, debemos regresar del lado de código javascript. Agregamos la siguiente función:

//Función para buscar cuando se escriba algo en el Textbox
$("#<%=txtBuscar.ClientID%>").autocomplete({
    source: function (request, response) {
        /*Aquí se configura el origen de datos*/
        $.ajax({
            type: 'POST',
            url: "autocomplete-google-maps.aspx/BuscarLugar",
            data: "{textoBuscar: '" + request.term + "'}",
            dataType: "json",
            contentType: 'application/json',
            async: false,
            success: function (result) {
                response($.parseJSON(result.d));
            }
        });
    },
    search: function () {
        /*Este evento sucede mientras se escribe algo en el TextBox*/
        // Condicionar a menos 3 
        // caracteres en la búsqueda
        var term = this.value;
        if (term.length < 3) {
            return false;
        }
    },
    focus: function () {
        /*Este evento sucede cuando el TextBox obtiene el foco*/
        // Evitar que el valor se inserte cuando 
        // el TextBox obtenga el foco
        return false;
    },
    select: function (event, ui) {
        /*Este evento sucede cuando se selecciona uno de los resultados*/
        // Asignar el valor al TextBox
        this.value = ui.item.value;
        // Mostrar el ID
        alert(ui.item.id);//***ATENCION EN ESTA LINEA, LA MODIFICAREMOS MAS ADELANTE***/
        return false;
    }
});

Es momento de detenernos y comprobar si hemos hecho bien las cosas.

Ejecutamos nuestra página. Si escribimos algo en el TextBox, deberán mostrarse las coincidencias; además, si seleccionamos uno de los resultados, debe mostrarnos una alerta con el respectivo id:

Nuevamente, recomiendo detenerse aquí hasta lograr que funcione correctamente.

Mostrar un marcador cuando se seleccione un elemento

Como vimos, cuando seleccionamos un elemento de la lista de autocompletar, se muestra una alerta. Vamos a cambiar, la alerta, por un marcador.

Primero, de lado del código C#, agregamos una estructura, la cual nos servirá para generar un resultado tipo Json:

struct Ubicacion
{
    public string IdUbicacion;
    public string Nombre;
    public string Descripcion;
    public string Foto;
    public string Lat;
    public string Lng;
}

Luego, agregamos un WebMethod, para realizar una consulta a la base de datos:

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static String BuscarUbicacion(int idUbicacion)
{
    SqlConnection cnn = new SqlConnection("Data Source=.;Initial Catalog = ejemplos; User Id=sa;Password = db9921868");
    try
    {
        cnn.Open();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = cnn;
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = @"select * 
            from ubicaciones 
            where id_ubicacion=@id_ubicacion";
        cmd.Parameters.Add("@id_ubicacion", SqlDbType.Int).Value = idUbicacion;
        SqlDataReader dr = cmd.ExecuteReader();
        Ubicacion result = new Ubicacion();
        if (dr.Read())
        {
            result = new Ubicacion()
            {
                IdUbicacion = dr["id_ubicacion"].ToString(),
                Nombre = dr["nombre"].ToString(),
                Descripcion = dr["descripcion"].ToString(),
                Foto = dr["foto"].ToString(),
                Lat = dr["lat"].ToString(),
                Lng = dr["lng"].ToString()
            };
        }
        dr.Close();
        return new JavaScriptSerializer().Serialize(result);
    }
    catch (Exception ex) { throw (ex); }
    finally { cnn.Close(); cnn.Dispose(); }
}


En el código javascript, agregamos lo siguiente:

//Función para obtener la ubicación
function BuscarUbicacion(idUbicacion) {
    $.ajax({
        type: 'POST',
        url: "autocomplete-google-maps.aspx/BuscarUbicacion",
        data: "{idUbicacion: " + idUbicacion + "}",
        dataType: "json",
        contentType: 'application/json',
        async: false,
        success: function (result) {
            //Obtener la ubicación devuelta
            var ubicacion = $.parseJSON(result.d);
            var marker = new google.maps.Marker({
                position: new google.maps.LatLng(ubicacion.Lat, ubicacion.Lng),
                title: ubicacion.Nombre,
                icon: '../img/ico_red.png',
                map: map
            });
            markers.push(marker);
            marker.addListener('click', function () {
                //Poner todos los marcadores de color rojo
                for (var j = 0; j < markers.length; j++) {
                    markers[j].setIcon("../img/ico_red.png");
                }
                //Poner icono azul al marcador nuevo
                marker.setIcon("../img/ico_blue.png");
                //Diseñar la ventana que se va a mostrar
                infowindow.setContent("<h3>" + ubicacion.Nombre + "</h3><hr />" +
                    "<img src='../img/" + ubicacion.Foto + "' height='150px' width='250px' alt='Foto' /><br /><br />" +
                    "<a href='#' onclick='CalcularRuta(" + ubicacion.Lat + "," + ubicacion.Lng + ");' class='btn btn-primary btn-sm'><i class='glyphicon glyphicon-road'></i> Mostrar ruta</a>");
                infowindow.open(map, marker);
            });
            map.setZoom(16);
            map.setCenter(marker.getPosition());
            google.maps.event.trigger(map, 'resize');
        }
    });
}

Ahora, debemos modificar una línea.

Buscamos aquella que teníamos marcada:

alert(ui.item.id);//***ATENCION EN ESTA LINEA, LA MODIFICAREMOS MAS ADELANTE***/

La modificamos, para que quede así:

BuscarUbicacion(ui.item.id);//***ATENCION EN ESTA LINEA***/

Ahora, en lugar de mostrar una alerta, mostrará un marcador.

Vamos a detenernos nuevamente hasta asegurarnos que funciona como se espera.

Ejecutamos nuestra página, buscamos una ubicación y la seleccionamos. Debe mostrarse un marcador:

Si hacemos clic sobre el marcador, se debe ver una ventana emergente, también llamada InfoWindow:


Para finalizar, en el código javascript, agregamos la siguiente función:

//Función para calcular la ruta
//Nota Importante: En algunos casos no es posible calcular la ruta
//Especialmente cuando el destino no cuenta con carreteras
function CalcularRuta(lat, lng) {
    var destino = new google.maps.LatLng(lat, lng);
    var request = {
        origin: myCurrentPosition,
        destination: destino,
        travelMode: google.maps.TravelMode.DRIVING
    };
    directionsService.route(request, function (response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
            directionsDisplay.setDirections(response);
        }
    });
    infowindow.close();
}

De esta manera, cuando demos clic en el botón "Mostrar ruta" de la ventana emergente, Google Maps hará los cálculos necesarios para mostrarnos la mejor ruta posible. Es importante mencionar que esta funcionalidad solo estará disponible en los casos cuando hay acceso terrestre. Aquí tengo un ejemplo de un caso en el cual si se muestra la ruta:


Así finalizamos este largo tutorial.

No olvides regalarme un G+1

No hay comentarios:

Publicar un comentario