Akhir-akhir ini gue lagi eksperimen pake Nuxt 4 buat eksplor kemampuannya dalam ngebangun aplikasi web interaktif. Salah satu hasilnya, gue coba bikin peta interaktif Jakarta yang lengkap dengan clustered markers, custom popups, dan chart terintegrasi. Tutorial ini bakal ngebahas gimana cara gue ngebangunnya pake Nuxt 4, Leaflet, Leaflet.markercluster, dan Highcharts.

Live Demo: interactive-map-nuxt.vercel.app
Source Code: GitHub Repository

Tech Stack

  • Nuxt 4 – framework Vue modern dengan dukungan TypeScript yang mantap.
  • Tailwind CSS – buat styling yang sat-set dan responsif.
  • Leaflet – library andalan buat peta interaktif.
  • Leaflet.markercluster – buat pengelompokan (clustering) marker secara otomatis.
  • Highcharts – buat nampilin chart di dalam popup atau offcanvas.

Setup Project

Mulai dengan bikin project Nuxt 4 baru:

npx nuxi init interactive-map-nuxt
cd interactive-map-nuxt
npm install

Install dependencies yang dibutuhin:

npm install leaflet leaflet.markercluster highcharts @nuxtjs/tailwindcss

Konfigurasi di nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss'],
  css: [
    'leaflet/dist/leaflet.css',
    '@/assets/css/main.css'
  ],
  devtools: { enabled: true },
})

Struktur Folder

interactive-map-nuxt/
├─ app/
│  ├─ layouts/
│  │  └─ default.vue
│  ├─ pages/
│  │  └─ index.vue
│  └─ composables/
│     └─ useJakartaMap.ts
├─ assets/css/main.css
└─ public/jakarta.json

Struktur Folder

Membuat Map

<template>
  <div ref="mapContainer" class="fixed inset-0 z-0"></div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const mapContainer = ref<HTMLDivElement | null>(null);

onMounted(async () => {
  if (!mapContainer.value) return;

  const L = await import('leaflet');

  const map = L.map(mapContainer.value, {
    center: [-6.2088, 106.8456], // Jakarta
    zoom: 12,
    minZoom: 11,
    maxZoom: 18,
    scrollWheelZoom: true,
  });

  L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
    attribution: '© Carto © OpenStreetMap',
    subdomains: 'abcd',
    maxZoom: 19,
  }).addTo(map);
});
</script>

Basic Map

Menambahkan Marker & Clustering

import 'leaflet.markercluster';

const markers = L.markerClusterGroup();

data.features.forEach((feature) => {
  const [lng, lat] = feature.geometry.coordinates;
  const marker = L.marker([lat, lng]);
  marker.bindPopup(`<b>${feature.properties.name}</b><br>${feature.properties.category}`);
  markers.addLayer(marker);
});

map.addLayer(markers);

Custom Popup / Offcanvas

<div v-if="dialog.visible"
     class="absolute bg-white shadow-lg rounded-lg p-4 w-64 transition-all duration-200"
     :style="{ top: dialog.y + 'px', left: dialog.x + 'px' }">
  <h3 class="font-bold text-lg">{{ dialog.data?.name }}</h3>
  <p class="text-sm text-gray-600">Kategori: {{ dialog.data?.category }}</p>
  <ul class="list-disc ml-4 text-sm">
    <li v-for="(val, year) in dialog.data?.visitors" :key="year">
      {{ year }}: {{ val.toLocaleString() }}
    </li>
  </ul>
  <button @click="dialog.visible = false" class="mt-3 text-sm text-blue-600 hover:underline">
    Tutup
  </button>
</div>

Integrasi Highcharts

import Highcharts from 'highcharts';

Highcharts.chart('chart-container', {
  chart: { type: 'pie', height: 200 },
  title: { text: 'Breakdown Pengunjung' },
  series: [{
    name: 'Pengunjung',
    data: [
      { name: 'Domestik', y: feature.properties.visitors['2023'] * 0.7 },
      { name: 'Internasional', y: feature.properties.visitors['2023'] * 0.3 }
    ]
  }]
});

Custom Marker Icons

const icon = L.icon({
  iconUrl: '/marker-icon.png',
  iconSize: [25, 41],
  iconAnchor: [12, 41]
});

L.marker([lat, lng], { icon }).addTo(map);

Deployment

npm run build
npm run preview

Lanjut deploy ke Vercel. Preview: https://interactive-map-nuxt.vercel.app/

Kesimpulan

Eksperimen ini ngajarin gue banyak hal soal Nuxt 4, Leaflet, dan cara integrasi chart ke dalam peta interaktif. Sekarang lo udah punya peta yang fungsional dengan fitur:

  • Marker clustering (pengelompokan marker)
  • Custom popup dengan style Tailwind
  • Visualisasi Highcharts
  • Layout peta yang responsif dan interaktif

Lo bisa kembangin tutorial ini buat kota lain, dataset yang beda, atau bahkan visualisasi data real-time.