מיפוי שיתופי בזמן אמת ב-Firebase

סקירה כללית

במדריך הזה תלמדו איך ליצור מפה אינטראקטיבית באמצעות פלטפורמת האפליקציות של Firebase. אפשר ללחוץ על מיקומים שונים במפה שלמטה כדי ליצור מפת חום.

הקטע הבא מציג את הקוד המלא שנדרש כדי ליצור את המפה במדריך זה.

/**
 * Firebase config block.
 */
var config = {
  apiKey: 'AIzaSyDX-tgWqPmTme8lqlFn2hIsqwxGL6FYPBY',
  authDomain: 'maps-docs-team.firebaseapp.com',
  databaseURL: 'https://maps-docs-team.firebaseio.com',
  projectId: 'maps-docs-team',
  storageBucket: 'maps-docs-team.appspot.com',
  messagingSenderId: '285779793579'
};

firebase.initializeApp(config);

/**
 * Data object to be written to Firebase.
 */
var data = {sender: null, timestamp: null, lat: null, lng: null};

function makeInfoBox(controlDiv, map) {
  // Set CSS for the control border.
  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);

  // Set CSS for the control interior.
  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 =
      'The map shows all clicks made in the last 10 minutes.';
  controlUI.appendChild(controlText);
}

      /**
      * Starting point for running the program. Authenticates the user.
      * @param {function()} onAuthSuccess - Called when authentication succeeds.
      */
      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();
          } else {
            // User is signed out.
          }
        });
      }

      /**
       * Creates a map object with a click listener and a heatmap.
       */
      function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: 0, lng: 0},
          zoom: 3,
          styles: [{
            featureType: 'poi',
            stylers: [{ visibility: 'off' }]  // Turn off POI.
          },
          {
            featureType: 'transit.station',
            stylers: [{ visibility: 'off' }]  // Turn off bus, train stations etc.
          }],
          disableDoubleClickZoom: true,
          streetViewControl: false,
        });

        // Create the DIV to hold the control and call the makeInfoBox() constructor
        // passing in this DIV.
        var infoBoxDiv = document.createElement('div');
        makeInfoBox(infoBoxDiv, map);
        map.controls[google.maps.ControlPosition.TOP_CENTER].push(infoBoxDiv);

        // Listen for clicks and add the location of the click to firebase.
        map.addListener('click', function(e) {
          data.lat = e.latLng.lat();
          data.lng = e.latLng.lng();
          addToFirebase(data);
        });

        // Create a heatmap.
        var heatmap = new google.maps.visualization.HeatmapLayer({
          data: [],
          map: map,
          radius: 16
        });

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

      /**
       * Set up a Firebase with deletion on clicks older than expiryMs
       * @param {!google.maps.visualization.HeatmapLayer} heatmap The heatmap to
       */
      function initFirebase(heatmap) {

        // 10 minutes before current time.
        var startTime = new Date().getTime() - (60 * 10 * 1000);

        // Reference to the clicks in Firebase.
        var clicks = firebase.database().ref('clicks');

        // Listen for clicks and add them to the heatmap.
        clicks.orderByChild('timestamp').startAt(startTime).on('child_added',
          function(snapshot) {
            // Get that click from firebase.
            var newPosition = snapshot.val();
            var point = new google.maps.LatLng(newPosition.lat, newPosition.lng);
            var elapsedMs = Date.now() - newPosition.timestamp;

            // Add the point to the heatmap.
            heatmap.getData().push(point);

            // Request entries older than expiry time (10 minutes).
            var expiryMs = Math.max(60 * 10 * 1000 - elapsedMs, 0);

            // Set client timeout to remove the point after a certain time.
            window.setTimeout(function() {
              // Delete the old point from the database.
              snapshot.ref.remove();
            }, expiryMs);
          }
        );

        // Remove old data from the heatmap when a point is removed from 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);
        });
      }

      /**
       * Updates the last_message/ path with the current timestamp.
       * @param {function(Date)} addClick After the last message timestamp has been updated,
       *     this function is called with the current timestamp to add the
       *     click to the firebase.
       */
      function getTimestamp(addClick) {
        // Reference to location for saving the last click time.
        var ref = firebase.database().ref('last_message/' + data.sender);

        ref.onDisconnect().remove();  // Delete reference from firebase on disconnect.

        // Set value to timestamp.
        ref.set(firebase.database.ServerValue.TIMESTAMP, function(err) {
          if (err) {  // Write to last message was unsuccessful.
            console.log(err);
          } else {  // Write to last message was successful.
            ref.once('value', function(snap) {
              addClick(snap.val());  // Add click with same timestamp.
            }, function(err) {
              console.warn(err);
            });
          }
        });
      }

      /**
       * Adds a click to firebase.
       * @param {Object} data The data to be added to firebase.
       *     It contains the lat, lng, sender and timestamp.
       */
      function addToFirebase(data) {
        getTimestamp(function(timestamp) {
          // Add the new timestamp to the record data.
          data.timestamp = timestamp;
          var ref = firebase.database().ref('clicks').push(data, function(err) {
            if (err) {  // Data was not written to firebase.
              console.warn(err);
            }
          });
        });
      }
<div id="map"></div>
/* Always set the map height explicitly to define the size of the div
 * element that contains the map. */
#map {
  height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=visualization&callback=initMap" defer></script>
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase.js"></script>

התנסות עצמית

אפשר להתנסות עם הקוד הזה ב-JSFiddle על ידי לחיצה על הסמל <> בפינה השמאלית העליונה של חלון הקוד.

<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>

    <script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-database.js"></script>
    <script>
/**
 * Firebase config block.
 */
var config = {
  apiKey: 'AIzaSyDX-tgWqPmTme8lqlFn2hIsqwxGL6FYPBY',
  authDomain: 'maps-docs-team.firebaseapp.com',
  databaseURL: 'https://maps-docs-team.firebaseio.com',
  projectId: 'maps-docs-team',
  storageBucket: 'maps-docs-team.appspot.com',
  messagingSenderId: '285779793579'
};

firebase.initializeApp(config);

/**
 * Data object to be written to Firebase.
 */
var data = {sender: null, timestamp: null, lat: null, lng: null};

function makeInfoBox(controlDiv, map) {
  // Set CSS for the control border.
  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);

  // Set CSS for the control interior.
  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 =
      'The map shows all clicks made in the last 10 minutes.';
  controlUI.appendChild(controlText);
}

      /**
      * Starting point for running the program. Authenticates the user.
      * @param {function()} onAuthSuccess - Called when authentication succeeds.
      */
      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();
          } else {
            // User is signed out.
          }
        });
      }

      /**
       * Creates a map object with a click listener and a heatmap.
       */
      function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: 0, lng: 0},
          zoom: 3,
          styles: [{
            featureType: 'poi',
            stylers: [{ visibility: 'off' }]  // Turn off POI.
          },
          {
            featureType: 'transit.station',
            stylers: [{ visibility: 'off' }]  // Turn off bus, train stations etc.
          }],
          disableDoubleClickZoom: true,
          streetViewControl: false,
        });

        // Create the DIV to hold the control and call the makeInfoBox() constructor
        // passing in this DIV.
        var infoBoxDiv = document.createElement('div');
        makeInfoBox(infoBoxDiv, map);
        map.controls[google.maps.ControlPosition.TOP_CENTER].push(infoBoxDiv);

        // Listen for clicks and add the location of the click to firebase.
        map.addListener('click', function(e) {
          data.lat = e.latLng.lat();
          data.lng = e.latLng.lng();
          addToFirebase(data);
        });

        // Create a heatmap.
        var heatmap = new google.maps.visualization.HeatmapLayer({
          data: [],
          map: map,
          radius: 16
        });

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

      /**
       * Set up a Firebase with deletion on clicks older than expiryMs
       * @param {!google.maps.visualization.HeatmapLayer} heatmap The heatmap to
       */
      function initFirebase(heatmap) {

        // 10 minutes before current time.
        var startTime = new Date().getTime() - (60 * 10 * 1000);

        // Reference to the clicks in Firebase.
        var clicks = firebase.database().ref('clicks');

        // Listen for clicks and add them to the heatmap.
        clicks.orderByChild('timestamp').startAt(startTime).on('child_added',
          function(snapshot) {
            // Get that click from firebase.
            var newPosition = snapshot.val();
            var point = new google.maps.LatLng(newPosition.lat, newPosition.lng);
            var elapsedMs = Date.now() - newPosition.timestamp;

            // Add the point to the heatmap.
            heatmap.getData().push(point);

            // Request entries older than expiry time (10 minutes).
            var expiryMs = Math.max(60 * 10 * 1000 - elapsedMs, 0);

            // Set client timeout to remove the point after a certain time.
            window.setTimeout(function() {
              // Delete the old point from the database.
              snapshot.ref.remove();
            }, expiryMs);
          }
        );

        // Remove old data from the heatmap when a point is removed from 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);
        });
      }

      /**
       * Updates the last_message/ path with the current timestamp.
       * @param {function(Date)} addClick After the last message timestamp has been updated,
       *     this function is called with the current timestamp to add the
       *     click to the firebase.
       */
      function getTimestamp(addClick) {
        // Reference to location for saving the last click time.
        var ref = firebase.database().ref('last_message/' + data.sender);

        ref.onDisconnect().remove();  // Delete reference from firebase on disconnect.

        // Set value to timestamp.
        ref.set(firebase.database.ServerValue.TIMESTAMP, function(err) {
          if (err) {  // Write to last message was unsuccessful.
            console.log(err);
          } else {  // Write to last message was successful.
            ref.once('value', function(snap) {
              addClick(snap.val());  // Add click with same timestamp.
            }, function(err) {
              console.warn(err);
            });
          }
        });
      }

      /**
       * Adds a click to firebase.
       * @param {Object} data The data to be added to firebase.
       *     It contains the lat, lng, sender and timestamp.
       */
      function addToFirebase(data) {
        getTimestamp(function(timestamp) {
          // Add the new timestamp to the record data.
          data.timestamp = timestamp;
          var ref = firebase.database().ref('clicks').push(data, function(err) {
            if (err) {  // Data was not written to firebase.
              console.warn(err);
            }
          });
        });
      }
    </script>
    <script defer
        src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=visualization&callback=initMap">
    </script>
  </body>
</html>

תחילת העבודה

תוכלו לפתח גרסה משלכם של מפת Firebase בעזרת הקוד במדריך הזה. כדי להתחיל לעשות זאת, צריך ליצור קובץ חדש בעורך טקסט ולשמור אותו בשם index.html.

יש לקרוא את הסעיפים הבאים כדי להבין את הקוד שניתן להוסיף לקובץ הזה.

יצירת מפה בסיסית

בקטע הזה מוסבר הקוד שמגדיר מפה בסיסית. האפשרות הזו יכולה להיות דומה לאופן שבו יצרתם מפות כשהתחלתם להשתמש ב-API של JavaScript במפות Google.

מעתיקים את הקוד שלמטה לקובץ index.html. הקוד הזה טוען את API JavaScript של מפות Google ומציג את המפה במסך מלא. הוא גם טוען את ספריית ההמחשה החזותית, שצריך בהמשך המדריך כדי ליצור מפת חום.

<!DOCTYPE html>
<html>
  <head>
    <style>
      #map {
        height: 100%;
      }
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script defer
        src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY
        &libraries=visualization&callback=initMap">
    </script>

    <script>
      // The JavaScript code that creates the Firebase map goes here.
    </script>

  </body>
</html>

לוחצים על YOUR_API_KEY בדוגמת הקוד, או פועלים לפי ההוראות לקבלת מפתח API. מחליפים את YOUR_API_KEY במפתח ה-API של האפליקציה.

בקטעים הבאים מוסבר קוד ה-JavaScript שיוצר את מפת Firebase. אפשר להעתיק את הקוד ולשמור אותו בקובץ firebasemap.js ולהפנות אליו בין תגי סקריפט כמו שמתואר בהמשך.

<script>firebasemap.js</script>

לחלופין, אפשר להוסיף את הקוד ישירות לתגי הסקריפט, כמו הקוד המלא לדוגמה בתחילת המדריך.

צריך להוסיף את הקוד שלמטה לקובץ firebasemap.js, או בין תגי הסקריפט הריקים בקובץ ה-index.html. זוהי נקודת ההתחלה להפעלת התוכנית על ידי יצירה של פונקציה שמפעילה את אובייקט המפה.

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 0, lng: 0},
    zoom: 3,
    styles: [{
      featureType: 'poi',
      stylers: [{ visibility: 'off' }]  // Turn off points of interest.
    }, {
      featureType: 'transit.station',
      stylers: [{ visibility: 'off' }]  // Turn off bus stations, train stations, etc.
    }],
    disableDoubleClickZoom: true,
    streetViewControl: false
  });
}

כדי להקל על השימוש במפת החום הזו, הקוד שלמעלה משתמש בעיצוב המפה כדי להשבית נקודות עניין ותחנות תחבורה ציבורית (שמציגות חלון מידע כשלוחצים עליהן). בנוסף, היא משביתה את הזום לאחר לחיצה כפולה כדי למנוע שינוי מרחק התצוגה בטעות. למידע נוסף בנושא עיצוב המפה.

לאחר שה-API נטען בצורה מלאה, פרמטר הקריאה החוזרת (callback) שבתג הסקריפט שבהמשך מריץ את הפונקציה initMap() בקובץ ה-HTML.

<script defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY
    &libraries=visualization&callback=initMap">
</script>

מוסיפים את הקוד שלמטה כדי ליצור את בקרת הטקסט בחלק העליון של המפה.

function makeInfoBox(controlDiv, map) {
  // Set CSS for the control border.
  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);

  // Set CSS for the control interior.
  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.innerText = 'The map shows all clicks made in the last 10 minutes.';
  controlUI.appendChild(controlText);
}

צריך להוסיף את הקוד שלמטה בתוך הפונקציה initMap, אחרי var map, כדי לטעון את תיבת בקרת הטקסט.

// Create the DIV to hold the control and call the makeInfoBox() constructor
// passing in this DIV.
var infoBoxDiv = document.createElement('div');
var infoBox = new makeInfoBox(infoBoxDiv, map);
infoBoxDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_CENTER].push(infoBoxDiv);
אני רוצה לנסות

כדי להציג את מפת Google שהקוד יוצר, פותחים את הקובץ index.html בדפדפן אינטרנט.

הגדרת Firebase

כדי להפוך את האפליקציה לשיתופית, צריך לאחסן את הקליקים במסד נתונים חיצוני שכל המשתמשים יכולים לגשת אליו. מתאים למטרה הזו ולא נדרש ידע ב-SQL כדי להשתמש ב-Firebase Realtime Database.

קודם כול, נרשמים לחשבון Firebase ללא תשלום. אם זו הפעם הראשונה שאתם משתמשים ב-Firebase, תראו אפליקציה חדשה בשם 'האפליקציה הראשונה שלי'. כשיוצרים אפליקציה חדשה, אפשר לתת לה שם חדש וכתובת URL מותאמת אישית ב-Firebase שמסתיימת ב-firebaseIO.com. לדוגמה, אפשר לתת לאפליקציה 'מפת Firebase של יעל' ולהשתמש בכתובת ה-URL https://janes-firebase-map.firebaseIO.com. ניתן להשתמש בכתובת ה-URL הזו כדי לקשר את מסד הנתונים לאפליקציית JavaScript.

כדי לייבא את ספריית Firebase, צריך להוסיף את השורה שלמטה אחרי תגי <head> בקובץ ה-HTML.

<script src="www.gstatic.com/firebasejs/5.3.0/firebase.js"></script>

מוסיפים את השורה הבאה לקובץ ה-JavaScript:

var firebase = new Firebase("<Your Firebase URL here>");

אחסון של נתוני קליקים ב-Firebase

בקטע הזה מוסבר הקוד שמאחסן נתונים ב-Firebase, לגבי קליקים על המפה.

עבור כל לחיצה של עכבר על המפה, הקוד הבא יוצר אובייקט נתונים גלובלי ומאחסן את הפרטים שלו ב-Firebase. אובייקט זה מתעד נתונים כמו רוחב הלקוח וחותמת הזמן של הקליק, וכן מזהה ייחודי של הדפדפן שיצר את הקליק.

/**
 * Data object to be written to Firebase.
 */
var data = {
  sender: null,
  timestamp: null,
  lat: null,
  lng: null
};

הקוד שבהמשך מתעד מזהה סשן ייחודי לכל קליק. המערכת הזו עוזרת לשלוט בשיעור התנועה במפה בהתאם לכללי האבטחה של Firebase.

/**
* Starting point for running the program. Authenticates the user.
* @param {function()} onAuthSuccess - Called when authentication succeeds.
*/
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();
    } else {
      // User is signed out.
    }
  });
}

בקטע הבא של הקוד שבהמשך המערכת מתייחסת לקליקים על המפה, פעולה שמוסיפה 'צאצא' למסד הנתונים שלך ב-Firebase. במקרה כזה, הפונקציה snapshot.val() מקבלת את ערכי הנתונים של הרשומה ויוצרת אובייקט LatLng חדש.

// Listen for clicks and add them to the heatmap.
clicks.orderByChild('timestamp').startAt(startTime).on('child_added',
  function(snapshot) {
    var newPosition = snapshot.val();
    var point = new google.maps.LatLng(newPosition.lat, newPosition.lng);
    heatmap.getData().push(point);
  }
);

הקוד הבא מגדיר את Firebase כך:

  • מקשיבים לקליקים על המפה. כשמשתמש לוחץ על האפליקציה, היא מתעדת חותמת זמן ואז מוסיפה 'צאצא' למסד הנתונים שלך ב-Firebase.
  • מחיקת כל הקליקים במפה שנוספו לפני יותר מ-10 דקות, בזמן אמת.
/**
 * Set up a Firebase with deletion on clicks older than expirySeconds
 * @param {!google.maps.visualization.HeatmapLayer} heatmap The heatmap to
 * which points are added from Firebase.
 */
function initFirebase(heatmap) {

  // 10 minutes before current time.
  var startTime = new Date().getTime() - (60 * 10 * 1000);

  // Reference to the clicks in Firebase.
  var clicks = firebase.database().ref('clicks');

  // Listen for clicks and add them to the heatmap.
  clicks.orderByChild('timestamp').startAt(startTime).on('child_added',
    function(snapshot) {
      // Get that click from firebase.
      var newPosition = snapshot.val();
      var point = new google.maps.LatLng(newPosition.lat, newPosition.lng);
      var elapsedMs = Date.now() - newPosition.timestamp;

      // Add the point to the heatmap.
      heatmap.getData().push(point);

      // Request entries older than expiry time (10 minutes).
      var expiryMs = Math.max(60 * 10 * 1000 - elapsed, 0);
      // Set client timeout to remove the point after a certain time.
      window.setTimeout(function() {
        // Delete the old point from the database.
        snapshot.ref.remove();
      }, expiryMs);
    }
  );

  // Remove old data from the heatmap when a point is removed from 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);
  });
}

מעתיקים את כל קוד ה-JavaScript שבקטע הזה אל הקובץ firebasemap.js.

יצירת מפת החום

השלב הבא הוא הצגת מפת חום שמעניקה לצופים רושם גרפי לגבי מספר הקליקים היחסי במיקומים שונים במפה. מידע נוסף זמין במדריך למפות חום.

צריך להוסיף את הקוד שלמטה בתוך הפונקציה initMap() כדי ליצור מפת חום.

// Create a heatmap.
var heatmap = new google.maps.visualization.HeatmapLayer({
  data: [],
  map: map,
  radius: 16
});

הקוד שבהמשך מפעיל את הפונקציות initFirebase, addToFirebase ו-getTimestamp.

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

שימו לב שאם לוחצים על מפת החום, היא עדיין לא יוצרת נקודות. כדי ליצור נקודות במפה, עליך להגדיר מאזין למפה.

יצירת נקודות במפת החום

הקוד שבהמשך מוסיף האזנה בתוך initMap(), אחרי הקוד שיוצר את המפה. הקוד הזה מסתמך על הנתונים מכל קליק, שומר את מיקום הקליק במסד הנתונים של Firebase ומציג את הנקודות במפת החום.

// Listen for clicks and add the location of the click to firebase.
map.addListener('click', function(e) {
  data.lat = e.latLng.lat();
  data.lng = e.latLng.lng();
  addToFirebase(data);
});
אני רוצה לנסות

לוחצים על מיקומים במפה כדי ליצור נקודות במפת החום.

עכשיו יש לך אפליקציה פועלת בזמן אמת שפועלת באופן מלא ונעשה בה שימוש ב-Firebase וב-API של JavaScript של מפות Google.

כשלוחצים על מפת החום, קווי הרוחב והאורך של הקליק אמורים להופיע עכשיו במסד הנתונים של Firebase. כדי לראות את הנתונים האלה, צריך להתחבר לחשבון Firebase ולעבור לכרטיסיית הנתונים של האפליקציה. בשלב הזה, אם מישהו אחר לוחץ על המפה, לך ולמשתמש הזה תהיה אפשרות לראות נקודות במפה. מיקום הקליקים נשאר גם אחרי שהמשתמש סוגר את הדף. כדי לבדוק את הפונקציונליות לשיתוף פעולה בזמן אמת, פתחו את הדף בשני חלונות נפרדים. הסמנים אמורים להופיע בשתי האפליקציות בזמן אמת.

מידע נוסף

Firebase היא פלטפורמת אפליקציות שמאחסנת נתונים כקובץ JSON, ומסתנכרנת עם כל הלקוחות המחוברים בזמן אמת. היא תהיה זמינה גם אחרי שהאפליקציה תעבור למצב אופליין. במדריך הזה נעשה שימוש במסד הנתונים בזמן אמת.