Ringkasan
Tutorial ini menampilkan cara membuat peta interaktif dengan menggunakan platform aplikasi Firebase. Coba klik beberapa lokasi yang berbeda pada peta di bawah untuk membuat peta panas.
Bagian di bawah ini menampilkan seluruh kode yang Anda butuhkan untuk membuat peta dalam tutorial ini.
/** * 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>
Cobalah sendiri
Anda dapat bereksperimen dengan kode ini di JSFiddle dengan mengklik ikon <>
di sudut kanan atas jendela kode.
<!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>
Memulai
Anda dapat mengembangkan versi peta Firebase sendiri menggunakan kode dalam tutorial ini. Untuk mulai melakukannya, buat file baru di editor teks dan simpan sebagai index.html
.
Bacalah bagian-bagian berikut untuk memahami kode yang bisa Anda tambahkan ke file ini.
Membuat peta dasar
Bagian ini menjelaskan kode yang akan menyiapkan peta dasar. Caranya mungkin mirip dengan proses pembuatan peta saat memulai Maps JavaScript API.
Salin kode di bawah ke dalam file index.html
Anda. Kode ini memuat Maps JavaScript API, dan membuat peta menjadi layar penuh. Kode ini juga akan memuat library visualisasi, yang nanti Anda butuhkan dalam tutorial untuk membuat peta panas.
<!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>
Klik YOUR_API_KEY
dalam contoh kode, atau ikuti petunjuk untuk mendapatkan kunci API. Ganti YOUR_API_KEY
dengan kunci API aplikasi Anda.
Bagian berikut ini menjelaskan kode JavaScript yang akan membuat peta Firebase. Anda dapat menyalin dan menyimpan kode dalam file firebasemap.js
, serta mereferensikannya di antara tag skrip seperti di bawah.
<script>firebasemap.js</script>
Atau, Anda dapat langsung menyisipkan kode dalam tag skrip seperti dalam kode contoh lengkap di awal tutorial ini.
Tambahkan kode di bawah ke file firebasemap.js
, atau di antara tag skrip kosong pada file index.html
Anda. Ini adalah titik awal yang menjalankan program dengan membuat fungsi yang akan memulai objek peta.
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 }); }
Agar peta panas yang dapat diklik ini lebih mudah digunakan, kode di atas menggunakan gaya visual peta untuk menonaktifkan lokasi menarik dan stasiun transportasi umum (yang menampilkan jendela info saat diklik). Kode ini juga menonaktifkan zoom pada klik dua kali untuk mencegah zoom yang tidak disengaja. Baca selengkapnya tentang menata gaya peta.
Setelah API dimuat sepenuhnya, parameter callback dalam tag skrip di bawah akan mengeksekusi fungsi initMap()
di file HTML.
<script defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY
&libraries=visualization&callback=initMap">
</script>
Tambahkan kode di bawah ini untuk membuat kontrol teks di bagian atas peta.
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); }
Tambahkan kode di bawah di dalam fungsi initMap
, setelah var map
, untuk memuat kotak kontrol teks.
// 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);Coba sekarang
Untuk melihat peta Google yang dibuat oleh kode, buka file index.html
di browser web.
Mempersiapkan Firebase
Agar aplikasi ini kolaboratif, Anda harus menyimpan klik dalam database eksternal yang bisa diakses oleh semua pengguna. Firebase Realtime Database cocok untuk keperluan ini, dan tidak memerlukan pengetahuan SQL.
Pertama, daftar ke akun Firebase tanpa biaya.
Jika masih baru dengan Firebase, Anda akan melihat aplikasi baru bernama "My First App". Jika
membuat aplikasi baru, Anda dapat memberinya nama baru dan URL Firebase kustom yang diakhiri dengan
firebaseIO.com
. Misalnya, Anda dapat memberi nama aplikasi "Jane's Firebase Map" dengan URL
https://janes-firebase-map.firebaseIO.com
. Anda dapat menggunakan URL ini untuk menautkan database ke aplikasi JavaScript.
Tambahkan baris di bawah setelah tag <head>
pada file HTML Anda untuk mengimpor library Firebase.
<script src="www.gstatic.com/firebasejs/5.3.0/firebase.js"></script>
Tambahkan baris berikut ke file JavaScript Anda:
var firebase = new Firebase("<Your Firebase URL here>");
Menyimpan data klik di Firebase
Bagian ini menjelaskan kode yang menyimpan data di Firebase serta klik mouse pada peta.
Untuk setiap klik pada peta, kode di bawah ini akan membuat objek data global dan menyimpan informasinya dalam Firebase. Objek ini mencatat data seperti latLng, dan stempel waktu klik, serta ID unik browser yang membuat klik tersebut.
/** * Data object to be written to Firebase. */ var data = { sender: null, timestamp: null, lat: null, lng: null };
Kode di bawah ini merekam ID sesi unik setiap klik, yang membantu mengontrol laju lalu lintas pada peta sehubungan dengan aturan keamanan 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. } }); }
Bagian berikutnya dari kode di bawah ini memantau klik pada peta, yang menambahkan 'turunan' ke database Firebase Anda. Jika ini terjadi, fungsi snapshot.val()
mendapatkan nilai data entri dan membuat objek LatLng baru.
// 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); } );
Kode di bawah ini menyiapkan Firebase untuk:
- Mendeteksi klik pada peta. Saat terjadi klik, aplikasi akan merekam stempel waktu, kemudian menambahkan 'turunan' ke database Firebase.
- Menghapus semua klik di peta yang berdurasi lebih dari 10 menit secara real time.
/** * 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); }); }
Salin semua kode JavaScript di bagian ini ke file firebasemap.js
Anda.
Membuat peta panas
Langkah berikutnya adalah menampilkan peta panas yang memberikan tayangan grafis kepada pengguna atas jumlah klik relatif pada beragam lokasi di peta. Untuk mempelajari lebih lanjut, baca panduan peta panas.
Tambahkan kode di bawah di dalam fungsi initMap()
untuk membuat peta panas.
// Create a heatmap. var heatmap = new google.maps.visualization.HeatmapLayer({ data: [], map: map, radius: 16 });
Kode di bawah memicu fungsi initFirebase
, addToFirebase
,
dan getTimestamp
.
initAuthentication(initFirebase.bind(undefined, heatmap));
Perhatikan, jika Anda mengklik peta panas, titik-titik tersebut tidak akan langsung dibuat. Untuk membuat titik pada peta, Anda perlu menyiapkan pemroses peta.
Membuat titik-titik pada peta panas
Kode di bawah menambahkan pemroses di dalam initMap()
, setelah kode yang membuat peta. Kode ini memantau data dari setiap klik, menyimpan lokasi klik Anda dalam database Firebase, dan menampilkan titik-titik pada peta panas.
// 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); });Coba sekarang
Klik lokasi pada peta untuk membuat titik-titik pada peta panas Anda.
Anda kini memiliki aplikasi real time yang berfungsi penuh menggunakan Firebase dan Maps JavaScript API.
Jika mengklik peta panas, lintang dan bujur klik tersebut kini seharusnya muncul dalam database Firebase Anda. Anda dapat melihatnya dengan login ke akun Firebase dan membuka tab data aplikasi Anda. Pada tahap ini, jika orang lain mengklik peta, Anda serta orang tersebut dapat melihat titik di peta. Lokasi klik akan dipertahankan bahkan setelah pengguna menutup halaman. Sebagai cara untuk menguji fungsionalitas kolaboratif realtime, buka halaman di dua jendela terpisah. Penanda akan muncul pada kedua jendela secara real time.
Pelajari lebih lanjut
Firebase adalah platform aplikasi yang menyimpan data sebagai JSON, dan menyinkronkannya ke semua klien yang terhubung secara real time. Data ini tersedia meskipun aplikasi Anda offline. Tutorial ini menggunakan database realtime-nya.