Share Location With HTML, JS & Leaflet: A Tutorial

by Alex Johnson 51 views

Have you ever wanted to share your precise location with a friend, family member, or even for a web application? This guide will walk you through creating a simple web page using HTML, JavaScript, and the Leaflet library to share your location with permission. This method prioritizes user privacy by only accessing location data when explicitly authorized. Let's dive in!

Understanding the Core Components

Before we jump into the code, let's break down the key technologies we'll be using:

  • HTML (HyperText Markup Language): This is the foundation of our web page, providing the structure and content, such as buttons, text, and the map container.
  • JavaScript: This dynamic scripting language will handle the logic for requesting location access, displaying the coordinates, and interacting with the Leaflet map.
  • Geolocation API: A browser API that allows websites to request and access a user's location data (with their permission, of course!).
  • Leaflet: A popular open-source JavaScript library for creating interactive maps. We'll use it to display the user's location on a map using OpenStreetMap tiles.

Setting Up the HTML Structure

First, let's create the basic HTML structure for our page. This includes the title, a description, a button to trigger location sharing, and a div element where the map will be displayed.

<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Share Lokasi — Klik & Beri Izin</title>
  <style>
    body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial; padding: 18px; max-width:900px; margin:auto; color:#111 }
    h1 { font-size:1.4rem; margin-bottom:6px }
    p.lead { margin-top:0; color:#444 }
    button { padding:10px 14px; border-radius:8px; border:1px solid #2b6cb0; background:#3182ce; color:white; cursor:pointer; font-weight:600 }
    .muted { color:#666; font-size:0.92rem }
    #info { margin-top:12px; }
    #map { height: 360px; width:100%; border-radius:8px; margin-top:12px; display:none; box-shadow:0 6px 18px rgba(0,0,0,0.08) }
    .field { margin:6px 0; }
    .actions { margin-top:10px; display:flex; gap:8px; flex-wrap:wrap }
    .linkish { background:#f3f4f6; padding:8px 10px; border-radius:6px; font-family:monospace; word-break:break-all }
    small { color:#666 }
  </style>

  <!-- Leaflet untuk peta (OpenStreetMap) -->
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
    integrity="sha256-sA+e2Gv4k5y8k8c3g6kOa2k6j9zv2Z2yVv6v1+Qm4sM=" crossorigin=""/>
</head>
<body>
  <h1>Bagikan Lokasi Anda (dengan izin)</h1>
  <p class="lead">Tekan tombol di bawah, lalu beri izin ketika browser menanyakan. Hanya akan membaca lokasi saat Anda setuju.</p>

  <div>
    <button id="btn">Bagikan Lokasi Saya</button>
    <span style="margin-left:10px" class="muted">(Butuh izin dari pengguna)</span>
  </div>

  <div id="info" aria-live="polite"></div>

  <div class="actions" id="actions" style="display:none">
    <button id="copyBtn">Salin link Google Maps</button>
    <button id="downloadBtn">Download lokasi (.txt)</button>
  </div>

  <div id="map"></div>

  <p style="margin-top:14px" class="muted">
    Catatan: Halaman ini hanya membaca lokasi ketika pengunjung menekan tombol dan memberi izin. Jangan gunakan untuk melacak orang tanpa persetujuan mereka — itu melanggar privasi dan bisa ilegal.
  </p>

  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
    integrity="sha256-kxZ2aXn00u7y+0Vf8f3Q0r3b8b0qk2gqG2p0d9y+7oM=" crossorigin=""></script>
  <script>
    const btn = document.getElementById('btn');
    const info = document.getElementById('info');
    const actions = document.getElementById('actions');
    const copyBtn = document.getElementById('copyBtn');
    const downloadBtn = document.getElementById('downloadBtn');
    const mapEl = document.getElementById('map');

    let lastPosition = null;
    let map, marker;

    function showMessage(html){
      info.innerHTML = html;
    }

    function formatCoords(pos){
      const c = pos.coords;
      const time = new Date(pos.timestamp).toLocaleString();
      return `
        <div class="field"><strong>Latitude:</strong> ${c.latitude}</div>
        <div class="field"><strong>Longitude:</strong> ${c.longitude}</div>
        <div class="field"><strong>Akurasi:</strong> ${c.accuracy} meter</div>
        <div class="field"><strong>Waktu:</strong> ${time}</div>
        <div style="margin-top:8px" class="linkish">geo:${c.latitude},${c.longitude}</div>
      `;
    }

    function showMap(lat, lng){
      mapEl.style.display = 'block';
      if(!map){
        map = L.map('map', { zoomControl: true }).setView([lat, lng], 15);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
          maxZoom: 19,
          attribution: '&copy; OpenStreetMap contributors'
        }).addTo(map);
        marker = L.marker([lat, lng]).addTo(map);
      } else {
        map.setView([lat, lng], 15);
        marker.setLatLng([lat, lng]);
      }
    }

    btn.addEventListener('click', async () => {
      if (!('geolocation' in navigator)){
        showMessage('<div style="color:crimson">Perangkat/browser Anda tidak mendukung Geolocation API.</div>');
        return;
      }

      showMessage('Meminta lokasi... (browser akan minta izin)');
      actions.style.display = 'none';

      // opsi: minta akurasi tinggi jika tersedia
      navigator.geolocation.getCurrentPosition(
        (pos) => {
          lastPosition = pos;
          showMessage(formatCoords(pos));
          actions.style.display = 'flex';

          const lat = pos.coords.latitude;
          const lng = pos.coords.longitude;
          showMap(lat, lng);
        },
        (err) => {
          let msg = `<div style="color:crimson"><strong>Gagal mendapatkan lokasi:</strong> ${err.message}</div>`;
          if (err.code === 1) msg = '<div style="color:crimson">Izin ditolak oleh pengguna.</div>';
          showMessage(msg);
          actions.style.display = 'none';
          mapEl.style.display = 'none';
        },
        { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
      );
    });

    copyBtn.addEventListener('click', () => {
      if(!lastPosition) return;
      const lat = lastPosition.coords.latitude;
      const lng = lastPosition.coords.longitude;
      const gm = `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`;
      navigator.clipboard.writeText(gm).then(() => {
        copyBtn.textContent = 'Tersalin!';
        setTimeout(()=> copyBtn.textContent = 'Salin link Google Maps', 1600);
      }).catch(()=> {
        alert('Gagal menyalin ke clipboard. Anda bisa salin manual: ' + gm);
      });
    });

    downloadBtn.addEventListener('click', () => {
      if(!lastPosition) return;
      const lat = lastPosition.coords.latitude;
      const lng = lastPosition.coords.longitude;
      const acc = lastPosition.coords.accuracy;
      const time = new Date(lastPosition.timestamp).toISOString();
      const text = `Latitude: ${lat}\nLongitude: ${lng}\nAccuracy(m): ${acc}\nTime: ${time}\nGoogleMaps: https://www.google.com/maps/search/?api=1&query=${lat},${lng}\n`;
      const blob = new Blob([text], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'lokasi.txt';
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    });

  </script>
</body>
</html>

Key elements in this HTML include:

  • A button with the ID btn that triggers the location sharing process.
  • A div with the ID info to display messages and coordinates.
  • A div with the ID map where the Leaflet map will be rendered.
  • Buttons with IDs copyBtn and downloadBtn to copy the Google Maps link and download the location as a text file, respectively.

Feel free to customize the styling to match your preferences.

Implementing the JavaScript Logic

Now comes the exciting part – adding the JavaScript code to handle location requests, display information, and render the map. Let's break down the script step by step.

1. Accessing DOM Elements

First, we need to get references to the HTML elements we'll be interacting with. This is done using document.getElementById():

const btn = document.getElementById('btn');
const info = document.getElementById('info');
const actions = document.getElementById('actions');
const copyBtn = document.getElementById('copyBtn');
const downloadBtn = document.getElementById('downloadBtn');
const mapEl = document.getElementById('map');

2. Initializing Variables

We'll also need a few variables to store the user's last known position and the Leaflet map instance:

let lastPosition = null;
let map, marker;

3. Displaying Messages

A simple function to update the info div with messages:

function showMessage(html){
  info.innerHTML = html;
}

4. Formatting Coordinates

This function takes a Position object (returned by the Geolocation API) and formats the latitude, longitude, accuracy, and timestamp into an HTML string for display:

function formatCoords(pos){
  const c = pos.coords;
  const time = new Date(pos.timestamp).toLocaleString();
  return `
    <div class="field"><strong>Latitude:</strong> ${c.latitude}</div>
    <div class="field"><strong>Longitude:</strong> ${c.longitude}</div>
    <div class="field"><strong>Akurasi:</strong> ${c.accuracy} meter</div>
    <div class="field"><strong>Waktu:</strong> ${time}</div>
    <div style="margin-top:8px" class="linkish">geo:${c.latitude},${c.longitude}</div>
  `;
}

5. Displaying the Map with Leaflet

This function initializes or updates the Leaflet map with the given latitude and longitude. It creates a new map instance if one doesn't exist, sets the view to the provided coordinates, adds a tile layer (using OpenStreetMap), and places a marker on the user's location. If a map already exists, it simply updates the view and marker position.

function showMap(lat, lng){
  mapEl.style.display = 'block';
  if(!map){
    map = L.map('map', { zoomControl: true }).setView([lat, lng], 15);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 19,
      attribution: '&copy; OpenStreetMap contributors'
    }).addTo(map);
    marker = L.marker([lat, lng]).addTo(map);
  } else {
    map.setView([lat, lng], 15);
    marker.setLatLng([lat, lng]);
  }
}

6. Handling the Button Click

This is the core of our script. It's an event listener attached to the button that triggers the location sharing process. It first checks if the Geolocation API is supported by the browser. If not, it displays an error message. If supported, it requests the user's location using navigator.geolocation.getCurrentPosition(). This function takes three arguments:

  • A success callback function that's executed if the location is successfully retrieved.
  • An error callback function that's executed if there's an error (e.g., the user denies permission).
  • An options object that allows you to configure the location request (e.g., requesting high accuracy).
btn.addEventListener('click', async () => {
  if (!('geolocation' in navigator)){
    showMessage('<div style="color:crimson">Perangkat/browser Anda tidak mendukung Geolocation API.</div>');
    return;
  }

  showMessage('Meminta lokasi... (browser akan minta izin)');
  actions.style.display = 'none';

  // opsi: minta akurasi tinggi jika tersedia
  navigator.geolocation.getCurrentPosition(
    (pos) => {
      lastPosition = pos;
      showMessage(formatCoords(pos));
      actions.style.display = 'flex';

      const lat = pos.coords.latitude;
      const lng = pos.coords.longitude;
      showMap(lat, lng);
    },
    (err) => {
      let msg = `<div style="color:crimson"><strong>Gagal mendapatkan lokasi:</strong> ${err.message}</div>`;
      if (err.code === 1) msg = '<div style="color:crimson">Izin ditolak oleh pengguna.</div>';
      showMessage(msg);
      actions.style.display = 'none';
      mapEl.style.display = 'none';
    },
    { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
  );
});

The success callback function formats the coordinates, displays them, shows the action buttons, and calls showMap() to render the map. The error callback function displays an error message (including a specific message if the user denied permission) and hides the map.

7. Copying to Google Maps Link

This event listener attached to the copyBtn creates a Google Maps link from the user's last known coordinates and copies it to the clipboard using the navigator.clipboard.writeText() method. It also provides feedback to the user by changing the button text temporarily.

copyBtn.addEventListener('click', () => {
  if(!lastPosition) return;
  const lat = lastPosition.coords.latitude;
  const lng = lastPosition.coords.longitude;
  const gm = `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`;
  navigator.clipboard.writeText(gm).then(() => {
    copyBtn.textContent = 'Tersalin!';
    setTimeout(()=> copyBtn.textContent = 'Salin link Google Maps', 1600);
  }).catch(()=> {
    alert('Gagal menyalin ke clipboard. Anda bisa salin manual: ' + gm);
  });
});

8. Downloading Location as Text

This event listener attached to the downloadBtn creates a text file containing the user's latitude, longitude, accuracy, timestamp, and a Google Maps link. It then triggers a download of this file.

downloadBtn.addEventListener('click', () => {
  if(!lastPosition) return;
  const lat = lastPosition.coords.latitude;
  const lng = lastPosition.coords.longitude;
  const acc = lastPosition.coords.accuracy;
  const time = new Date(lastPosition.timestamp).toISOString();
  const text = `Latitude: ${lat}\nLongitude: ${lng}\nAccuracy(m): ${acc}\nTime: ${time}\nGoogleMaps: https://www.google.com/maps/search/?api=1&query=${lat},${lng}\n`;
  const blob = new Blob([text], { type: 'text/plain' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'lokasi.txt';
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(url);
});

Important Considerations

  • User Privacy: Always prioritize user privacy. Only request location access when necessary and clearly communicate why you need it. Displaying the location on a map is a great way to give users context.
  • Error Handling: The Geolocation API can fail for various reasons (e.g., the user denies permission, the device doesn't have GPS). Make sure to handle these errors gracefully and provide informative messages to the user.
  • HTTPS: The Geolocation API requires a secure context (HTTPS). Your page won't be able to access the user's location if it's served over HTTP.
  • Accuracy: The accuracy of the location data can vary depending on the device and environment. The accuracy property of the Coordinates object indicates the accuracy in meters.

Conclusion

This guide has demonstrated how to create a simple yet effective web page for sharing location with user permission using HTML, JavaScript, and Leaflet. You can extend this foundation to build more complex location-aware applications. Remember to always prioritize user privacy and handle potential errors gracefully.

For further learning about the Geolocation API, visit the Mozilla Developer Network (MDN) documentation.