Liên kết theo thời gian thực cộng tác bằng Firebase

Tổng quan

Hướng dẫn này chỉ cho bạn cách tạo bản đồ tương tác bằng nền tảng ứng dụng Firebase. Hãy thử nhấp vào các vị trí khác nhau trên bản đồ bên dưới để tạo bản đồ nhiệt.

Phần bên dưới hiển thị toàn bộ mã mà bạn cần để tạo bản đồ trong hướng dẫn này.

/**
 * 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>

Thử ngay

Bạn có thể thử nghiệm mã này trong JSFiddle bằng cách nhấp vào biểu tượng <> ở góc trên cùng bên phải cửa sổ mã.

<!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>

Bắt đầu

Bạn có thể phát triển phiên bản bản đồ Firebase của riêng mình bằng cách sử dụng mã trong hướng dẫn này. Để bắt đầu thực hiện việc này, hãy tạo một tệp mới trong trình chỉnh sửa văn bản và lưu tệp đó dưới dạng index.html.

Hãy đọc các phần tiếp theo để nắm được mã mà bạn có thể thêm vào tệp này.

Tạo bản đồ cơ bản

Phần này giải thích mã thiết lập bản đồ cơ bản. Điều này có thể tương tự như cách bạn tạo bản đồ khi bắt đầu sử dụng API JavaScript của Maps.

Sao chép mã bên dưới vào tệp index.html. Mã này tải API Maps JavaScript và đặt bản đồ ở chế độ toàn màn hình. Thao tác này cũng tải thư viện hình ảnh trực quan mà bạn sẽ cần sau này trong hướng dẫn để tạo bản đồ nhiệt.

<!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>

Nhấp vào YOUR_API_KEY trong mã mẫu hoặc làm theo hướng dẫn để nhận khoá API. Thay thế YOUR_API_KEY bằng khoá API của ứng dụng.

Các phần sau giải thích mã JavaScript tạo bản đồ Firebase. Bạn có thể sao chép và lưu mã trong tệp firebasemap.js, đồng thời tham chiếu mã giữa các thẻ tập lệnh như bên dưới.

<script>firebasemap.js</script>

Ngoài ra, bạn có thể chèn trực tiếp mã vào trong thẻ tập lệnh như trong mã mẫu đầy đủ ở đầu hướng dẫn này.

Thêm mã bên dưới vào tệp firebasemap.js hoặc giữa các thẻ tập lệnh trống của tệp index.html. Đây là điểm xuất phát để chạy chương trình bằng cách tạo một hàm khởi động đối tượng bản đồ.

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

Để làm cho bản đồ nhiệt có thể nhấp này dễ sử dụng hơn, mã ở trên sử dụng kiểu bản đồ để vô hiệu hóa các địa điểm yêu thích và trạm phương tiện (sẽ hiển thị cửa sổ thông tin khi được nhấp vào). Thao tác này cũng vô hiệu hoá tính năng thu phóng khi nhấp đúp để ngăn việc vô tình thu phóng. Đọc thêm về tạo kiểu cho bản đồ.

Sau khi API được tải hoàn toàn, tham số gọi lại trong thẻ tập lệnh bên dưới sẽ thực thi hàm initMap() trong tệp HTML.

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

Thêm mã bên dưới để tạo điều khiển văn bản ở phía trên cùng của bản đồ.

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

Thêm mã bên dưới vào bên trong hàm initMap, sau var map, để tải hộp điều khiển văn bản.

// 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);
Dùng thử ngay

Để xem bản đồ Google mà mã này tạo ra, hãy mở tệp index.html trong trình duyệt web.

Thiết lập Firebase

Để ứng dụng này có tính cộng tác, bạn phải lưu trữ các lượt nhấp trong cơ sở dữ liệu bên ngoài mà tất cả người dùng đều có thể truy cập. Cơ sở dữ liệu theo thời gian thực của Firebase phù hợp với mục đích này và không yêu cầu bạn phải có kiến thức về SQL.

Trước tiên, hãy đăng ký tài khoản Firebase mà không mất phí. Nếu mới sử dụng Firebase, bạn sẽ thấy một ứng dụng mới có tên là "Ứng dụng đầu tiên của tôi". Nếu tạo một ứng dụng mới, bạn có thể đặt tên mới cho ứng dụng đó và một URL Firebase tuỳ chỉnh kết thúc bằng firebaseIO.com. Ví dụ: bạn có thể đặt tên cho ứng dụng là "Bản đồ Firebase của Jane" bằng URL https://janes-firebase-map.firebaseIO.com. Bạn có thể sử dụng URL này để liên kết cơ sở dữ liệu với ứng dụng JavaScript của mình.

Thêm dòng bên dưới sau thẻ <head> của tệp HTML để nhập thư viện Firebase.

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

Thêm dòng sau vào tệp JavaScript của bạn:

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

Lưu trữ dữ liệu lượt nhấp trong Firebase

Phần này giải thích về mã lưu trữ dữ liệu trong Firebase, về lượt nhấp chuột trên bản đồ.

Đối với mỗi lần nhấp chuột trên bản đồ, mã dưới đây sẽ tạo một đối tượng dữ liệu chung và lưu trữ thông tin của đối tượng đó trong Firebase. Đối tượng này ghi lại dữ liệu như vĩ độ và dấu thời gian của lượt nhấp, cũng như mã nhận dạng duy nhất của trình duyệt đã tạo ra lượt nhấp.

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

Mã dưới đây ghi lại một mã phiên duy nhất cho mỗi lượt nhấp. Điều này giúp kiểm soát tỷ lệ lưu lượng truy cập trên bản đồ theo các quy tắc bảo mật của 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.
    }
  });
}

Phần mã tiếp theo dưới đây sẽ xử lý các lượt nhấp trên bản đồ, thêm một "con" vào cơ sở dữ liệu Firebase của bạn. Khi điều này xảy ra, hàm snapshot.val() sẽ lấy giá trị dữ liệu của mục nhập và tạo một đối tượng LatLng mới.

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

Đoạn mã dưới đây thiết lập Firebase để:

  • Nghe lượt nhấp vào bản đồ. Khi một lượt nhấp xảy ra, ứng dụng sẽ ghi lại dấu thời gian, sau đó thêm "con" vào cơ sở dữ liệu Firebase của bạn.
  • Xoá mọi lượt nhấp cũ hơn 10 phút trên bản đồ theo thời gian thực.
/**
 * 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);
  });
}

Sao chép toàn bộ mã JavaScript trong phần này vào tệp firebasemap.js.

Tạo bản đồ nhiệt

Bước tiếp theo là hiển thị bản đồ nhiệt hiển thị cho người xem một hình ảnh biểu đồ về số lượt nhấp tương đối tại các vị trí khác nhau trên bản đồ. Để tìm hiểu thêm, hãy đọc hướng dẫn về bản đồ nhiệt.

Thêm mã dưới đây vào bên trong hàm initMap() để tạo bản đồ nhiệt.

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

Đoạn mã dưới đây kích hoạt các hàm initFirebase, addToFirebasegetTimestamp.

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

Lưu ý rằng nếu bạn nhấp vào bản đồ nhiệt, thao tác này sẽ chưa tạo điểm. Để tạo các điểm trên bản đồ, bạn cần thiết lập một trình nghe bản đồ.

Tạo điểm trên bản đồ nhiệt

Mã dưới đây thêm một trình nghe vào bên trong initMap(), sau mã tạo bản đồ. Mã này sẽ lắng nghe dữ liệu từ mỗi lượt nhấp, lưu trữ vị trí của lượt nhấp trong cơ sở dữ liệu Firebase và hiện các điểm trên bản đồ nhiệt của bạn.

// 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);
});
Dùng thử ngay

Nhấp vào các vị trí trên bản đồ để tạo các điểm trên bản đồ nhiệt.

Giờ đây, bạn sẽ có một ứng dụng có đầy đủ chức năng theo thời gian thực bằng cách sử dụng Firebase và Maps JavaScript API.

Khi bạn nhấp vào bản đồ nhiệt, vĩ độ và kinh độ của lượt nhấp đó sẽ xuất hiện trong cơ sở dữ liệu Firebase của bạn. Bạn có thể xem thông tin này bằng cách đăng nhập vào tài khoản Firebase rồi chuyển đến thẻ dữ liệu trong ứng dụng của bạn. Khi đó, khi người khác nhấp vào bản đồ của bạn, bạn cũng như người đó đều có thể nhìn thấy các điểm trên bản đồ. Vị trí của lượt nhấp vẫn tồn tại ngay cả sau khi người dùng đóng trang. Bạn có thể mở trang trong hai cửa sổ riêng để kiểm tra chức năng cộng tác theo thời gian thực. Điểm đánh dấu sẽ xuất hiện trên cả hai khu vực này theo thời gian thực.

Tìm hiểu thêm

Firebase là một nền tảng ứng dụng lưu trữ dữ liệu dưới dạng JSON và đồng bộ hoá với tất cả ứng dụng được kết nối theo thời gian thực. Bạn có thể sử dụng tính năng này ngay cả khi ứng dụng không có kết nối mạng. Hướng dẫn này sử dụng cơ sở dữ liệu theo thời gian thực.