الربط الفوري التعاوني باستخدام 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.

اقرأ الأقسام التالية لفهم الرمز الذي يمكنك إضافته إلى هذا الملف.

إنشاء خريطة أساسية

يشرح هذا القسم الرمز الذي يقوم بإعداد الخريطة الأساسية. قد يكون هذا مشابهًا لكيفية إنشاء الخرائط عندما بدء استخدام واجهة برمجة تطبيقات JavaScript للخرائط.

انسخ الرمز أدناه إلى ملف index.html. ويحمّل هذا الرمز ملف واجهة برمجة تطبيقات JavaScript للخرائط وتجعل الخريطة بملء الشاشة. كما يقوم بتحميل التصور والتي ستحتاج إليها لاحقًا في البرنامج التعليمي لإنشاء خريطة تمثيل لوني.

<!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 في عيّنة الرمز البرمجي أو اتّبِع التعليمات الحصول على مفتاح واجهة برمجة التطبيقات استبدال YOUR_API_KEY باستخدام مفتاح واجهة برمجة التطبيقات لتطبيقك.

توضّح الأقسام التالية رمز 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
  });
}

من أجل تسهيل استخدام خريطة التمثيل اللوني هذه القابلة للنقر، يستخدم الكود أعلاه تصميم الخريطة لتعطيل نقاط الاهتمام ومحطات النقل العام (التي تعرض نافذة معلومات عند النقر فوقها). كما يتم إيقاف التكبير/التصغير عند النقر المزدوج منع التكبير غير المقصود. مزيد من المعلومات عن تصميم خريطتك.

بعد تحميل واجهة برمجة التطبيقات بالكامل، يتم استخدام مَعلمة معاودة الاتصال في علامة النص البرمجي أدناه تنفذ الدالة 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

لجعل هذا التطبيق تعاونيًا، يجب تخزين النقرات في واجهة مستخدم رسومية قاعدة بيانات يمكن لجميع المستخدمين الوصول إليها. وتناسب قاعدة بيانات 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.
    }
  });
}

يستمع القسم التالي من الرمز أدناه إلى النقرات على الخريطة، مما يضيف العنصر "child" إلى قاعدة بيانات 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 من أجل:

  • الاستماع إلى النقرات على الخريطة. وعند حدوث نقرة، يسجِّل التطبيق طابع زمني، ثم تتم إضافة "child" إلى قاعدة بيانات 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 واجهة برمجة تطبيقات JavaScript للخرائط.

عند النقر على خريطة التمثيل اللوني، يجب أن يكون خط العرض وخط الطول للنقرة تظهر الآن في قاعدة بيانات Firebase يمكنك مشاهدة ذلك عن طريق تسجيل الدخول إلى حساب Firebase والانتقال إلى علامة تبويب "البيانات" في تطبيقك. في هذه المرحلة، إذا نقر شخص آخر على خريطتك، فستتمكّن أنت وهذا الشخص أيضًا من الاطّلاع على نقاط على الخريطة. ويستمر موقع النقرات حتى بعد أن ينتهي المستخدم يغلق الصفحة. كطريقة لاختبار وظائف التعاون في الوقت الفعلي، فتح الصفحة في نافذتين منفصلتين. يجب أن تظهر العلامات على كليهما في في الوقت الفعلي.

مزيد من المعلومات

Firebase هو نظام أساسي للتطبيقات يخزِّن البيانات بتنسيق JSON وتتم مزامنتها مع جميع والعملاء المتصلين في الوقت الفعلي. وتتوفّر هذه الميزة حتى عندما يكون التطبيق غير متصل بالإنترنت. يستخدم هذا البرنامج التعليمي قاعدة البيانات الخاصة به في الوقت الفعلي.