Peta panas mengubah awan titik koordinat menjadi permukaan kepadatan yang dapat dibaca secara instan. Warna panas menandai tempat acara bergerombol; warna dingin menandai tempat mereka menipis. Pengguna memahami pola sebelum mereka membaca label tunggal. Itulah mengapa peta panas adalah pilihan default untuk analisis lalu lintas kaki, perkiraan permintaan pengiriman, alat pelaporan kejahatan, dan penelitian harga properti.
Tutorial ini membangun peta panas interaktif dari awal menggunakan SDK MapAtlas. Anda akan menstruktur data titik sebagai GeoJSON berbobot, merender lapisan kepadatan dengan gradien warna kustom, menghubungkan slider intensitas, dan menyelesaikan dengan contoh permintaan pengiriman dunia nyata. Pada akhirnya Anda akan memiliki pola yang dapat digunakan kembali yang dapat Anda jatuhkan ke proyek JavaScript atau React apa pun.
Jika Anda baru mengenal SDK MapAtlas, baca Cara Menambahkan Peta Interaktif ke Situs Web Anda terlebih dahulu. Ini mencakup instalasi, inisialisasi peta, dan penanda. Tutorial ini melanjutkan di mana yang lain berhenti.
Kapan Menggunakan Heatmap
Peta panas adalah alat yang tepat ketika Anda memiliki kumpulan besar lokasi titik individual dan ingin mengkomunikasikan kepadatan, bukan identitas. Penanda individual kehilangan makna melewati beberapa ratus poin; peta panas mengungkapkan struktur yang tidak bisa diungkap oleh jumlah pin apa pun.
Kasus penggunaan umum:
- Analisis lalu lintas pejalan kaki: pemilihan situs ritel, perencanaan kota, pemodelan kerumunan acara. Jatuhkan ping GPS untuk setiap pelanggan yang melewati pintu dan peta panas menunjukkan area kota, pusat belanja, atau tempat mana yang menarik paling banyak orang.
- Permintaan pengiriman: agregat asal pesanan menurut kode pos atau koordinat mentah untuk menunjukkan kepada dispatcher di mana permintaan terkonsentrasi. Ini memberi makan langsung ke perencanaan zona dan alokasi pengemudi.
- Data kejahatan dan insiden: dasbor analitik kepolisian, peta risiko asuransi, dan alat pelaporan keselamatan publik semua menggunakan peta panas kepadatan untuk mengkomunikasikan risiko spasial tanpa membanjiri pengguna dengan penanda individual.
- Gradien harga properti: ketika dikombinasikan dengan nilai berbobot, peta panas dapat menunjukkan di mana harga tertinggi di seluruh kota. Lihat tutorial Real Estate Property Map untuk lebih lanjut tentang membangun alat peta yang berfokus pada properti.
Jika pertanyaan Anda adalah "di mana hal-hal terjadi paling banyak?" peta panas adalah jawaban Anda.
Format Data: Poin GeoJSON Berbobot
Lapisan peta panas MapAtlas membaca FeatureCollection GeoJSON standar dari fitur Point. Setiap fitur dapat membawa properti weight yang menskalakan kontribusinya ke permukaan kepadatan. Pesanan pengiriman senilai 10 barang berkontribusi lebih banyak panas daripada pesanan satu item; pusat transit utama menghasilkan lebih banyak lalu lintas pejalan kaki daripada jalan samping.
const demandData = {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: { type: "Point", coordinates: [4.8952, 52.3702] },
properties: { weight: 8, zone: "centrum" }
},
{
type: "Feature",
geometry: { type: "Point", coordinates: [4.9123, 52.3601] },
properties: { weight: 3, zone: "oost" }
},
{
type: "Feature",
geometry: { type: "Point", coordinates: [4.8801, 52.3780] },
properties: { weight: 12, zone: "west" }
},
{
type: "Feature",
geometry: { type: "Point", coordinates: [4.9041, 52.3540] },
properties: { weight: 1, zone: "south" }
}
]
};
Nilai weight bersifat tanpa dimensi. Anda menormalkannya relatif terhadap rentang dataset Anda. Jika zona permintaan tertinggi Anda menghasilkan 500 pesanan dan yang tertenang menghasilkan 10, petakan mereka ke skala 1 hingga 10 sebelum meneruskannya. Ini menjaga peta panas tetap bermakna secara visual di seluruh dataset dengan hitungan absolut yang sangat berbeda.
Tanpa properti weight, setiap titik berkontribusi secara merata dan peta panas mencerminkan kepadatan hitungan murni.
Prasyarat
Sebelum memulai:
- Kunci API MapAtlas (daftar gratis, tidak ada kartu kredit diperlukan)
- Node.js 18+ untuk proyek berbasis npm, atau halaman HTML biasa jika Anda lebih suka CDN
Langkah 1: Instal dan Inisialisasi Peta
Instal SDK:
npm install @mapmetrics/mapmetrics-gl
Atau muat melalui CDN di file HTML biasa:
<link
rel="stylesheet"
href="https://unpkg.com/@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css"
/>
<script src="https://unpkg.com/@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.js"></script>
Tambahkan kontainer dengan tinggi yang ditentukan:
<div id="map" style="width: 100%; height: 600px;"></div>
Inisialisasi peta. Gaya Gelap membuat gradien warna peta panas menonjol dari latar belakang, itulah mengapa ini adalah basis pilihan untuk visualisasi kepadatan:
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
const map = new mapmetricsgl.Map({
container: 'map',
style: 'https://tiles.mapatlas.eu/styles/dark/style.json?key=YOUR_API_KEY',
center: [4.9041, 52.3676], // Amsterdam
zoom: 12,
});
Langkah 2: Tambahkan Lapisan Heatmap
Daftarkan GeoJSON Anda sebagai sumber, lalu tambahkan lapisan peta panas yang membacanya. Callback map.on('load', ...) memastikan gaya telah selesai dimuat sebelum Anda memodifikasinya.
map.on('load', () => {
map.addSource('demand', {
type: 'geojson',
data: demandData,
});
map.addLayer({
id: 'demand-heatmap',
type: 'heatmap',
source: 'demand',
paint: {
// Weight each point by its 'weight' property (defaults to 1 if absent)
'heatmap-weight': [
'interpolate', ['linear'],
['get', 'weight'],
0, 0,
12, 1
],
// Radius in pixels; larger = smoother but less precise
'heatmap-radius': 30,
// Overall opacity of the heatmap layer
'heatmap-opacity': 0.85,
},
});
});
Pada titik ini Anda memiliki peta panas yang berfungsi. Area biru-hijau adalah kepadatan rendah; gradien default berubah menuju kuning dan merah pada kepadatan tinggi. Langkah berikutnya mengganti palet default dengan skema warna yang disengaja.
Langkah 3: Menyesuaikan Gradien Warna
Properti heatmap-color memetakan nilai kepadatan (0 hingga 1) ke warna menggunakan ekspresi interpolate yang sama yang digunakan di seluruh sistem cat MapAtlas lainnya. Kepadatan 0 transparan sehingga lapisan dasar peta menunjukkan melalui area kosong.
map.addLayer({
id: 'demand-heatmap',
type: 'heatmap',
source: 'demand',
paint: {
'heatmap-weight': [
'interpolate', ['linear'],
['get', 'weight'],
0, 0,
12, 1
],
'heatmap-radius': 30,
'heatmap-opacity': 0.85,
'heatmap-color': [
'interpolate', ['linear'],
['heatmap-density'],
0, 'rgba(0, 0, 255, 0)', // transparent at zero density
0.2, 'rgba(0, 128, 255, 0.6)',
0.4, 'rgba(0, 230, 200, 0.7)',
0.6, 'rgba(100, 230, 0, 0.8)',
0.8, 'rgba(255, 200, 0, 0.9)',
1.0, 'rgba(255, 50, 0, 1)' // bright red at peak density
],
},
});
Gradien ini berjalan biru (jarang) melalui hijau dan kuning menjadi merah (padat), cocok dengan model mental yang dibawa sebagian besar pengguna dari peta radar cuaca dan pencitraan termal. Jika aplikasi Anda memiliki palet warna bermerek, ganti nilai RGB dengan berhenti Anda sendiri; interpolasi menangani transisi halus secara otomatis.
Tip desain: Untuk dasbor profesional dan alat analitik, jaga bagian kepadatan rendah tetap hampir transparan. Ini mempertahankan keterbacaan peta dasar di area tenang dan menarik mata secara alami ke zona panas.
Langkah 4: Menambahkan Slider Radius untuk Kontrol Interaktif
Radius peta panas mengontrol seberapa jauh setiap titik "memancarkan" pengaruh. Radius kecil (10 hingga 15px) menunjukkan cluster berbutir halus; radius besar (50 hingga 80px) menghasilkan permukaan yang lebih luas dan halus. Kasus penggunaan yang berbeda memerlukan default yang berbeda: lalu lintas pejalan kaki di pusat kota yang padat memerlukan radius kecil, permintaan pengiriman nasional di seluruh negara memerlukan radius besar.
Berikan pengguna slider sehingga mereka dapat menyesuaikan dengan cepat:
<div id="controls" style="position: absolute; top: 16px; left: 16px; z-index: 1;
background: white; padding: 12px 16px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
<label style="font-size: 14px; font-weight: 600;">
Radius: <span id="radius-value">30</span>px
</label>
<br />
<input id="radius-slider" type="range" min="5" max="80" value="30" style="width: 180px; margin-top: 6px;" />
</div>
Hubungkan slider ke setPaintProperty, yang memperbarui lapisan tanpa menambahkannya kembali:
const slider = document.getElementById('radius-slider');
const radiusLabel = document.getElementById('radius-value');
slider.addEventListener('input', () => {
const radius = Number(slider.value);
radiusLabel.textContent = radius;
map.setPaintProperty('demand-heatmap', 'heatmap-radius', radius);
});
setPaintProperty adalah pembaruan langsung tanpa kedipan. Peta panas merender ulang pada GPU dalam frame yang sama. Pola ini berfungsi untuk properti cat apa pun: opacity, intensitas, color stops.
Langkah 5: Penskalaan Intensitas Menurut Tingkat Zoom
Pada level zoom rendah (tampilan luas kota), titik-titik terdekat tumpang tindih berat dan peta panas dapat terlihat jenuh seragam. Pada zoom tinggi (level jalan), titik-titik yang sama tersebar dan permukaan kepadatan terlihat jarang. Kompensasi intensitas yang terkait zoom menjaga visualisasi tetap dapat dibaca pada setiap zoom.
paint: {
// ...other paint properties...
'heatmap-intensity': [
'interpolate', ['linear'],
['zoom'],
8, 1, // low zoom: normal intensity
14, 3 // high zoom: boost intensity to compensate for point spread
],
'heatmap-radius': [
'interpolate', ['linear'],
['zoom'],
8, 20, // small radius at city scale
14, 50 // larger radius at street scale
],
},
Kedua properti menggunakan ekspresi interpolate yang sama di atas zoom. Nilai-nilai antara pemberhentian diinterpolasi secara linier, sehingga transisi halus saat pengguna zoom.
Contoh Dunia Nyata: Heatmap Permintaan Pengiriman
Berikut adalah implementasi lengkap yang berdiri sendiri untuk dasbor permintaan pengiriman. Pesanan tiba dari API sebagai GeoJSON FeatureCollection. Peta panas diperbarui setiap kali pengguna mengubah filter waktu.
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
const API_KEY = 'YOUR_API_KEY';
const map = new mapmetricsgl.Map({
container: 'map',
style: `https://tiles.mapatlas.eu/styles/dark/style.json?key=${API_KEY}`,
center: [4.9041, 52.3676],
zoom: 11,
});
async function loadOrders(hourFrom, hourTo) {
const res = await fetch(
`/api/orders/geojson?hour_from=${hourFrom}&hour_to=${hourTo}`
);
return res.json(); // returns a GeoJSON FeatureCollection
}
map.on('load', async () => {
const orders = await loadOrders(8, 12); // morning peak
map.addSource('orders', { type: 'geojson', data: orders });
map.addLayer({
id: 'order-heatmap',
type: 'heatmap',
source: 'orders',
paint: {
'heatmap-weight': [
'interpolate', ['linear'], ['get', 'items'],
0, 0, 20, 1
],
'heatmap-color': [
'interpolate', ['linear'], ['heatmap-density'],
0, 'rgba(0, 0, 255, 0)',
0.2, 'rgba(0, 128, 255, 0.5)',
0.5, 'rgba(0, 230, 150, 0.8)',
0.8, 'rgba(255, 200, 0, 0.9)',
1.0, 'rgba(255, 50, 0, 1)'
],
'heatmap-radius': [
'interpolate', ['linear'], ['zoom'],
8, 20, 14, 50
],
'heatmap-intensity': [
'interpolate', ['linear'], ['zoom'],
8, 1, 14, 3
],
'heatmap-opacity': 0.9,
},
});
// Time-of-day filter buttons
document.querySelectorAll('[data-hour-range]').forEach((btn) => {
btn.addEventListener('click', async () => {
const [from, to] = btn.dataset.hourRange.split('-').map(Number);
const newOrders = await loadOrders(from, to);
map.getSource('orders').setData(newOrders);
});
});
});
Panggilan setData pada sumber yang sudah ada mengganti GeoJSON tanpa menambahkan kembali lapisan. Peta panas merender ulang secara otomatis. Pola ini skala ke filter berbasis waktu apa pun: jam dalam sehari, hari dalam seminggu, kondisi cuaca.
Untuk lapisan perencanaan rute yang biasanya menyertai peta panas permintaan pengiriman, lihat tutorial Route Optimization API. Overlay rute pengiriman yang dioptimalkan di atas peta panas permintaan memberikan dispatcher gambaran operasional lengkap dalam satu tampilan.
Tips Kinerja untuk Dataset Besar
Lapisan peta panas MapAtlas menggunakan WebGL dan merender dengan cepat, tetapi pipeline data yang memberinya makan dapat menjadi hambatan dalam skala.
Preaggregasi di server untuk dataset yang sangat besar. Jika Anda memiliki jutaan ping GPS, jangan mengirimkan semuanya ke browser. Jalankan agregasi spasial sisi server (kisi heksagonal H3, quadtree, atau pembulatan kisi sederhana) yang mengurangi 1 juta titik mentah Anda menjadi 10.000 sel kisi dengan bidang count dan weight. Peta panas akan terlihat identik bagi pengguna dan akan dimuat dalam sebagian kecil waktunya.
Streaming pembaruan secara bertahap. Untuk data langsung (lalu lintas pejalan kaki real-time, penempatan pesanan langsung), gunakan setData dengan jendela bergulir poin terbaru daripada mengumpulkan objek GeoJSON yang terus bertambah. Jaga sumber pada jumlah titik maksimum tetap dan lepaskan catatan lama.
Gunakan maxzoom pada sumber. Menambahkan maxzoom: 14 ke panggilan addSource Anda memberitahu SDK untuk berhenti meminta data ubin di atas zoom 14. Untuk peta panas ini jarang penting karena lapisan peta panas membaca sumber GeoJSON datar tunggal daripada data ubin, tetapi ini mencegah pemrosesan ulang yang tidak perlu pada level zoom tinggi.
Kurangi kompleksitas properti cat. Setiap stop interpolate tambahan dalam ekspresi cat menambah biaya evaluasi GPU per frame. Untuk aplikasi yang menargetkan seluler, sederhanakan gradien warna menjadi tiga atau empat stop dan lepaskan penskalaan radius/intensitas yang terkait zoom pada tampilan prioritas rendah.
Peta inisialisasi malas. Bungkus seluruh inisialisasi peta dalam callback IntersectionObserver sehingga hanya berjalan ketika kontainer peta bergulir ke dalam tampilan. Ini menunda bundel SDK dari pemuatan halaman awal dan sangat berharga pada halaman pemasaran di mana peta berada di bawah lipatan.
Untuk menyelam lebih dalam ke pola kinerja peta, termasuk pemuatan malas dan pengelompokan, daftar periksa produksi dalam Cara Menambahkan Peta Interaktif ke Situs Web Anda mencakup daftar lengkap.
Integrasi React
Membungkus peta panas dalam komponen React mengikuti pola yang sama seperti peta MapAtlas apa pun: inisialisasi di useEffect, paparkan status untuk slider dan filter melalui useState, dan bersihkan saat unmount.
import { useEffect, useRef, useState } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
export function DeliveryHeatmap({ geojson, apiKey }) {
const containerRef = useRef(null);
const mapRef = useRef(null);
const [radius, setRadius] = useState(30);
useEffect(() => {
const map = new mapmetricsgl.Map({
container: containerRef.current,
style: `https://tiles.mapatlas.eu/styles/dark/style.json?key=${apiKey}`,
center: [4.9041, 52.3676],
zoom: 11,
});
mapRef.current = map;
map.on('load', () => {
map.addSource('orders', { type: 'geojson', data: geojson });
map.addLayer({
id: 'order-heatmap',
type: 'heatmap',
source: 'orders',
paint: {
'heatmap-radius': radius,
'heatmap-opacity': 0.9,
},
});
});
return () => map.remove();
}, [apiKey]);
// Update radius without remounting the map
useEffect(() => {
const map = mapRef.current;
if (!map || !map.getLayer('order-heatmap')) return;
map.setPaintProperty('order-heatmap', 'heatmap-radius', radius);
}, [radius]);
return (
<div>
<div style={{ padding: '8px 0' }}>
<label>
Radius: {radius}px
<input
type="range" min={5} max={80} value={radius}
onChange={e => setRadius(Number(e.target.value))}
style={{ marginLeft: 8, width: 160 }}
/>
</label>
</div>
<div ref={containerRef} style={{ width: '100%', height: '600px' }} />
</div>
);
}
Di Next.js, impor komponen ini dengan dynamic(() => import('./DeliveryHeatmap'), { ssr: false }) untuk menghindari kesalahan rendering sisi server dari SDK yang hanya browser.
Apa yang Harus Dibangun Selanjutnya
Anda sekarang memiliki peta panas interaktif yang berfungsi dengan data berbobot, gradien warna kustom, slider radius, dan intensitas yang terkait zoom. Ini adalah tempat untuk membawanya:
- Overlay lapisan routing di atas peta panas untuk menampilkan rute pengiriman yang direncanakan terhadap permukaan permintaan. Tutorial Route Optimization API memandu implementasi lengkap.
- Tambahkan animasi waktu: siklus melalui snapshot per jam dengan loop
setIntervalyang memanggilsetDatapada sumber. Ini mengubah peta kepadatan statis menjadi time-lapse tentang bagaimana permintaan bergerak sepanjang hari. - Gabungkan dengan data harga properti untuk menunjukkan gradien harga menurut lingkungan. Tutorial Real Estate Property Map mencakup pola data berbobot untuk platform properti.
- Periksa halaman harga MapAtlas untuk menemukan rencana yang tepat untuk lalu lintas produksi Anda.
Referensi SDK lengkap dan contoh tambahan tersedia di docs.mapatlas.xyz.
Pertanyaan yang Sering Diajukan
Apa perbedaan antara peta panas dan peta choropleth?
Peta panas memvisualisasikan kepadatan titik dengan memadukan poin terdekat menjadi gradien warna berkelanjutan, ideal untuk data koordinat mentah seperti ping GPS atau lokasi acara. Peta choropleth mewarnai area geografis yang telah ditentukan sebelumnya (negara, kode pos, tract sensus) menurut nilai statistik. Gunakan peta panas ketika Anda memiliki banyak poin individual; gunakan choropleth ketika data Anda sudah dikumpulkan menurut wilayah.
Berapa banyak titik data yang dapat ditangani peta panas JavaScript?
Lapisan peta panas MapAtlas merender pada GPU melalui WebGL, jadi menangani puluhan ribu poin tanpa penurunan frame pada level zoom normal. Di atas kira-kira 500.000 poin, preaggregasi data Anda sisi server menjadi kisi resolusi lebih rendah dan beralih ke lapisan fill-extrusion atau circle GeoJSON memberikan kinerja lebih baik pada perangkat kelas bawah.
Dapatkah saya menggunakan peta panas MapAtlas secara gratis?
Ya. MapAtlas memiliki tingkat gratis yang mencakup rendering ubin peta, dukungan lapisan GeoJSON, dan lapisan peta panas. Rencana gratis mencakup pengembangan dan penggunaan produksi volume rendah. Lihat mapatlas.eu/pricing untuk detail rencana lengkap.
Apakah peta panas bekerja di browser seluler?
Ya. SDK MapAtlas menggunakan WebGL untuk rendering, yang didukung di semua browser seluler modern termasuk Safari di iOS dan Chrome di Android. Untuk dataset sangat besar di hardware seluler kelas bawah, mengurangi jumlah titik atau meningkatkan radius peta panas menjaga frame rate tetap halus.
Bacaan terkait:

