Hướng dẫn sử dụng và khai thác bản đồ 2D/3D

Bản đồ nền vector toàn Việt Nam, địa hình, ảnh vệ tinh, tìm kiếm địa chỉ, tìm đường và lớp dữ liệu riêng — tất cả sau một địa chỉ. Trang này vừa là bản đồ dùng thử, vừa là tài liệu tích hợp.

1. Bản đồ

Nền và chế độ xem
Tìm kiếm địa chỉ
    Tìm đường

      Dữ liệu nghiệp vụ

      Dữ liệu mẫu giả lập quanh khuôn viên ở Cầu Giấy.

      Đang tải bản đồ…
      Kinh độ, vĩ độ – Zoom – Nghiêng – Xoay – Ảnh tĩnh của khung nhìn này
      Hai cách xem 3D. Nút 3D dựng khối toà nhà theo chiều cao có sẵn trong dữ liệu (render_height) rồi nghiêng camera. “Địa hình nổi 3D” dựng mặt đất theo độ cao thật — thấy rõ ở vùng núi như Sa Pa; ở đồng bằng gần như phẳng.

      2. Thao tác trên bản đồ

      Chuột và bàn phím

      Kéo chuột tráiDi chuyển
      Cuộn chuộtPhóng to, thu nhỏ
      Nháy đúpPhóng to một mức (giữ Shift để thu nhỏ)
      Shift + kéoVẽ khung để phóng vào vùng chọn
      Kéo chuột phải, hoặc Ctrl + kéoXoay (kéo ngang) và nghiêng (kéo dọc)
      + −Phóng to, thu nhỏ
      ← ↑ → ↓Di chuyển
      Shift + ← →Xoay
      Shift + ↑ ↓Nghiêng
      Bấm một điểmXem thông tin tại điểm

      Màn hình cảm ứng và nút điều khiển

      Kéo một ngónDi chuyển
      Chụm, mở hai ngónThu nhỏ, phóng to
      Xoay hai ngónXoay bản đồ
      Kéo hai ngón lên, xuốngNghiêng
      Nút la bànBấm để quay về hướng Bắc; kéo để xoay
      Nút toàn màn hìnhMở bản đồ kín màn hình
      Thước tỉ lệGóc dưới trái, đơn vị mét

      3. Nhúng vào ứng dụng

      Server kèm sẵn MapLibre GL JS và Leaflet, nên trang nội bộ không cần tải gì từ Internet. Trong các ví dụ, http://MAY-CHU:3650 là địa chỉ gốc của máy chủ bản đồ (trang này tự thay bằng địa chỉ bạn đang mở).

      Bản đồ 2D

      <link rel="stylesheet" href="http://MAY-CHU:3650/maplibre-gl.css">
      <script src="http://MAY-CHU:3650/maplibre-gl.js"></script>
      <div id="map" style="height:480px"></div>
      <script>
        const map = new maplibregl.Map({
          container: 'map',
          style: 'http://MAY-CHU:3650/api/maps/xanh-la-toi/style.json',
          center: [105.7816, 21.0436],   // [kinh độ, vĩ độ]
          zoom: 14
        });
        map.addControl(new maplibregl.NavigationControl({ visualizePitch: true }));
      </script>

      3D: toà nhà khối

      Cách nhanh nhất là dùng thẳng style xanh-la-sang-3d hoặc xanh-la-toi-3d rồi đặt pitch: 60. Muốn bật tắt trên style bất kỳ thì tự thêm lớp:

      map.on('style.load', () => {
        // chèn dưới lớp nhãn đầu tiên để chữ không bị khối nhà che
        const firstLabel = map.getStyle().layers.find(l => l.type === 'symbol')?.id;
        // tên nguồn vector của style đang dùng
        const nen = Object.keys(map.getStyle().sources).find(k => map.getStyle().sources[k].type === 'vector');
        map.addLayer({
          id: 'building-3d', type: 'fill-extrusion',
          source: nen, 'source-layer': 'building', minzoom: 13,
          filter: ['!=', ['get', 'hide_3d'], true],
          paint: {
            'fill-extrusion-color': '#2b3644',
            'fill-extrusion-height': ['coalesce', ['get', 'render_height'], 5],
            'fill-extrusion-base': ['coalesce', ['get', 'render_min_height'], 0],
            'fill-extrusion-opacity': 0.85
          }
        }, firstLabel);
        map.easeTo({ pitch: 60, bearing: -20, zoom: 15.5 });
      });

      3D: địa hình nổi và tra độ cao

      Nguồn dùng cho setTerrain phải khai tiles với maxzoom: 12 như dưới đây (mức zoom địa hình phủ kín cả nước), không dùng url tới /data/terrain.json: nếu nguồn khai mức zoom cao hơn mức phủ kín thì ở nơi thiếu tile (rõ nhất là vùng núi như Sa Pa) toà nhà 3D và nhãn sẽ bay lơ lửng hoặc chìm dưới mặt đất. Bóng núi (hillshade) không bị ảnh hưởng.

      map.addSource('dem', {
        type: 'raster-dem', tiles: ['http://MAY-CHU:3650/data/terrain/{z}/{x}/{y}.png'],
        maxzoom: 12,   // zoom phủ kín cả nước; khai cao hơn thì nơi thiếu tile nhà 3D bị bay lơ lửng
        encoding: 'terrarium', tileSize: 256
      });
      map.setTerrain({ source: 'dem', exaggeration: 1.4 });
      
      // độ cao (mét) tại một điểm: /data/terrain/elevation/{zoom}/{kinh độ}/{vĩ độ}
      const r = await fetch('http://MAY-CHU:3650/data/terrain/elevation/11/103.7751/22.3033');
      console.log((await r.json()).elevation);

      Tìm kiếm địa chỉ và tra ngược toạ độ

      const q = encodeURIComponent('Bệnh viện Bạch Mai');
      const places = await (await fetch(
        `http://MAY-CHU:3650/geocode/search?q=${q}&format=jsonv2&limit=5&accept-language=vi`)).json();
      // → [{ display_name, lat, lon, boundingbox, category, type }, …]
      
      const here = await (await fetch(
        'http://MAY-CHU:3650/geocode/reverse?lat=21.0288&lon=105.8525&format=jsonv2&accept-language=vi')).json();
      // → { display_name, address: { road, suburb, city, … } }

      Tìm đường và vùng tới được theo thời gian

      const route = await (await fetch('http://MAY-CHU:3650/route/route', {
        method: 'POST',
        body: JSON.stringify({
          locations: [{ lat: 21.0436, lon: 105.7816 }, { lat: 21.0288, lon: 105.8525 }],
          costing: 'motor_scooter',          // auto | motor_scooter | motorcycle | bicycle | pedestrian | truck
          units: 'kilometers', language: 'vi-VN'
        })
      })).json();
      // route.trip.summary → { length (km), time (giây) }; route.trip.legs[0].shape là polyline độ chính xác 6
      
      const iso = await (await fetch('http://MAY-CHU:3650/route/isochrone', {
        method: 'POST',
        body: JSON.stringify({
          locations: [{ lat: 21.0436, lon: 105.7816 }], costing: 'auto',
          contours: [{ time: 5 }, { time: 10 }, { time: 15 }], polygons: true
        })
      })).json();                             // GeoJSON, đưa thẳng vào map.addSource

      Đơn vị gần nhất theo thời gian đi, hành trình xe, mặt cắt độ cao

      Ba API cùng cổng /route/, hay dùng trong điều hành: ma trận thời gian để chọn đơn vị tới hiện trường nhanh nhất; nắn vết GPS của xe vào lòng đường; mặt cắt độ cao dọc một tuyến.

      // 1. Đơn vị nào tới hiện trường nhanh nhất: n nguồn → 1 đích, kết quả theo thứ tự nguồn
      const m = await (await fetch('http://MAY-CHU:3650/route/sources_to_targets', {
        method: 'POST',
        body: JSON.stringify({
          sources: donVi.map(d => ({ lat: d.lat, lon: d.lon })),     // các trạm, xe đang rảnh
          targets: [{ lat: 21.0288, lon: 105.8525 }],                // hiện trường
          costing: 'auto'
        })
      })).json();
      const xepHang = m.sources_to_targets.map((h, i) => ({ ...donVi[i], giay: h[0].time, km: h[0].distance }))
                       .sort((a, b) => a.giay - b.giay);            // xepHang[0] là đơn vị tới nhanh nhất
      
      // 2. Nắn vết GPS của xe vào đường (map matching) rồi vẽ lại tuyến đã đi
      const tr = await (await fetch('http://MAY-CHU:3650/route/trace_route', {
        method: 'POST',
        body: JSON.stringify({ shape: vetGps, costing: 'auto', shape_match: 'map_snap' }) // vetGps: [{lat, lon, time}]
      })).json();                              // tr.trip.legs[0].shape: polyline độ chính xác 6, bám lòng đường
      
      // 3. Mặt cắt độ cao dọc tuyến, mỗi 50 m một mẫu
      const h = await (await fetch('http://MAY-CHU:3650/route/height', {
        method: 'POST',
        body: JSON.stringify({ encoded_polyline: route.trip.legs[0].shape, resample_distance: 50 })
      })).json();                              // h.height: [m, m, …] cùng thứ tự với h.shape

      Lớp dữ liệu riêng

      Mỗi bảng dữ liệu riêng tự thành vector tile (cho lớp lớn, vẽ nhanh) và thành GeoJSON (cho gom cụm, bản đồ nhiệt, truy vấn).

      // vector tile: mỗi bảng một nguồn, tên lớp trong tile = tên bảng
      map.addSource('khu-vuc', { type: 'vector', tiles: ['http://MAY-CHU:3650/tiles/khu_vuc/{z}/{x}/{y}'], maxzoom: 16 });
      map.addLayer({ id: 'khu-vuc', type: 'line', source: 'khu-vuc', 'source-layer': 'khu_vuc',
                     paint: { 'line-color': '#0ea5e9', 'line-width': 2 } });
      
      // GeoJSON có lọc: camera đang hoạt động
      map.addSource('thiet-bi', { type: 'geojson', cluster: true,
        data: "http://MAY-CHU:3650/features/collections/ioc.thiet_bi/items.json?limit=5000&filter=loai='camera' AND trang_thai='hoat_dong'" });
      
      // truy vấn không gian: thiết bị trong bán kính 100 m
      const near = await (await fetch(
        'http://MAY-CHU:3650/features/functions/thiet_bi_quanh/items.json?lon=105.7816&lat=21.0436&ban_kinh_m=100')).json();

      Icon dùng chung

      Bộ icon dùng chung có icon POI (poi-hospital, poi-school…) và icon nghiệp vụ (camera, cảm biến, sự cố, báo cháy, SOS…); danh sách tên ở /styles/xanh-la-sang-3d/sprite.json. Nạp vào style bất kỳ dưới một tiền tố tự đặt rồi gọi theo tên có tiền tố đó:

      map.addSprite('bt', 'http://MAY-CHU:3650/styles/xanh-la-sang-3d/sprite');
      map.addLayer({ id: 'benh-vien', type: 'symbol', source: 'diem',
                     layout: { 'icon-image': 'bt:poi-hospital', 'icon-allow-overlap': true } });

      Leaflet, QGIS và phần mềm chỉ đọc ảnh

      L.tileLayer('http://MAY-CHU:3650/styles/xanh-la-sang/{z}/{x}/{y}.png', { maxZoom: 20 }).addTo(map);
      Kết nối trong QGISĐịa chỉ nhập vào
      Vector Tileshttp://MAY-CHU:3650/data/openmaptiles/{z}/{x}/{y}.pbf, zoom 0–14, style http://MAY-CHU:3650/styles/xanh-la-sang/style.json
      XYZ Tileshttp://MAY-CHU:3650/styles/xanh-la-sang/{z}/{x}/{y}.png
      WMTShttp://MAY-CHU:3650/styles/xanh-la-sang/wmts.xml
      OGC API Features (WFS3)http://MAY-CHU:3650/features

      Các địa chỉ này đã kiểm bằng HTTP; chưa thử kết nối trực tiếp trong QGIS.

      Ảnh tĩnh cho báo cáo, email, thông báo

      Ảnh tĩnh nền sáng có ghim đỏ
      Có ghim: …/static/105.8525,21.0288,15.5/700x420.png?marker=105.8525,21.0288|marker-red.png
      Ảnh tĩnh nền tối nhìn nghiêng
      Xoay −20°, nghiêng 60°: /styles/xanh-la-toi/static/105.8525,21.0288,15.6@-20,60/700x420.png
      Ảnh tĩnh có tuyến đường màu đỏ
      Vẽ tuyến, tự khớp khung: …/static/auto/700x420.png?path=…&stroke=red&width=4

      Ghim có sẵn: marker-red.png, marker-blue.png, marker-green.png, marker-orange.png, marker-gray.png. Nhiều ghim thì lặp tham số marker.

      Ứng dụng di động (Android, iOS, Flutter, React Native)

      Ứng dụng di động dùng bộ thư viện MapLibre Native và đọc đúng địa chỉ style như bản web: chỉ cần đưa địa chỉ style.json cho thư viện, tile, font và icon nó tự tải theo. Tìm kiếm địa chỉ, tìm đường và dữ liệu riêng là API HTTP thường, gọi bằng thư viện mạng của nền tảng với đúng địa chỉ và tham số ở các ví dụ phía trên.

      Nền tảngThư viện
      Android (Kotlin/Java)org.maplibre.gl:android-sdk
      iOS (Swift)MapLibre Native cho iOS (Swift Package maplibre-gl-native-distribution)
      Fluttermaplibre_gl
      React Native@maplibre/maplibre-react-native
      // Android (Kotlin) — trong Activity, layout có <org.maplibre.android.maps.MapView android:id="@+id/mapView" …/>
      MapLibre.getInstance(this)
      setContentView(R.layout.activity_main)
      mapView = findViewById(R.id.mapView)
      mapView.onCreate(savedInstanceState)
      mapView.getMapAsync { map ->
        map.setStyle("http://MAY-CHU:3650/api/maps/xanh-la-sang/style.json")
        map.cameraPosition = CameraPosition.Builder()
          .target(LatLng(21.0436, 105.7816))   // (vĩ độ, kinh độ) — ngược thứ tự với bản web
          .zoom(14.0).build()
      }
      // nhớ chuyển tiếp onStart/onResume/onPause/onStop/onDestroy/onLowMemory của Activity cho mapView
      // iOS (Swift)
      import MapLibre
      
      let mapView = MLNMapView(frame: view.bounds,
        styleURL: URL(string: "http://MAY-CHU:3650/api/maps/xanh-la-sang/style.json"))
      mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
      mapView.setCenter(CLLocationCoordinate2D(latitude: 21.0436, longitude: 105.7816), zoomLevel: 14, animated: false)
      view.addSubview(mapView)
      // Flutter (Dart)
      MapLibreMap(
        styleString: 'http://MAY-CHU:3650/api/maps/xanh-la-sang/style.json',
        initialCameraPosition: const CameraPosition(target: LatLng(21.0436, 105.7816), zoom: 14),
      )
      
      // React Native — tên thuộc tính style khác nhau giữa các bản (mapStyle hoặc styleURL), xem tài liệu bản đang dùng
      <MapView style={{ flex: 1 }} mapStyle="http://MAY-CHU:3650/api/maps/xanh-la-sang/style.json">
        <Camera centerCoordinate={[105.7816, 21.0436]} zoomLevel={14} />   {/* [kinh độ, vĩ độ] */}
      </MapView>
      Việc cần lưu ýCách làm
      Địa chỉ http:// bị chặnAndroid và iOS mặc định chỉ cho gọi HTTPS. Nên gọi qua tên miền HTTPS của hệ thống. Khi thử trong mạng nội bộ bằng http://: Android thêm android:usesCleartextTraffic="true" vào thẻ application (hoặc khai Network Security Config cho riêng máy chủ này); iOS thêm ngoại lệ App Transport Security cho máy chủ trong Info.plist.
      Quyền mạngAndroid cần android.permission.INTERNET. Hiện vị trí người dùng thì xin thêm quyền vị trí của nền tảng.
      Thứ tự toạ độAndroid, iOS, Flutter dùng (vĩ độ, kinh độ). Web, React Native và GeoJSON dùng [kinh độ, vĩ độ]. API tìm đường và tìm kiếm ghi rõ tên trường lat, lon.
      Nền sáng, nền tốiĐổi địa chỉ style giữa xanh-la-sang và xanh-la-toi theo chế độ giao diện của máy.
      3DDùng style xanh-la-sang-3d hoặc xanh-la-toi-3d rồi nghiêng camera (tilt/pitch 60). Địa hình nổi 3D (setTerrain) chỉ có ở bản web; trên di động dùng bóng núi (lớp hillshade với nguồn raster-dem khai như mục “địa hình nổi”) và API tra độ cao.
      Ngôn ngữ nhãnĐặt lại thuộc tính text-field của các lớp nhãn sang name:vi, name:zh hoặc name:en, dự phòng về name khi thiếu.
      Vẽ tuyến đườngKết quả tìm đường trả shape là polyline mã hoá độ chính xác 6: giải mã với hệ số 1e6 (không phải 1e5 như mặc định của nhiều thư viện) rồi đưa vào một nguồn GeoJSON.
      IconIcon POI và icon nghiệp vụ nằm sẵn trong sprite của style, gọi theo tên trong icon-image; icon riêng của ứng dụng thì thêm bằng hàm thêm ảnh của thư viện.
      Dùng khi mất mạngThư viện có sẵn bộ tải vùng ngoại tuyến (offline region): chọn khung và dải zoom, thư viện tải tile của style về máy.
      Tiết kiệm dữ liệu di độngDùng nền vector (style ở trên), không dùng tile ảnh PNG: nhẹ hơn nhiều lần và nét ở mọi mật độ điểm ảnh. Thư viện tự giữ cache tile trên máy.
      Ảnh xem trước, thông báo đẩyKhông cần dựng bản đồ: dùng địa chỉ ảnh tĩnh ở mục trên làm ảnh thường.

      4. Định dạng được hỗ trợ

      Định dạngDùng choTrạng tháiGhi chú
      Vector tile .pbf / .mvtBản đồ vector, 3DCóNén gzip, z0–14, có cache. Cả hai đuôi đều chạy.
      GeoJSONDữ liệu thô theo tile; bảng và hàm dữ liệu riêngCó/data/…/{z}/{x}/{y}.geojson và /features/…/items.json
      PNG, JPEG, WebPTile ảnh, ảnh tĩnhCóThêm @2x cho màn hình mật độ cao; ô 256 hoặc 512 px
      Style JSON MapLibre v8Kiểu nềnCóSáng và tối (có bản 3D), ảnh vệ tinh, nền nhạt không nhãn; xem mục 5
      TileJSON 2.0 / 3.0Mô tả nguồn tileCóCho nền bản đồ và lớp dữ liệu riêng
      WMTS 1.0.0QGIS, ArcGISCóEPSG:3857 và EPSG:4326
      OGC API FeaturesTruy vấn dữ liệu riêngCóLọc CQL, bbox, phân trang, hàm có tham số
      Glyph PBFChữ trên bản đồCóNoto Sans Regular, Bold, Italic — đủ dấu tiếng Việt
      SpriteIcon POI và nghiệp vụCóBộ icon dùng chung, 1x và 2x
      Địa hình terrarium (raster-dem)Địa hình 3D, bóng núi, độ caoCóToàn quốc tới zoom 12
      Ảnh vệ tinh (JPEG)Nền ảnhCó10 m/điểm ảnh; toàn quốc tới zoom 12, đô thị lớn tới zoom 14
      Polyline (độ chính xác 6)Hình tuyến đườngCóTrả về từ /route/route
      WMS, WFS (cũ)Dịch vụ OGC đời trướcKhôngDùng WMTS và OGC API Features thay thế

      5. Danh sách API

      Mọi đường dẫn tính từ địa chỉ gốc http://MAY-CHU:3650. Không cần xác thực trong LAN; có CORS mở. {id} là mã kiểu nền, ví dụ xanh-la-sang, xanh-la-toi (bản 3D thêm đuôi -3d). Danh mục đầy đủ kèm tên hiển thị: GET /huong-dan/styles.json. Bản 3D và nền nhạt không nhãn chỉ có style.json; không có tile ảnh, ảnh tĩnh, WMTS.

      Đường dẫnTrả vềThử
      Kiểu nền
      GET /api/maps/{id}/style.jsonStyle JSON của kiểu nềnmở
      GET /styles/{id}/style.jsonCùng nội dung, đường dẫn thay thếmở
      GET /styles/{id}/sprite[@2x].{json|png}Sprite icon của bản 3Dmở
      GET /fonts/{fontstack}/{range}.pbfGlyph chữmở
      Dữ liệu nền
      GET /data/openmaptiles.jsonTileJSON vector: phạm vi, zoom, 16 lớp và trường thuộc tínhmở
      GET /data/openmaptiles/{z}/{x}/{y}.{pbf|mvt|geojson}Tile vector; bản GeoJSON có properties.layer cho từng đối tượngmở
      GET /pmtiles/vietnam.pmtiles (kèm Range)Cả kho tile vector trong một file PMTiles; trả 206 cho từng đoạn. Đọc bằng pmtiles.js, xem mục 3.
      GET /data/terrain.json, /data/terrain/{z}/{x}/{y}.pngĐịa hình mã hoá terrariummở
      GET /data/terrain/elevation/{z}/{kinh}/{vĩ}Độ cao (m) tại một điểm. POST /data/terrain/elevation nhận nhiều điểm.mở
      GET /data/satellite.json, /data/satellite/{z}/{x}/{y}.jpgẢnh vệ tinh thômở
      Ảnh vẽ từ style
      GET /styles/{id}/{z}/{x}/{y}[@2x].{png|jpg|webp}Tile ảnh 256 px, zoom 0–20. Thêm /512/ trước {z} cho ô 512 px.mở
      GET /styles/{id}.json, /styles/{id}/wmts.xmlTileJSON raster và WMTS GetCapabilitiesmở
      GET /styles/{id}/static/{kinh},{vĩ},{zoom}[@{xoay}[,{nghiêng}]]/{rộng}x{cao}[@2x].{định dạng}Ảnh tĩnh theo tâm. Cạnh tối đa 4096 px.mở
      GET /styles/{id}/static/{tây},{nam},{đông},{bắc}/{rộng}x{cao}.{định dạng}Ảnh tĩnh theo khung toạ độmở
      GET /styles/{id}/static/auto/{rộng}x{cao}.{định dạng}?path=…&marker=…Tự khớp khung. path: các điểm kinh,vĩ nối bằng |, kèm stroke, width, fill, padding. marker: kinh,vĩ|tên-ảnh.png.mở
      Tìm kiếm địa chỉ
      GET /geocode/search?q=…&format=jsonv2Tìm theo tên hoặc địa chỉ. Thêm limit, accept-language, viewbox, addressdetails=1, polygon_geojson=1.mở
      GET /geocode/reverse?lat=…&lon=…&format=jsonv2Toạ độ → địa chỉmở
      GET /geocode/statusTrạng thái dịch vụmở
      Tìm đường — POST thân JSON, hoặc GET ?json=…
      /route/routeTuyến đường và chỉ dẫn từng chặng. costing: auto, motor_scooter, motorcycle, bicycle, pedestrian, truck.mở
      /route/isochroneVùng tới được trong N phút hoặc N km, dạng GeoJSONmở
      /route/sources_to_targetsMa trận thời gian giữa nhiều điểm: ví dụ từ n đơn vị (sources) tới một hiện trường (targets) để chọn đơn vị tới nhanh nhất. Trả sources_to_targets[i][j].time (giây), .distance (km).mở
      /route/trace_routeNắn vết GPS vào đường (map matching): đưa dãy điểm GPS của xe (shape, có thể kèm time), shape_match: "map_snap", nhận lại tuyến bám đúng lòng đường và các chặng đã đi. Dùng cho hành trình phương tiện, phát lại.mở
      /route/heightMặt cắt độ cao theo tuyến: shape là dãy điểm (hoặc encoded_polyline lấy từ /route/route), resample_distance mét giữa hai mẫu; trả mảng height (m) cùng thứ tự. Dùng cho ngập lụt, tuyến ống, tầm nhìn. Độ cao lấy từ cùng dữ liệu địa hình của máy chủ.mở
      /route/optimized_route, /route/locateSắp thứ tự điểm ghé tối ưu; bắt một điểm vào đoạn đường gần nhất
      GET /route/statusTrạng thái và phiên bảnmở
      Lớp dữ liệu riêng
      GET /tiles/catalogDanh mục nguồn vector tile (bảng và hàm dữ liệu riêng)mở
      GET /tiles/{nguồn}, /tiles/{nguồn}/{z}/{x}/{y}TileJSON và tile. Gộp nhiều nguồn: /tiles/khu_vuc,dia_gioi_tinh/{z}/{x}/{y}. Hàm nhận tham số qua query.mở
      GET /features/collectionsDanh sách bảng (OGC API Features); có trang HTML để duyệtmở
      GET /features/collections/ioc.{bảng}/items.jsonGeoJSON. Tham số: limit, offset, bbox, filter (CQL), properties, sortby.mở
      GET /features/functions/{hàm}/items.jsonTruy vấn không gian: thiet_bi_quanh, khu_vuc_chua_diem, su_co_trong_khumở
      GET /features/functions/diem_thuoc_dia_gioi/items.json?lon=…&lat=…Điểm này thuộc đâu: xã/phường và tỉnh chứa điểm theo địa giới mới sau 2025 (ten_xa, ten_tinh, kèm ranh xã). Ranh để vẽ: /tiles/dia_gioi_tinh, /tiles/dia_gioi_xa.mở
      Danh mục, giám sát, thư viện
      GET /healthOK khi nền bản đồ sốngmở
      GET /styles.json, /data.json, /rendered.json, /index.jsonDanh mục style và nguồn dữ liệumở
      GET /maplibre-gl.js, /maplibre-gl.css, /leaflet.js, /leaflet.css, /pmtiles.jsThư viện bản đồ phía trình duyệt