สลับการออกแบบแผนที่ (ไทล์)
รูปลักษณ์ของแผนที่ถูกกำหนดด้วย mapDesignType เพียงอย่างเดียว เลือกพรีเซ็ตที่เตรียมไว้สำหรับแต่ละผู้ให้บริการ หรือระบุ URL ของ Style JSON และ URL ของไทล์เพื่อกำหนดการออกแบบที่กำหนดเอง การสลับเพียงแค่กำหนดค่าให้กับพร็อพเพอร์ตี้ ไม่จำเป็นต้องสร้างแผนที่ใหม่
01 · ประเภทของการออกแบบ
การออกแบบของผู้ให้บริการใดๆ จะใช้งาน MapDesignTypeInterface (ใน iOS คือ MapDesignTypeProtocol) หากจำเพียงสามองค์ประกอบหลักเหล่านี้ วิธีการใช้งานจะเหมือนกันแม้ว่าผู้ให้บริการจะเปลี่ยนไป
ค่าสำหรับระบุการออกแบบ เป็นค่าเนทีฟของผู้ให้บริการ (เช่น ค่าคงที่ mapType ของ Google) หรือสตริง
ค่าจริงที่ส่งไปยังเอ็นจิ้นแผนที่ของผู้ให้บริการ ประกอบด้วย URL ของ Style JSON หรือคำนิยามของไทล์
กฎสำหรับสลับการแสดงที่มาของข้อมูลตามระดับการซูมและพื้นที่แสดงผล จำเป็นเมื่อใช้ไทล์ที่กำหนดเอง
02 · พรีเซ็ต
ในแพ็กเกจของผู้ให้บริการแต่ละราย มีการออกแบบมาตรฐานที่ใช้ได้กับผู้ให้บริการนั้นๆ อยู่ในรูปแบบค่าคงที่ แอปตัวอย่างใช้รายการนี้ตรงๆ เป็นตัวเลือก
iOS · React
React: MapboxDesign
บน React: Streets · Outdoors · Light · Dark · SatelliteStreets และสไตล์ JSON ตระกูล OsmBright / MapTiler
iOS / React: ArcGISMapDesign
React: TomTomDesign
React มีเพิ่มอีก StandardLight / Dark · DrivingLight / Dark · MonoLight / Dark
React
React
React
React
จะแสดงหมายเหตุเฉพาะสิ่งที่แตกต่างกันระหว่างแพลตฟอร์มเท่านั้น แถวที่ไม่มีหมายเหตุ ชื่อประเภทและชื่อค่าคงที่ของพรีเซ็ตจะเหมือนกันในทั้ง 3 แพลตฟอร์ม
03 · การสลับ
กำหนดค่าให้กับ mapDesignType ของออบเจกต์สถานะในมุมมองแผนที่ เนื่องจากสถานะถูกตรวจสอบอยู่ รูปลักษณ์ของแผนที่จะเปลี่ยนแปลงทันทีที่กำหนดค่า
// state เป็น MapViewStateInterface<*> ให้แคบลงเป็นชนิดของผู้ให้บริการก่อนกำหนดค่า
when (state) {
is GoogleMapViewStateInterface ->
state.mapDesignType = GoogleMapDesign.Satellite
is MapLibreViewStateInterface ->
state.mapDesignType = MapLibreDesign.OsmBrightJa
is MapTilerViewStateInterface ->
state.mapDesignType = MapTilerDesign.Toner
}// ส่งดีไซน์เริ่มต้นตอนสร้าง State
@StateObject private var mapLibreState = MapLibreViewState(
mapDesignType: MapLibreDesign.DemoTiles,
cameraPosition: viewModel.initCameraPosition
)
// การสลับคือการกำหนดค่าให้พร็อพเพอร์ตี้ @Published เท่านั้น
mapLibreState.mapDesignType = MapLibreDesign.OsmBrightJaconst [mapViewState, setMapViewState] =
useState<MapViewStateInterface<MapDesignTypeInterface<unknown>> | null>(null);
const handleDesignChange = (designId: string) => {
const option = mapDesignOptions.find(item => item.design.id === designId);
if (!mapViewState || !option) return;
mapViewState.mapDesignType = option.design;
};04 · กำหนดการออกแบบที่กำหนดเอง
ประเภทของพรีเซ็ตถูกเปิดเผยเป็นคอนสตรัคเตอร์โดยตรง หากส่งค่า ID และ URL ของ Style JSON (ประเภทเวกเตอร์) หรือเทมเพลต URL ของไทล์ (ประเภทแรสเตอร์) คุณสามารถใช้สไตล์ของบริษัทหรือไทล์ของ GSI เหมือนกับพรีเซ็ตได้
// MapLibreDesign เป็น data class เพียงส่ง URL ของ style JSON ก็ได้ดีไซน์ของคุณเอง
val GsiPale =
MapLibreDesign(
id = "gsi-pale",
styleJsonURL = "https://example.com/styles/gsi-pale/style.json",
attributionRules =
listOf(
AttributionRule(attribution = "ไทล์ของ GSI"),
AttributionRule(attribution = "GEBCO", minZoom = 5, maxZoom = 8),
),
)private val mapLibreDesigns =
listOf(
MapDesignOption(label = "OsmBright", design = MapLibreDesign.OsmBright),
MapDesignOption(label = "GSI Pale", design = GsiPale),
)// ห่อค่าคงที่ mapType ของเนทีฟไว้ตามเดิม แล้วเติมเฉพาะการระบุแหล่งที่มา
val NormalWithNotice =
GoogleMapDesign.Custom(
id = MAP_TYPE_NORMAL,
attributionRules = listOf(AttributionRule(attribution = "ข้อมูลของเราเอง 2026")),
)สำหรับผู้ให้บริการที่ประเภทของแผนที่ถูกกำหนดโดยค่าคงที่ของระบบ (เช่น Google Maps) ให้ใช้ GoogleMapDesign.Custom และส่งค่าคงที่ไปที่ id เพื่อเปลี่ยนเฉพาะการแสดงที่มา MapTiler, Mapbox, HERE ฯลฯ ก็มีคอนสตรัคเตอร์ในรูปแบบเดียวกัน
// public init(id:styleJsonURL:attributionRules:) คือทางเข้าสำหรับดีไซน์ของคุณเอง
let gsiPale = MapLibreDesign(
id: "gsi-pale",
styleJsonURL: "https://example.com/styles/gsi-pale/style.json",
attributionRules: [
AttributionRule(attribution: "ไทล์ของ GSI"),
AttributionRule(attribution: "GEBCO", minZoom: 5, maxZoom: 8),
]
)private let mapLibreDesigns = [
MapDesignOption(label: "DemoTiles", design: MapLibreDesign.DemoTiles),
MapDesignOption(label: "GSI Pale", design: gsiPale),
]
// ตอนนำไปใช้ ให้แคสต์เป็นชนิดของผู้ให้บริการ
if let design = option.design as? MapLibreDesign {
mapLibreState.mapDesignType = design
}เป็นโครงสร้าง จึงกำหนดด้วย let และแบ่งปันได้ทุกที่ เนื่องจาก MapDesignOption ใน ViewModel มี design: Any เราจึงกรองเป็นประเภทของผู้ให้บริการด้วย as? เมื่อใช้งาน
const GSI_STANDARD_DESIGN = new LeafletDesign({
id: 'gsi-standard',
tileUrl: 'https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png',
tileOptions: { minZoom: 5, maxZoom: 18, tileSize: 256 },
attributionRules: GSI_STANDARD_ATTRIBUTION_RULES,
});
export const LEAFLET_DESIGNS: MapDesignOption[] = [
{ label: 'OpenStreetMap', design: LeafletDesign.OpenStreetMap },
{ label: 'GSI Standard', design: GSI_STANDARD_DESIGN },
{ label: 'None', design: LeafletDesign.None },
];// new MapLibreDesign(id, styleJsonURL, attributionRules?)
const GSI_PALE = new MapLibreDesign(
'gsi-pale',
'https://example.com/styles/gsi-pale/style.json',
[{ attribution: GSI_ATTRIBUTION }],
);
export const MAPLIBRE_DESIGNS: MapDesignOption[] = [
{ label: 'OsmBrightJa', design: MapLibreDesign.OsmBrightJa },
{ label: 'GSI Pale', design: GSI_PALE },
];Leaflet กำหนดด้วยไทล์แรสเตอร์ MapLibre กำหนดด้วย JSON ของสไตล์ เนื่องจากข้อมูลเมตาของดีไซน์อยู่ในแพ็กเกจเดียวกับ SDK รันไทม์ที่หนักของผู้ให้บริการแต่ละราย ในตัวอย่างจึงทำการ import แบบไดนามิกสำหรับแต่ละผู้ให้บริการเพื่อแยกชิงก์
05 · การระบุแหล่งที่มา (attributionRules)
เมื่อใช้ไทล์ที่กำหนดเอง ให้ระบุเงื่อนไขการแสดงชื่อของผู้ให้บริการไทล์เป็นกฎ จะมีการเลือกเฉพาะชื่อที่จำเป็นตามการซูมและช่วงการแสดงผลของกล้องโดยอัตโนมัติ
06 · แอปตัวอย่าง
ทั้ง 3 แพลตฟอร์มมี UI สำหรับสลับดีไซน์ โครงสร้างของ UI เป็นการใช้งานตรงไปตรงมาสำหรับแต่ละแพลตฟอร์ม และมีเฉพาะกระบวนการมอบหมายค่าที่เหมือนกัน
val mapViewState = rememberMapLibreMapViewState(
mapDesign = MapLibreDesign.DemoTiles,
cameraPosition = MapCameraPosition(
position = GeoPoint.fromLatLong(21.382314, -157.933097),
zoom = 12.0,
),
)
val designs = listOf(
"Demo" to MapLibreDesign.DemoTiles,
"OSM Bright" to MapLibreDesign.OsmBrightJa,
"Toner" to MapLibreDesign.MapTilerTonerJa,
)
MapLibreMapView(state = mapViewState, modifier = Modifier.weight(1f))
Row {
designs.forEach { (label, design) ->
// Just an assignment. The map is not rebuilt, so the camera stays where it is
Button(onClick = { mapViewState.mapDesignType = design }) { Text(label) }
}
}