เอกสารประกอบ / เลเยอร์ส่วนขยาย / เลเยอร์เวกเตอร์ไทล์

เลเยอร์เวกเตอร์ไทล์

แพ็กเกจที่วาดเวกเตอร์สไตล์รูปแบบ MapLibre (style.json) เป็นแรสเตอร์ไทล์ภายในเบราว์เซอร์ เพื่อให้ซ้อนทับบนผู้ให้บริการแผนที่ใดก็ได้ แม้แต่แผนที่ที่อ่านเวกเตอร์สไตล์เองไม่ได้อย่าง Google Maps, MapKit, HERE, ArcGIS หรือ Cesium ก็จะแสดงผลหน้าตาเหมือนกัน

REACT
@mapconductor/react-vectortile
วิธีการวาด
แรสเตอร์ไทล์ (wasm)
ESM / CJS
รองรับเฉพาะ ESM

01 · ภาพรวม

การวาดใช้เรนเดอเรอร์ที่เขียนด้วย Rust คอมไพล์เป็น wasm และทำงานภายใน Web Worker ไทล์ที่วาดแล้วจะถูกส่งมอบจากเซิร์ฟเวอร์ไทล์ในเครื่องของ SDK (Service Worker) และถูกวางบนแผนที่เป็น RasterLayer ธรรมดา จากมุมมองของแผนที่ มันก็เป็นเพียงแรสเตอร์เลเยอร์ธรรมดา จึงไม่จำกัดผู้ให้บริการ

เลเยอร์ถูกแบ่งเป็น 2 ชั้น คือ "พื้น" ที่ประกอบด้วยการเติมสี เส้น และวงกลม กับ "ป้ายชื่อ" ที่โปร่งใสอยู่ด้านบน เมื่อฟอนต์ถูกส่งมาจะมีการวาดใหม่เฉพาะฝั่งป้ายชื่อเท่านั้น จึงไม่เกิดอาการแผนที่หายไปชั่วขณะในจังหวะที่ตัวอักษรปรากฏขึ้น การแสดงที่มาของสไตล์ (เช่น OpenStreetMap) ก็จะถูกเพิ่มให้โดยอัตโนมัติ

02 · การติดตั้ง

terminalnpm
npm install @mapconductor/js-sdk-core @mapconductor/js-sdk-react \
            @mapconductor/react-vectortile

@mapconductor/js-vectorstyle จะถูกติดตั้งมาด้วยกันในฐานะ dependency แพ็กเกจนี้รองรับเฉพาะ ESM

วาง Service Worker สำหรับไทล์

ไทล์จะถูกส่งมอบจาก /tile-sw.js ข้อกำหนดเหมือนกับฮีตแมป กรุณาคัดลอกไฟล์ที่อยู่ใน @mapconductor/js-sdk-core ไปยังไดเรกทอรี public ของแอป

package.jsonJSON
{
  "scripts": {
    "postinstall": "cp node_modules/@mapconductor/js-sdk-core/dist/tile-sw.js public/tile-sw.js"
  }
}

ใน production build ของ Vite จำเป็นต้องตั้งค่าให้ output worker เป็น ES module (ไม่จำเป็นบน dev server)

vite.config.tsTypeScript
import { defineConfig } from 'vite';

export default defineConfig({
  worker: { format: 'es' },
});
ข้อควรระวัง
Service Worker ทำงานได้เฉพาะใน secure context เท่านั้น หากเป็น localhost ใช้ HTTP ตามเดิมได้ แต่เมื่อเปิดจากอุปกรณ์อื่นใน LAN จะต้องใช้ HTTPS

03 · วิธีใช้พื้นฐาน

วางไว้ใน *MapView ใดก็ได้ คุณสามารถส่ง style เป็น URL ของ style.json, เป็นสตริง หรือเป็นอ็อบเจกต์ที่แยกวิเคราะห์แล้วก็ได้ ตัวอย่างด้านล่างซ่อนแผนที่ของ Google Maps เอง (GoogleMapDesign.None) แล้ววาดสไตล์เวกเตอร์ทับด้านบน

VectorTileMap.tsxTypeScript · React
import { createGeoPoint, createMapCameraPosition } from '@mapconductor/js-sdk-core';
import { GoogleMapDesign, GoogleMapView2D, useGoogleMapViewState } from '@mapconductor/react-for-googlemaps';
import { VectorTileLayer } from '@mapconductor/react-vectortile';

const TOKYO = createGeoPoint({ latitude: 35.6812, longitude: 139.7671 });
const STYLE_URL = 'https://tiles.versatiles.org/assets/styles/colorful/style.json';

export function VectorTileMap() {
  const state = useGoogleMapViewState({
    apiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
    mapDesignType: GoogleMapDesign.None,
    cameraPosition: createMapCameraPosition({ position: TOKYO, zoom: 12 }),
  });

  return (
    <GoogleMapView2D state={state} style={{ height: 480 }}>
      <VectorTileLayer style={STYLE_URL} onDiagnostics={(messages) => console.warn(messages)} />
    </GoogleMapView2D>
  );
}

style ถูกเปรียบเทียบตามเนื้อหา ถ้าเนื้อหาเหมือนกัน แม้ส่งอ็อบเจกต์ใหม่ทุกครั้งก็จะไม่มีการวาดใหม่

04 · เปลี่ยนรูปลักษณ์

rules に ส่งกฎที่เขียนตามหัวข้อ การปรับสไตล์ของแผนที่ ไปยัง rules แล้วจะวาดในสถานะที่มีการปรับแต่ง เช่น เปลี่ยนสี หรือซ่อนเลเยอร์ ส่วนบทบาทที่ถูกซ่อนไว้ (อาคาร ป้ายข้อความ ฯลฯ) จะไม่ถูกวาดตั้งแต่แรก

TypeScriptTypeScript · React
import { useMemo } from 'react';
import { buildStyleRules, LayerRole } from '@mapconductor/js-vectorstyle';
import { VectorTileLayer } from '@mapconductor/react-vectortile';

const rules = useMemo(
  () => buildStyleRules((r) => {
    r.role(LayerRole.building, { visible: false });
    r.role(LayerRole.water, { colorFilter: { mix: { color: '#3a7ca5', amount: 0.6 } } });
    r.role(LayerRole.label, { opacity: 0.6 });
  }),
  [],
);

<VectorTileLayer style={STYLE_URL} rules={rules} />

เมื่อเปลี่ยนกฎหรือสไตล์ จะวาดใหม่จากเวกเตอร์ที่อยู่ในหน่วยความจำเท่านั้น ไม่ต้องไปดึงจากเครือข่าย เพราะรูปทรงไม่เปลี่ยน มีแต่วิธีระบายสีที่เปลี่ยน แม้ใช้สไลเดอร์เลื่อนสีก็ไม่เพิ่มการสื่อสาร ถ้าละเว้น rules คอมไพเลอร์ของกฎ (wasm) จะไม่ถูกโหลด

05 · ใช้เป็นแผนที่พื้นฐาน

ถ้าระบุ asBasemap ใน MapLibre, Mapbox และ MapTiler จะไม่แปลงเป็นแรสเตอร์ แต่ส่งสไตล์ตรงไปที่แผนที่เพื่อแทนที่ดีไซน์ของแผนที่ ทั้งสามนี้วาดเวกเตอร์สไตล์ได้เอง จึงเร็วกว่าและสวยกว่า ในกรณีนี้ opacity จะไม่ทำงาน

TypeScriptTypeScript · React
import { MapLibreMapView2D, useMapLibreViewState } from '@mapconductor/react-for-maplibre';
import { VectorTileLayer } from '@mapconductor/react-vectortile';

<MapLibreMapView2D state={state}>
  <VectorTileLayer style={STYLE_URL} rules={rules} asBasemap />
</MapLibreMapView2D>

ในโปรไวเดอร์อื่น asBasemap จะไม่เปลี่ยนอะไรเลย สำหรับแผนที่ของโปรไวเดอร์เอง กรุณาซ่อนโดยตั้งดีไซน์เป็น None จากฝั่งแอป

06 · พร็อพเพอร์ตี้หลัก

พร็อพเพอร์ตี้
ค่าเริ่มต้น
คำอธิบาย
style
—
URL, สตริง หรืออ็อบเจกต์ของ style.json จำเป็นต้องระบุ
rules
—
กฎของ js-vectorstyle ถ้าละเว้นจะวาดสไตล์ตามที่เป็น
opacity
1
ความทึบของเลเยอร์ทั้งหมด
visible
true
แสดงหรือไม่
tileSize
512
ขนาดของไทล์ที่ส่งออก (px) ถ้าโปรไวเดอร์มีความต้องการจะใช้ค่านั้นเป็นหลัก (ArcGIS 3D คือ 256)
maxZoom
22
ซูมสูงสุดที่จะวาด
headers
—
ส่วนหัวที่แนบไปเมื่อไปดึงไทล์จากซอร์ส ใช้สำหรับโทเคนหรือ API key
asBasemap
false
ในแผนที่ที่รองรับเวกเตอร์ จะส่งสไตล์ตรงไปที่แผนที่
onDiagnostics
—
เหตุผลที่วาดไม่ได้ตามที่คาด เช่น ชนิดเลเยอร์ที่วาดไม่ได้ หรือซอร์สที่ดึงไม่ได้

ใช้ไทล์ที่ต้องมีคีย์

TypeScriptTypeScript · React
<VectorTileLayer
  style="https://tiles.example.com/styles/basic/style.json"
  headers={{ Authorization: `Bearer ${token}` }}
/>

07 · ข้อจำกัดปัจจุบัน

เนื่องจากป้ายชื่อเป็นแรสเตอร์ด้วย เมื่อหมุนแผนที่ตัวอักษรจะหมุนตามไปด้วย
ไม่วาด imports ของ Mapbox และเลเยอร์บางชนิด จะแสดงใน onDiagnostics
MapKit และ Mappls ไม่มีดีไซน์ "ไม่มีแผนที่" จึงมีการโหลดแผนที่ของผู้ให้บริการเองอยู่ใต้ไทล์ที่ทึบแสงด้วย
ต้องวางไว้ภายใน *MapView จะไม่ทำงานนอกแผนที่

หน้าที่เกี่ยวข้อง