Google Maps + Firebase


foto

Firebase es una plataforma de desarrollo de aplicaciones que permite crear y desarrollar aplicaciones más rápidamente. Respaldado por Google y en el que confían millones de empresas de todo el mundo.

¿Qué son los geodatos?

Los geodatos son simplemente datos que contienen algún componente espacial, como las coordenadas de ubicación, que representan una realidad geográfica. Son producto de una observación y generalización del entorno geográfico complejo y permiten su representación y análisis espacial en un contexto definido.

Los elementos fundamentales de los geodatos son (Aronoff, 1989):

  • Ubicación espacial, posición geográfica del objeto de acuerdo a un sistema de coordenadas.
  • Atributos, elemento cuantificable del objeto geográfico que permite su caracterización y lo define apropiadamente.
  • Temporalidad, escala de tiempo en el cual se observa el objeto para cuantificar e identificar cambios significativos.

Existen diferentes formas de guardar los geodatos, 

Firebase nos ofrece diferentes soluciones, a lo largo de esta publicación se tratarán las principales ventajas de usar Firebase con Google Maps. 

Laboratorio de Código

Objetivo: Crear un Mapa Colaborativo de Google Maps con una base de datos en Firebase 

Creación del Proyecto: 

Creamos el proyecto desde la consola de Firebase, que es accedida desde https://console.firebase.google.com/.

Desarrollo de Código:

Para comenzar, crea un archivo nuevo en un editor de texto, nosotros usamos Visual Studio Code y guárdalo como index.html.

Crear un mapa básico

Este código carga la API de Maps JavaScript y muestra el mapa en pantalla completa. También carga la biblioteca de visualización, que servirá para crear un mapa de calor. Reemplaza APIKEY por la clave de API de tu aplicación, que puede ser generada desde https://console.cloud.google.com/apis/credentials, donde se debe de tener un proyecto creado así como una cuenta de facturación activada..

Agregar Firebase

Para que esta aplicación sea colaborativa, debes almacenar los clics en una base de datos externa a la que todos los usuarios puedan acceder. Firebase Realtime Database se adapta a este propósito y no requiere conocimientos de SQL.

Generación de la Configuración de Firebase

La generación de configuración de firebase se tiene que hacer https://console.firebase.google.com/ en donde se tiene que crear un proyecto; para lo que es necesario configurar o tener configurada una cuenta de facturación. Para este laboratorio se creó el proyecto con el plan Blaze, haciendo uso del nivel gratuito. Una vez creado el proyecto, podremos agregar nuestra aplicación; si es web, android o IOS.

Para poder utilizar firebase , se tendra que crear un proyecto en firebase, se puede hacer en un nivel gratuito (Blaze). Si creas una app nueva, puedes asignarle un nombre nuevo y una URL de Firebase personalizada que termine en firebaseIO.com. Por ejemplo, puedes nombrar el mapa de Firebase de tu app con la URL https://janes-firebase-map.firebaseIO.com. Puedes usar esta URL para vincular la base de datos a tu aplicación de JavaScript.

Dependiendo de la versión en la que se encuentre Firebase, nos recomendará hacer la importación por script o bien mediante un manejador como npm o yarn para proyectos con Node.

Cómo muestra un ejemplo de la configuración obtenida; además fue necesario activar la base de datos; en donde se utilizó en tiempo real. 

Almacenamiento de datos de clics en Firebase

Por cada clic del mouse en el mapa, el siguiente código crea un objeto de datos global y almacena su información en Firebase. Este objeto registra datos como su latitud y longitud (latlng) y la marca de tiempo del clic, así como un ID único del navegador que creó el clic.

El siguiente código registra un ID de sesión único para cada clic, lo que ayuda a controlar la tasa de tráfico en el mapa de acuerdo con las reglas de seguridad de Firebase.

La siguiente sección de código 

  • detecta clicks en el mapa, que agrega un elemento secundario a tu base de datos de Firebase. Cuando esto ocurre, la función snapshot.val() obtiene los valores de datos de la entrada y crea un nuevo objeto LatLng.. Cuando se produce un clic, la app registra una marca de tiempo y, luego, agrega un elemento secundario a tu base de datos de Firebase.
  • Borra en el mapa los clics que tengan más de 10 minutos en tiempo real.

Inicialización del mapa con propiedades iniciales y el mapa de calor

Resultado

También podemos ver el resultado directamente desde firebase

Finalmente el código completo tambien disponible en el repositorio de github: https://github.com/eSourceCapital/ESC-WS-Firebase-and-maps 

<!DOCTYPE html>

<html>

  <head>

    <style>

      #map {

        height: 100%;

      }

      /* Opcional: tamaño completo. */

      html,

      body {

        height: 100%;

        margin: 0;

        padding: 0;

      }

    </style>

    <!– Importamos firebase (8.10)–>

    <script src=”https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js”></script>

    <script src=”https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js”></script>

    <script src=”https://www.gstatic.com/firebasejs/8.10.0/firebase-firestore.js”></script>

    <script src=”https://www.gstatic.com/firebasejs/8.10.0/firebase-database.js”></script>

  </head>

  <body>

    <!– Agregamos el div del mapa–>

    <div id=”map”></div>

    <script

      defer

      src=”https://maps.googleapis.com/maps/api/js?key=[APIKEY]&libraries=visualization&callback=initMap”

    ></script>

    <script>

      /**

       * Firebase config block.

       */

      const firebaseConfig = {

       [change]

      };

      firebase.initializeApp(firebaseConfig);

      var db = firebase.firestore();

      /**

       * objeto a guardar en firebase

       */

      var data = {

        sender: null,

        timestamp: null,

        lat: null,

        lng: null

      };

      function makeInfoBox(controlDiv, map) {

        // CSS

        var controlUI = document.createElement(“div”);

        controlUI.style.boxShadow = “rgba(0, 0, 0, 0.298039) 0px 1px 4px -1px”;

        controlUI.style.backgroundColor = “#fff”;

        controlUI.style.border = “2px solid #fff”;

        controlUI.style.borderRadius = “2px”;

        controlUI.style.marginBottom = “22px”;

        controlUI.style.marginTop = “10px”;

        controlUI.style.textAlign = “center”;

        controlDiv.appendChild(controlUI);

        // CSS: mensaje.

        var controlText = document.createElement(“div”);

        controlText.style.color = “rgb(25,25,25)”;

        controlText.style.fontFamily = “Roboto,Arial,sans-serif”;

        controlText.style.fontSize = “100%”;

        controlText.style.padding = “6px”;

        controlText.textContent = “el mapa muestra los últimos 10 min.”;

        controlUI.appendChild(controlText);

      }

      /**

       * Función Principal, se llama a la autenticación

       * @param {function()} onAuthSuccess – se llama cunado la autenticación fue exitosa.

       */

      function initAuthentication(onAuthSuccess) {

        firebase

          .auth()

          .signInAnonymously()

          .catch(

            function (error) {

              console.log(error.code + “, ” + error.message);

            },

            { remember: “sessionOnly” }

          );

        firebase.auth().onAuthStateChanged(function (user) {

          if (user) {

            data.sender = user.uid;

            onAuthSuccess();

          }

        });

      }

      /**

       * Creamos un objeto mapa con un listener de clicks y un mapa de calor.

       */

      function initMap() {

        var map = new google.maps.Map(document.getElementById(“map”), {

          center: { lat: 0, lng: 0 },

          zoom: 3,

          disableDoubleClickZoom: true,

          streetViewControl: false,

        });

        // creamos un div para el infowindows

        var infoBoxDiv = document.createElement(“div”);

        makeInfoBox(infoBoxDiv, map);

        map.controls[google.maps.ControlPosition.TOP_CENTER].push(infoBoxDiv);

        // Agregamos el Listener.

        map.addListener(“click”, function (e) {

          data.lat = e.latLng.lat();

          data.lng = e.latLng.lng();

          addToFirebase(data);

        });

        // Creamos el mapa de calor.

        var heatmap = new google.maps.visualization.HeatmapLayer({

          data: [],

          map: map,

          radius: 16,

        });

        // mandamos a llamar la autenticación

        initAuthentication(initFirebase.bind(undefined, heatmap));

      }

      /**

       * Configure un Firebase con eliminación de clics anteriores a expiryMs

       * @param {!google.maps.visualization.HeatmapLayer} heatmap Mapa de calor

       */

      function initFirebase(heatmap) {

        // 10 minutos antes.

        var startTime = new Date().getTime() – 60 * 10 * 1000;

        // Referencia a los clicks en Firebase.

        var clicks = firebase.database().ref(“clicks”);

        // Escuchamos clicks y los agregamos al mapa de calor.

        clicks

          .orderByChild(“timestamp”)

          .startAt(startTime)

          .on(“child_added”, function (snapshot) {

            // Obtenemos el click de firebase.

            var newPosition = snapshot.val();

            var point = new google.maps.LatLng(

              newPosition.lat,

              newPosition.lng

            );

            var elapsedMs = Date.now() – newPosition.timestamp;

            // Agregamos el punto al mapa de calor.

            heatmap.getData().push(point);

            // Solicitamos entradas dentro de los ultimos 10 minutos.

            var expiryMs = Math.max(60 * 10 * 1000 – elapsedMs, 0);

            // Configure el tiempo de espera del cliente para eliminar el punto después de un tiempo determinado.

            window.setTimeout(function () {

              // Eliminamos los puntos

              snapshot.ref.remove();

            }, expiryMs);

          });

        // Elimine los datos antiguos del mapa de calor cuando se elimine un punto de firebase.

        clicks.on(“child_removed”, function (snapshot, prevChildKey) {

          var heatmapData = heatmap.getData();

          var i = 0;

          while (

            snapshot.val().lat != heatmapData.getAt(i).lat() ||

            snapshot.val().lng != heatmapData.getAt(i).lng()

          ) {

            i++;

          }

          heatmapData.removeAt(i);

        });

      }

      /**

       * Actualiza la ruta last_message/ con el timestamp actual.

       * @param {function(Date)} addClick después de actualizar el timestamp del último mensaje,

       *     esta función se llama con el timestamp actual para agregar el

       *     click a firebase.

       */

      function getTimestamp(addClick) {

        var ref = firebase.database().ref(“last_message/” + data.sender);

        ref.onDisconnect().remove(); // Elimina la referenccia de firebase .

        // Establecer el timestamp.

        ref.set(firebase.database.ServerValue.TIMESTAMP, function (err) {

          if (err) {

            console.log(err);

          } else {

            ref.once(

              “value”,

              function (snap) {

                addClick(snap.val()); // Agrega el click con el timestamp.

              },

              function (err) {

                console.warn(err);

              }

            );

          }

        });

      }

      /**

       * Agregar clicks a firebase.

       * @param {Object} data Los datos a agregar a firebase.

       *     Contiene lat, lng, sender (quien envia) y el timestamp (fecha y hora).

       */

      function addToFirebase(data) {

        getTimestamp(function (timestamp) {

          // agrega el timestamp.

          data.timestamp = timestamp;

          var ref = firebase

            .database()

            .ref(“clicks”)

            .push(data, function (err) {

              if (err) {

                console.warn(err);

              }

            });

        });

      }

    </script>

  </body>

</html>

Laboratorio Original en https://developers.google.com/maps/documentation/javascript/firebase, es importante considerar que  la versión original es para Firebase 5.3. Mientras que la versión empleada por eSource fue firebase 8.10. Revisar el historial de versiones de firebase antes de decidir utilizar cualquier funcionalidad de dicha plataforma: https://firebase.google.com/support/releases 

Comparte!


Leave a Reply

Your email address will not be published. Required fields are marked *