การจับคู่แบบเรียลไทม์ร่วมกันด้วย 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

อ่านส่วนต่อไปนี้เพื่อให้เข้าใจโค้ดที่คุณสามารถเพิ่มลงในไฟล์นี้

การสร้างแผนที่พื้นฐาน

ส่วนนี้จะอธิบายโค้ดที่ใช้ตั้งค่าแผนที่พื้นฐาน ซึ่งอาจคล้ายกับวิธีที่คุณสร้างแผนที่ไว้เมื่อเริ่มต้นใช้งาน Maps JavaScript API

คัดลอกโค้ดด้านล่างลงในไฟล์ index.html โค้ดนี้จะโหลด Maps JavaScript API และทำให้แผนที่แสดงแบบเต็มหน้าจอ นอกจากนี้ยังโหลดไลบรารีการแสดงภาพ ซึ่งคุณจะต้องใช้ในภายหลังในบทแนะนำเพื่อสร้างแผนที่ความหนาแน่น

<!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 เสร็จสมบูรณ์แล้ว พารามิเตอร์เรียกกลับในแท็กสคริปต์ด้านล่างจะเรียกใช้ฟังก์ชัน 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 Maps ที่โค้ดสร้างขึ้น ให้เปิดไฟล์ index.html ในเว็บเบราว์เซอร์

การตั้งค่า Firebase

คุณต้องจัดเก็บคลิกไว้ในฐานข้อมูลภายนอกที่ผู้ใช้ทุกคนเข้าถึงได้ เพื่อทำให้แอปพลิเคชันนี้ทำงานร่วมกันได้ ฐานข้อมูลเรียลไทม์ของ Firebase เหมาะกับวัตถุประสงค์นี้และไม่จำเป็นต้องมีความรู้เกี่ยวกับ SQL

ก่อนอื่น ให้ลงชื่อสมัครใช้บัญชี Firebase โดยไม่มีค่าใช้จ่าย หากคุณเพิ่งเริ่มใช้ Firebase คุณจะเห็นแอปใหม่ที่มีชื่อว่า "แอปแรกของฉัน" หากสร้างแอปใหม่ คุณสามารถตั้งชื่อใหม่และ URL ที่กำหนดเองของ Firebase ที่ลงท้ายด้วย firebaseIO.com เช่น คุณอาจตั้งชื่อแอปว่า "แผนที่ Firebase ของเจน" ด้วย URL https://janes-firebase-map.firebaseIO.com คุณใช้ URL นี้เพื่อลิงก์ฐานข้อมูลกับแอปพลิเคชัน JavaScript ได้

เพิ่มบรรทัดด้านล่างหลังแท็ก <head> ของไฟล์ HTML เพื่อนำเข้าไลบรารี Firebase

<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));

โปรดสังเกตว่าหากคุณคลิกแผนที่ความหนาแน่น แผนที่จะยังไม่สร้างจุด หากต้องการสร้างจุดบนแผนที่ คุณจะต้องตั้งค่า Listener แผนที่

การสร้างจุดบนแผนที่ความหนาแน่น

โค้ดด้านล่างจะเพิ่ม Listener ลงใน 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 และ Maps JavaScript API

เมื่อคลิกแผนที่ความหนาแน่น ละติจูดและลองจิจูดของคลิกจะปรากฏในฐานข้อมูล Firebase คุณดูข้อมูลนี้ได้โดยการลงชื่อเข้าใช้บัญชี Firebase และไปที่แท็บข้อมูลของแอป ณ จุดนี้ หากผู้อื่นคลิกบนแผนที่ของคุณ คุณและคนอื่นๆ จะเห็นจุดบนแผนที่ ตำแหน่งของการคลิกจะยังคงอยู่แม้ว่าผู้ใช้ปิดหน้าเว็บไปแล้วก็ตาม วิธีทดสอบฟังก์ชันการทำงานร่วมกันแบบเรียลไทม์คือให้เปิดหน้าเว็บใน 2 หน้าต่างแยกกัน เครื่องหมายควรปรากฏบนทั้ง 2 แพลตฟอร์มแบบเรียลไทม์

ดูข้อมูลเพิ่มเติม

Firebase เป็นแพลตฟอร์มแอปพลิเคชันที่จัดเก็บข้อมูลเป็น JSON และซิงค์กับไคลเอ็นต์ที่เชื่อมต่อทั้งหมดแบบเรียลไทม์ โดยพร้อมให้ใช้งานแม้ว่าแอปจะออฟไลน์ บทแนะนำนี้ใช้ฐานข้อมูลแบบเรียลไทม์