Petak Protomaps Basemap

Seluruh Protomaps Basemap, zoom 0 hingga 15, disajikan sebagai satu arsip PMTiles melalui HTTP biasa. Arahkan klien PMTiles mana pun ke URL ini dan peta langsung berfungsi.

https://tiles.jasontally.com/basemap.pmtiles

Petak OpenStreetMap diblokir, atau muncul 403 dari tile.openstreetmap.org? Mulai di sini.

Coba

Arsip yang sama dalam tiga gaya. Saat Anda mengganti gaya, petak yang sudah dimuat tetap ada sehingga perubahannya seketika.

z0

Buat sendiri

Ubah warna atau matikan lapisan, dan peta langsung diperbarui. Setelah itu salin JSON gaya, yaitu gaya MapLibre biasa yang dapat Anda host sendiri. Gaya ini mengarah ke petak di sini, sehingga tetap berfungsi di mana pun Anda meletakkannya.

Gunakan

Arsip ini mendukung permintaan rentang HTTP, sehingga setiap klien PMTiles dapat membacanya.

Satu. Tampilkan peta di halaman

Salin berkas ini. Ini adalah contoh lengkap: tiga tag, satu URL gaya, satu peta. Kedua pustaka dipatok versinya dan berlisensi BSD-3-Clause, serta berkas yang sama juga disajikan dari host ini jika Anda memilih tidak menggunakan CDN.

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Basemap</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css">
  <script src="https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/pmtiles@3.2.1/dist/pmtiles.js"></script>
  <style>html, body, #map { margin: 0; height: 100%; }</style>
</head>
<body>
  <div id="map"></div>
  <script>
    // Teach MapLibre how to read a PMTiles archive.
    const protocol = new pmtiles.Protocol();
    maplibregl.addProtocol("pmtiles", protocol.tile);

    new maplibregl.Map({
      container: "map",
      style: "https://tiles.jasontally.com/styles/light.json",
      center: [2.35, 48.85],   // Paris
      zoom: 4
    });
  </script>
</body>
</html>

Dua. Ganti petak pada gaya yang sudah Anda miliki

Setiap gaya MapLibre membaca petaknya dari sebuah sumber. Untuk menggunakan petak ini, ubah satu nilai url tersebut. Bagian lain di dalam gaya tidak berubah.

  "sources": {
    "protomaps": {
      "type": "vector",
-     "url": "pmtiles://https://demo-bucket.protomaps.com/v4.pmtiles",
+     "url": "pmtiles://https://tiles.jasontally.com/basemap.pmtiles",
      "attribution": "<a href=\"https://www.openstreetmap.org/copyright\">&copy; OpenStreetMap contributors</a>"
    }
  }

Atau lakukan lewat kode, yang berguna jika gaya berasal dari server yang tidak Anda kendalikan:

// Rewrite every PMTiles source in a style to point at these tiles.
const style = await (await fetch("https://your-server/style.json")).json();

for (const source of Object.values(style.sources)) {
  if (source.url?.startsWith("pmtiles://")) {
    source.url = "pmtiles://https://tiles.jasontally.com/basemap.pmtiles";
  }
}

new maplibregl.Map({ container: "map", style, center: [2.35, 48.85], zoom: 4 });

Tiga. Tempat menyimpan gaya yang Anda buat

Tombol JSON Gaya pada pembuat di atas membuka gaya yang sedang digambar peta ini, termasuk suntingan Anda, dan dialognya memiliki tombol salin. Ada dua cara untuk menggunakan hasilnya, dan keduanya adalah halaman web biasa.

Simpan sebagai berkas di samping halaman Anda lalu arahkan style ke berkas tersebut, sama seperti cara penggunaan ketiga gaya di host ini. Pilih cara ini jika gaya tersebut milik Anda dan berubah mengikuti situs Anda:

// Save the copied JSON as my-basemap.json beside this file.
new maplibregl.Map({
  container: "map",
  style: "my-basemap.json",           // relative, same origin
  center: [2.35, 48.85],
  zoom: 4
});

Atau simpan langsung di dalam HTML, sehingga hanya ada satu berkas untuk dipindahkan dan tidak ada yang perlu di-host terpisah. Gayanya sama, hanya tempat penyimpanannya yang berbeda:

// The copied JSON, pasted straight into the page.
const myStyle = {
  "version": 8,
  "name": "Protomaps Basemap — custom",
  "glyphs": "https://tiles.jasontally.com/font/{fontstack}/{range}.pbf",
  "sprite": "https://tiles.jasontally.com/sprites/v4/light",
  "sources": { /* ... as copied ... */ },
  "layers":  [ /* ... as copied ... */ ]
};

new maplibregl.Map({ container: "map", style: myStyle, zoom: 4 });

Biarkan baris glyphs dan sprite apa adanya. Keduanya menggambar label dan ikon serta mengarah ke host ini, sehingga gaya yang Anda tempelkan ke halaman sendiri tetap berfungsi dari mana pun Anda menyajikannya. Arahkan keduanya ke protomaps.github.io/basemaps-assets jika Anda tidak ingin bergantung pada host ini sama sekali.

Satu hal yang perlu diperiksa sebelum mengganti. Arsip ini menggunakan skema Protomaps v3. Gaya yang ditulis untuk skema lain akan dimuat tetapi tidak menggambar apa pun karena nama lapisan sumbernya tidak cocok. Kesembilan nama lapisan dicantumkan di bawah, beserta gaya v3 siap pakai yang dapat Anda salin.

Empat. Font, sprite, dan pustaka

Sebuah peta terdiri atas petak, URL glyphs untuk teks, URL sprite opsional untuk ikon, dan pustaka untuk menggambar semuanya. Semuanya tersedia di sini pada jalur yang diharapkan masing-masing komponen, sehingga peta dapat dimuat dari satu nama host jika Anda menginginkannya.

KomponenURL di siniLisensi

Berkas MapLibre dan PMTiles tersedia di jsDelivr dan di sini. Kedua URL dapat digunakan.

Baris terakhir tidak digunakan oleh halaman ini. Itu adalah perender vektor Leaflet, yang disediakan di sini agar penggantiannya hanya memerlukan satu tag skrip. Leaflet sendiri tetap dimuat dari CDN miliknya.

Dua tumpukan font, Noto Sans Regular dan Noto Sans Medium, dibagi ke dalam 256 rentang yang diminta MapLibre, masing-masing 256 titik kode. Seluruh 256 rentang dipublikasikan, bukan hanya aksara Latin: Protomaps memberi label fitur dengan nama lokalnya, sehingga Tokyo atau Kairo memerlukan rentang hingga puluhan ribu. Jika hanya rentang bahasa Inggris yang dipublikasikan, label tersebut akan hilang tanpa pesan kesalahan.

Lima lembar sprite, satu untuk setiap varian hulu, pada ukuran 1x dan 2x. Gaya di bawah mengambil ikon dari sana. Jika Anda menginginkan titik kota, perisai jalan raya, atau ikon tempat pada gaya buatan sendiri, arahkan sprite ke varian yang sesuai. Nama ikon dalam satu lembar tercantum di dalam light.json miliknya.

Apa yang digambar peta, dan asal setiap elemennya

Setiap lapisan berasal dari salah satu dari sembilan lapisan sumber di dalam arsip ini, sehingga tidak ada yang memerlukan arsip kedua. Dua di antaranya perlu disebutkan secara khusus karena tampak seperti data yang hilang padahal bukan:

LapisanBerasal dariAda di build ini?
Bentuk, jalan, bangunan, perairan, daratanearth, landcover, landuse, water, roads, buildingsya
Nama tempat, jalan, dan perairankolom name pada lapisan yang samaya
Ikon tempat menarik, titik kotapois.kind, places, ditambah spriteya
Perisai ruteroads.shield_texttidak. Build yang sedang disajikan belum memiliki kolom tersebut
Nomor rumahbuildings.kind=address dan buildings.addr_housenumbertidak, dengan alasan yang sama

Tidak ada arsip alamat terpisah dan tidak ada lapisan alamat untuk diambil. Proyek hulu menempatkan titik alamat di dalam lapisan buildings sebagai fitur dengan kind=address dan addr_housenumber. Kolom tersebut hadir pada build Protomaps yang lebih baru daripada yang disajikan peta ini sekarang, sehingga lapisan nomor rumah sudah disiapkan dan akan aktif sendiri saat pembaruan bulanan berikutnya membawanya. Hal yang sama berlaku untuk teks perisai rute: build saat ini memuat shield_text_length, yang berisi jumlah karakter nomor rute dan bukan teksnya, sehingga perisai yang digambar darinya hanya akan menjadi bentuk kosong di setiap jalan tol.

Menulis lapisan sendiri dan mewarnainya

Sebuah lapisan terdiri atas filter, tingkat zoom, bentuk, dan warna. Dua hal pada filter sering menjebak pengguna dan keduanya gagal tanpa pesan kesalahan:

Berikut contoh jalan, namanya, serta sakelar untuk mematikan garisnya:

{
  "id": "road-major",
  "type": "line",
  "source": "protomaps",
  "source-layer": "roads",            // one of the nine
  "minzoom": 4,                                  // not drawn below this
  "filter": ["==", ["get", "kind"], "major_road"],
  "layout": {
    "line-cap": "round",
    "visibility": "visible"          // "none" to hide it
  },
  "paint": {
    "line-color": "#f7c44d",          // any CSS colour
    "line-width": ["interpolate", ["linear"], ["zoom"], 4, 1.7, 12, 6]
  }
}

Nama adalah lapisan simbol yang membaca kolom name, dengan halo atau tanpa latar di belakangnya. Glyph yang hilang tidak memunculkan kesalahan, sehingga tumpukan font yang Anda minta harus salah satu dari dua yang ada di host ini:

{
  "id": "road-label-major",
  "type": "symbol",
  "source": "protomaps",
  "source-layer": "roads",
  "minzoom": 11,
  "layout": {
    "text-field": ["coalesce", ["get", "name:en"], ["get", "name"]],
    "text-font": ["Noto Sans Medium"],  // or Noto Sans Regular
    "text-size": 10,
    "symbol-placement": "line"       // follow the road
  },
  "paint": {
    "text-color": "#2b2a26",
    "text-halo-color": "#ffffff",
    "text-halo-width": 1.1
  }
}

Lapisan yang tidak menggambar apa pun bukanlah kesalahan, dan MapLibre tidak akan memberi tahu pemeriksaan mana yang gagal. Jika lapisan Anda kosong, periksa dengan urutan ini: nama kolom, minzoom lapisan, tumpukan font, lalu nama ikon terhadap light.json milik lembar sprite tersebut.

Jika Anda memiliki gaya yang mengarahkan glyph ke demotiles.maplibre.org, mengganti nama host tersebut sudah cukup. Jalurnya sengaja dibuat sama.

"glyphs": "https://tiles.jasontally.com/font/{fontstack}/{range}.pbf",
"sprite": "https://tiles.jasontally.com/sprites/v4/light"

// before, in a style you already have
- "glyphs": "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf",
+ "glyphs": "https://tiles.jasontally.com/font/{fontstack}/{range}.pbf",

Jika sebuah gaya meminta tumpukan font selain dua nama di atas, tidak ada teks yang akan digambar untuk lapisan tersebut. Gaya bawaan Protomaps menggunakan Noto Sans Medium untuk teks tebal; tidak ada Noto Sans Bold di kumpulan ini, itulah sebabnya gaya yang memintanya akan kehilangan seluruh label tanpa pesan kesalahan.

Host mana yang lebih cepat, dan apa yang diputuskan. Diukur secara langsung, bukan diasumsikan: permintaan berselang-seling, satu per satu, pada satu koneksi, tiga sampel pertama dibuang, dan waktu hingga byte pertama dipisahkan dari waktu transfer. Dalam pengujian tersebut, CDN merespons 10 hingga 45 md lebih cepat untuk setiap berkas ini, melampaui aturan 15% dengan selisih yang jelas pada sampel. Karena alasan itulah pustaka dimuat dari jsDelivr.

Font dan sprite disajikan dari sini meskipun pengukuran yang sama menunjukkan bahwa CDN merespons sekitar 10 md lebih cepat. Ini adalah keputusan teknis, bukan soal hasil ukur. Peta yang berasal dari satu nama host tidak ikut rusak saat host pihak lain bermasalah, sedangkan server glyph yang mati akan membuat peta kehilangan seluruh label. Jika Anda lebih memilih selisih 10 md tersebut, arahkan glyphs ke protomaps.github.io/basemaps-assets/fonts dan jalur yang sama langsung berfungsi. Angka di atas berasal dari satu pengujian di satu kota, dan pengujian ulang dapat dijalankan dengan satu perintah.

Lima. Tentang Leaflet

L.tileLayer pada Leaflet menggambar gambar raster; petak di sini adalah petak vektor. Peta Leaflet tetap dapat menggunakannya, dan kedua cara di bawah tetap mempertahankan penanda, popup, serta kontrol Anda. Kedua cara penggantian tersebut ada di bagian Beralih dari petak OpenStreetMap.

Enam. Membaca arsip dengan pustaka PMTiles

Tanpa peta, hanya data. Berguna untuk skrip, pengujian, dan apa pun yang bukan tampilan gambar.

import { PMTiles, FetchSource } from "pmtiles";

const archive = new PMTiles(new FetchSource("https://tiles.jasontally.com/basemap.pmtiles"));

const header = await archive.getHeader();
console.log(header.minZoom, header.maxZoom);        // 0 15
console.log(header.numAddressedTiles);              // 1431655765

const metadata = await archive.getMetadata();
console.log(metadata.name);                          // "Protomaps Basemap"

const tile = await archive.getZxy(3, 4, 2);          // z, x, y
console.log(tile.data.byteLength);

Perhatikan kedua kelas tersebut. FetchSource adalah pembaca byte melalui HTTP, sedangkan PMTiles adalah pembaca di atasnya yang memahami format arsip. FileSource adalah padanan berkas lokal untuk FetchSource; jika diberi string URL, kelas itu tidak akan berfungsi.

Arsip ini adalah cuplikan berkala, bukan umpan langsung. Bagian Seberapa baru data ini? menjelaskan jadwalnya.

Beralih dari petak OpenStreetMap

Pemblokiran akibat kebijakan penggunaan petak, galat 403, dan cara mengatasinya. Tanpa kunci, tanpa kuota.

Mengapa peta menampilkan gambar pemblokiran

App is not following the tile usage policy of OpenStreetMap’s volunteer-run servers

General block: app is not following the tile usage policy of openstreetmap volunteer-run servers

403 Forbidden — tile.openstreetmap.org

Server petak sengaja mengirimkan gambar tersebut sebagai pengganti peta berdasarkan kebijakan penggunaan petak. Ini bukan gangguan teknis, dan memperbaiki URL tidak akan menghilangkannya.

Hal yang biasanya dicoba orang pertama kali:

Kantor, sekolah, VPN, dan jaringan seluler berbagi alamat IP yang sama, dan pemblokiran diterapkan pada alamat maupun aplikasi. Dari sisi Anda, tidak mungkin mengetahui mana yang sedang menimpa Anda.

Jadi berhentilah meminta petak ke server tersebut. Ada tiga cara untuk beralih darinya.

Tetap gunakan Leaflet

protomaps-leaflet menggambar petak vektor di dalam Leaflet. Pustaka ini membaca arsip secara langsung dan menambahkan dirinya sebagai lapisan biasa, sehingga penanda, popup, GeoJSON, dan kontrol tetap berada di tempatnya. Salinannya tersedia di sini dan telah diuji terhadap arsip ini: https://tiles.jasontally.com/vendor/protomaps-leaflet.js.

Sebelum:

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

<script>
  const map = L.map("map").setView([48.85, 2.35], 12);

  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
    maxZoom: 19,
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  }).addTo(map);
</script>

Sesudah:

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
+ <script src="https://tiles.jasontally.com/vendor/protomaps-leaflet.js"></script>

<script>
  const map = L.map("map").setView([48.85, 2.35], 12);

-  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { ... }).addTo(map);
+  protomapsL.leafletLayer({
+    url: "https://tiles.jasontally.com/basemap.pmtiles",
+    flavor: "light",
+    lang: "en"
+  }).addTo(map);
</script>

protomaps-leaflet berada dalam mode pemeliharaan di proyek hulunya: hanya perbaikan bug, tanpa fitur baru. Cocok untuk aplikasi Leaflet yang sudah ada. Proyek baru sebaiknya dimulai dengan MapLibre GL.

Tetap gunakan Leaflet, render dengan MapLibre

@maplibre/maplibre-gl-leaflet menempatkan peta MapLibre di dalam panel petak Leaflet. Gunakan cara ini jika Anda menginginkan salah satu gaya di atas, atau medan dan bayangan bukit, di dalam aplikasi yang tetap menggunakan Leaflet.

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://tiles.jasontally.com/vendor/maplibre-gl.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://tiles.jasontally.com/vendor/maplibre-gl.js"></script>
<script src="https://tiles.jasontally.com/vendor/pmtiles.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@maplibre/maplibre-gl-leaflet@0.1.4/dist/leaflet-maplibre-gl.js"></script>

<script>
  // The style's source is pmtiles://, so MapLibre needs the protocol first.
  maplibregl.addProtocol("pmtiles", new pmtiles.Protocol().tile);

  const map = L.map("map", { minZoom: 1 }).setView([48.85, 2.35], 12);

  const gl = L.maplibreGL({
    style: "https://tiles.jasontally.com/styles/light.json"
  }).addTo(map);

  // gl.getMaplibreMap() is the MapLibre map, for sources and layers.
</script>

Beralih ke MapLibre GL

Satu pustaka, tanpa adaptor, dan seluruh gaya di atas langsung berfungsi apa adanya. Contoh halaman lengkapnya ada di Satu. Tampilkan peta di halaman. Perubahannya sebagian besar hanyalah membalik urutan koordinat:

LeafletMapLibre GL
L.map("map").setView([lat, lng], z)new maplibregl.Map({ container: "map", center: [lng, lat], zoom: z })
L.tileLayer(url).addTo(map)gaya dengan sumber vektor; lihat di atas
L.marker([lat, lng]).bindPopup(html)new maplibregl.Marker().setLngLat([lng, lat]).setPopup(new maplibregl.Popup().setHTML(html))
L.geoJSON(data)addSource(id, { type: "geojson", data }), lalu addLayer
L.control.scale()new maplibregl.ScaleControl()
map.invalidateSize()map.resize()

setView([lat, lng]) menerima garis lintang terlebih dahulu; setiap pemanggilan MapLibre menerima [lng, lat]. Peta yang muncul di belahan bumi yang salah disebabkan oleh urutan ini, bukan oleh petaknya. Sumber dan lapisan yang ditambahkan sebelum gaya selesai dimuat akan dibuang tanpa pesan kesalahan, jadi tambahkan di dalam map.on("load", …).

“archive contains MVT vector tiles, but leafletRasterLayer is for displaying raster tiles”

Pesan itu berasal dari pmtiles.leafletRasterLayer, yang menggambar PMTiles raster sebagai gambar. Petak di sini adalah petak vektor sehingga ditolak oleh fungsi tersebut. Tidak ada opsi yang dapat mengubahnya, dan tidak tersedia salinan raster di sini. Gunakan salah satu opsi di atas.

“download.openstreetmap.fr returned 403”

Server tersebut adalah cermin ekstrak dan replikasi, bukan server petak. Pada Oktober 2026 server itu memblokir sejumlah alamat setelah terjadi pengunduhan berlebihan, dan pengelolanya menyatakan akan memulihkan akses kasus demi kasus. Tidak ada layanan di halaman ini yang memerlukannya: arsip ini berasal dari rilis Protomaps, sehingga Anda tidak perlu merakit .osm.pbf sendiri. Jika Anda memang mengambil data OSM, ambil ekstrak berkala alih-alih aliran pembaruan per menit.

Gaya

Petak yang sama, warna yang berbeda. Pilih salah satu, salin, ubah, dan gunakan sesuka Anda.

GayaTampilanBerkas

Isi di dalam petak

Dibaca langsung dari metadata arsip saat halaman dimuat. Ini adalah nama lapisan yang harus digunakan oleh sebuah gaya.

Lapisan sumberZoomKolom
memuat…

Batasan layanan ini

Jawaban lugas agar tidak ada hal yang mengejutkan Anda di kemudian hari.

Seberapa baru data ini?

Petak ini adalah salinan dari Protomaps Basemap yang dibangun ulang sebulan sekali.

JSON Gaya

open raw