कैमरे की स्थिति पढ़ना
MapConductor के नियंत्रक में getCameraPosition() नहीं है। यह तीनों प्लेटफ़ॉर्म पर समान है। मैप छूते समय पहले खोजा जाने वाला विधि है, इसलिए इसके बजाय क्या उपयोग किया जाता है, और यह उपलब्ध क्यों नहीं कराया गया है, यहाँ लिखा गया है।
एक शब्द में कहें तो, कैमरा लाने के लिए नहीं, बल्कि प्राप्त होने वाली चीज़ है। मैप SDK ओर कैमरे में होने वाले बदलावों को जानता है, और हमें बस उसे प्राप्त करना है।
01 · 3 मार्ग
उपयोग के अनुसार चुनें। सभी में वही MapCameraPosition प्राप्त होता है, और प्रदर्शन क्षेत्र visibleRegion में होता है।
mapViewState.cameraPosition — कभी भी पढ़ा जा सकता है। प्रदर्शन क्षेत्र cameraPosition.visibleRegion.bounds है।onCameraMove / onCameraMoveEnd — गति के दौरान भी ट्रिगर होता है। UI को अनुसरण कराने के लिए यही है।onCameraChanged प्राप्त करें। मैप नियंत्रक के एकल स्लॉट श्रोता के लिए प्रतिस्पर्धा करने की आवश्यकता नहीं है।val camera = mapViewState.cameraPosition
val bounds = camera.visibleRegion?.bounds
// बदलाव देखें
MapView(
state = mapViewState,
onCameraMoveEnd = { camera -> reload(camera.visibleRegion?.bounds) },
)let camera = mapViewState.cameraPosition
let bounds = camera.visibleRegion?.bounds
// बदलाव देखें
MapLibreMapView(state: mapViewState, onCameraMoveEnd: { camera in
reload(camera.visibleRegion?.bounds)
})const camera = mapViewState.cameraPosition;
const bounds = camera.visibleRegion?.bounds;
// बदलाव देखें
<MapLibreMapView
state={mapViewState}
onCameraMoveEnd={(camera) => reload(camera.visibleRegion?.bounds)}
/>02 · प्राप्त करने की विधि क्यों नहीं है
MapConductor तीनों प्लेटफ़ॉर्म पर घोषणात्मक UI (Compose / SwiftUI / React) पर आधारित है। घोषणात्मक UI में, स्थिति को रखने के लिए एक ही स्थान होता है जो बताता है कि "अभी क्या है", और UI उसे प्रतिबिंबित करता है। कैमरा भी एक स्थिति है, इसलिए इसका स्थान state है।
कंट्रोलर में गेटर मेथड जोड़ने पर, एक ही मान के दो स्रोत हो जाते हैं। एक state से और दूसरा सीधे SDK से पढ़ा गया। दोनों समान होने चाहिए, लेकिन अंतर आने की संभावना बढ़ जाती है। वास्तव में ऐसा ही था, और हटाने से पहले हम एक ही फ्रेम में कैमरा दो बार बना रहे थे — एक बार SDK के इवेंट के लिए, और दूसरी बार हर री-पेंट पर दोबारा बनाए गए हिस्से के लिए।
मैप SDK से कैमरा इवेंट
↓ प्रोवाइडर SDK के कच्चे मान पढ़ता है, एकीकृत ज़ूम में बदलता है, visibleRegion जोड़ता है
state.updateCameraPosition(camera)
↓
├─ mapViewState.cameraPosition (कभी भी पढ़ा जा सकता है)
├─ onCameraMove / onCameraMoveEnd (ऐप के कॉलबैक)
└─ रजिस्टर किए ओवरले का onCameraChanged (एक्सटेंशन मॉड्यूल)03 · पुल की लागत
अगर केवल डिज़ाइन की बात हो तो "एक और जोड़ दें" का रुझान होता है, इसलिए यहाँ वास्तविक माप दिया गया है। कैमरा एक बार बनाना सस्ता नहीं है।
एक कॉल में क्या किया जाता है
SDK से center / zoom / bearing / tilt पढ़ें → प्रदाता-विशिष्ट ZoomAltitudeConverter द्वारा एकीकृत ज़ूम में रूपांतरण → स्क्रीन के चारों कोनों को वापस प्रक्षेपित करके visibleRegion बनाएं। आखिरी भाग सबसे भारी है, यह कोई साधारण गेटर नहीं है।
यह मापा गया मान है। MapLibre के मार्कर पेज को Chromium में खोला गया और एक बार ड्रैग (लगभग 20 फ्रेम का पैन) के दौरान getCameraPosition() कितनी बार कॉल हुआ, इसे गिना गया।
लगभग 65% कम हो गया। जो कम हुआ वह पूरी तरह से दोबारा बनाना है। SDK के इवेंट में एक बार बनाकर state में भेजने के बावजूद, हर री-पेंट पर व्यू उसी मान को दोबारा बना रहा था। कॉल करने वाला सभी 13 व्यू में मौजूद था, यानी सभी ताज़ा पुश किए गए मान को फेंक रहे थे।
जब तक स्थिर है तो 0 बार है। यह बेकाबू नहीं था, यह ऑपरेशन के दौरान ही निश्चित रूप से प्रभाव डालने वाली लागत थी। यह नक्शे के सबसे भारी पल में जुड़ती है, इसलिए इसका असर आसानी से महसूस होता है।
var camera by remember { mutableStateOf<MapCameraPosition?>(null) }
MapLibreMapView(
state = mapViewState,
modifier = Modifier.weight(1f),
// Fires throughout the gesture — keep this handler cheap
onCameraMove = { position -> camera = position },
// Once, when the map settles. Fetching and redrawing belong here
onCameraMoveEnd = { position -> viewModel.onCameraSettled(position) },
)
camera?.let { position ->
Text("lat %.5f".format(position.position.latitude))
Text("lng %.5f".format(position.position.longitude))
Text("zoom %.2f".format(position.zoom))
// Read the visible region off the value you were handed; do not rebuild it
position.visibleRegion?.bounds?.let { bounds ->
Text("SW ${bounds.southWest} NE ${bounds.northEast}")
}
}04 · 1 फ्रेम की देरी
mapViewState.cameraPosition "अंतिम पुश किया गया मान" है, इसलिए सैद्धांतिक रूप से यह SDK के वर्तमान मान से 1 फ्रेम पुराना हो सकता है। यह गेटर मेथड जोड़ने का एकमात्र ठोस कारण है, इसलिए इसे ईमानदारी से लिखा गया है।
onCameraMove खिसकाने के दौरान हर फ्रेम पर फायर करता है, इसलिए state हमेशा पिछले फ्रेम तक अपडेट रहता है। प्रदर्शन, डेटा प्राप्त करना, या दायरे का आकलन—इनमें से किसी में भी महसूस किया जाने वाला अंतर नहीं है। वास्तव में, प्राप्ति विधि को हटाने के बाद भी सभी 41 ब्राउज़र टेस्ट यथावत पास हो रहे हैं।
खींचने के दौरान फ्रेम से पूरी तरह सिंक किया गया रेंडरिंग। हालांकि, यह मैप SDK के रेंडरिंग लूप के साथ चलने की बात है, इसलिए एकीकृत API के बजाय आपको बाद में बताए गए बचाव के रास्ते का उपयोग करना चाहिए।
05 · फिर भी जब कच्चा मान चाहिए
statе के माध्यम से पर्याप्त नहीं है — उदाहरण के लिए, मैप SDK के रेंडरिंग लूप के साथ सिंक करना चाहते हैं — ऐसी स्थिति में, यूनिफाइड API का चक्कर न लगाकर MapViewHolder से नेटिव मैप इंस्टेंस ले आएं। यह प्रोवाइडर-विशिष्ट कोड हो जाएगा, लेकिन इसके बदले में यह सबसे तेज़ और सबसे सटीक है।
const holder = mapViewState.getMapViewHolder(); const map = holder?.map as maplibregl.Map | undefined; const liveZoom = map?.getZoom();