סקירה כללית
במדריך הזה תלמדו איך ליצור מפה אינטראקטיבית באמצעות פלטפורמת האפליקציות של 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
. הקוד הזה טוען את 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 שנוצרת על ידי הקוד, פותחים את הקובץ index.html
בדפדפן אינטרנט.
הגדרת Firebase
כדי שהאפליקציה תהיה שיתופית, צריך לאחסן את הקליקים במסד נתונים חיצוני שאליו כל המשתמשים יכולים לגשת. מסד הנתונים בזמן אמת של Firebase מתאים למטרה הזו, ואין צורך בידע ב-SQL.
קודם כול, נרשמים לחשבון 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. האובייקט הזה מתעד נתונים כמו latLng וחותמת הזמן של הקליק, וגם מזהה ייחודי של הדפדפן שיצר את הקליק.
/** * 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 ומסתנכרנת עם כל הלקוחות המחוברים בזמן אמת. הוא זמין גם כשהאפליקציה עוברת למצב אופליין. המדריך הזה משתמש במסד הנתונים שלו בזמן אמת.