कैमरा ― एब्सट्रैक्शन का सबसे मुश्किल हिस्सा
MapConductor में सबसे मुश्किल और सबसे मूल्यवान काम कैमरे को एकीकृत करना है। position, zoom, bearing, tilt, visibleRegion से बने एक कैमरा मॉडल को, 10 से अधिक प्रकार के मैप इंजन में एक ही अर्थ के साथ संरेखित किया गया है। अगर आप वही MapCameraPosition पास करें, तो किसी भी प्रदाता पर वही दृश्य दिखाई देगा।
01 · एकीकरण का क्या मतलब है
मैप इंजन के पास अपना अलग कैमरा मॉडल होता है। कुछ ज़ूम के हिसाब से, कुछ कैमरा ऊंचाई के हिसाब से, कुछ ज़मीन पर फोकस पॉइंट के चारों ओर घूमते हैं, और कुछ व्यूपॉइंट को ही बदलते हैं। अगर आप नेटिव SDK का सीधे इस्तेमाल करते हैं, तो प्रदाता बदलते ही "एक ही संख्या के बावजूद अलग दृश्य" हो जाएगा और आपको स्क्रीन के लॉजिक तक को बदलना पड़ेगा।
MapConductor इस अंतर को एडेप्टर लेयर में सीमित रखता है और ऐप से सिर्फ एक कैमरा मॉडल दिखाता है। नतीजतन, कैमरा पोज़िशन एक ऐसा मान बन जाता है जिसे आप प्रदाताओं के बीच ले जा सकते हैं। सैंपल ऐप के Camera Sync पेज पर, आप एक कैमरा पोज़िशन को सभी प्रदाताओं में भेजकर यह वास्तव में देख सकते हैं कि वे सभी एक ही स्थान, एक ही स्केल और एक ही झुकाव पर कैसे दिखाई देते हैं।
जूम या ऊंचाई
2D टाइल सिस्टम ज़ूम लेवल, और 3D सिस्टम कैमरा ऊँचाई या दृश्य दूरी का उपयोग करके पैमाने को व्यक्त करते हैं। इकाइयाँ और मानक भी अलग-अलग हैं।
दृष्टि बिंदु या निरीक्षण बिंदु
पृथ्वी पर एक बिंदु के चारों ओर घूमने (ऑर्बिट) वाला मॉडल और कैमरे की स्थिति और दिशा से वर्णित मॉडल एक साथ मिले हुए हैं।
झुकाव की सीमा
अधिकतम झुकाव कोण और यह कि क्या ऊपर की ओर झुकाया जा सकता है, यह इंजन के आधार पर भिन्न होता है। नकारात्मक झुकाव वाला कोई भी नहीं है।
val camera = MapCameraPosition(
position = geoPoint,
zoom = 18.0,
tilt = 70.0,
)
moveCameraTo(camera)02 · एकीकृत कैमरा मॉडल
कैमरा को MapCameraPosition से दर्शाया जाता है। प्रदाता-विशिष्ट कोई टाइप नहीं है, बस यह वैल्यू बनाएं और इसे moveCameraTo में पास करें।
copy() से आप केवल कुछ हिस्सों को बदल सकते हैं, और तुलना ज़ूम 0.01 और झुकाव 0.01 की अनुमति त्रुटि के साथ की जाती है। ताकि प्रदाता से लौटने वाले मानों में हल्के उतार-चढ़ाव के कारण "चला गया" की गलत पहचान न हो।
03 · ज़ूम लेवल=ऊंचाई का एकीकरण
ज़ूम को आंतरिक रूप से "कैमरा की ऊंचाई" के समान माना जाता है। 2D टाइल-आधारित ज़ूम और 3D आधारित ऊंचाई/दृश्य दूरी को परस्पर बदलने वाला कनवर्टर `core` में है, और किसी भी प्रदाता के मान को पहले एक सामान्य ज़ूम (Google Maps मानक) में बदला जाता है, फिर उसे प्रकाशित किया जाता है।
यह मानक सिर्फ सैद्धांतिक आधार पर तय नहीं किया गया है। सैंपल ऐप के कैलिब्रेशन टूल में, समान ज़ूम निर्दिष्ट करने पर वास्तव में दिखाई देने वाली सीमा का प्रत्येक इंजन द्वारा माप किया जाता है, और क्षेत्रफल मेल खाने के लिए मानक ऊंचाई को कैलिब्रेट किया जाता है। इसलिए, `zoom 14` किसी भी प्रदाता के लिए समान चौड़ाई है।
एक ही ज़ूम को अक्षांश के अनुसार अलग ऊँचाई चाहिए
Web Mercator ध्रुवों की ओर मैप को बड़ा कर देता है, इसलिए एक ही ज़ूम स्तर के लिए कैमरे की ऊँचाई भूमध्य रेखा और ऊँचे अक्षांशों के बीच कई गुना बदल जाती है। ज़ूम ⇄ ऊँचाई का रूपांतरण इसका हिसाब रखता है।
प्रत्येक दोगुने पर एक स्तर का संबंध और केवल मानक `zoom 0` की ऊंचाई स्थिरांक है। उच्च अक्षांश पर समान ज़ूम के लिए भूमि पर दूरी कम हो जाती है, यह बिंदु भी रूपांतरण में शामिल है, इसलिए टोक्यो और होनोलूलू में स्केल में कोई अंतर नहीं होता है।
04 · `tilt < 0` का नकली समर्थन
`tilt` −60 से 60 डिग्री का मान लेता है। धनात्मक मान एक परिचित तिरछा नीचे देखने का दृश्य है, लेकिन ऋणात्मक मान क्षितिज से ऊपर देखने का एक ऊंचा दृश्य है। मैप इंजन में इसे सीधे दर्शाने में सक्षम कुछ भी नहीं है। किसी भी SDK में `pitch` केवल 0 या उससे अधिक स्वीकार किया जाता है।
इसलिए `MapConductor` कैमरे की आंख की स्थिति और दिशा को बनाए रखते हुए, इंजन को एक धनात्मक झुकाव के रूप में देने के रूप में बदल देता है। ऐप से देखने पर ऋणात्मक `tilt` का उपयोग वैसे ही किया जा सकता है, और प्राप्त की गई कैमरा स्थिति भी ऋणात्मक `tilt` के रूप में वापस आती है।
सीधे ऊपर से देखा गया समतल दृश्य। ज़मीन पर एक आयत स्क्रीन पर एक आयत बन जाता है।
आगे की ओर झुका हुआ तिरछा दृश्य। ज़मीन पर यह एक समलम्ब बन जाता है जिसमें निकट की ओर संकरा और दूर की ओर चौड़ा हिस्सा होता है।
क्षितिज से ऊपर देखने वाला उन्नत दृश्य। आकाश की ओर वाला दृश्य जो मूल रूप से मौजूद नहीं है।
एकमात्र अपवाद React पर Google Maps 2D है — रास्टर JavaScript API वाला मैप। उसका tilt ब्राउज़र और टाइल की स्थिति पर निर्भर करता है, इसलिए एमुलेशन जिस ऊँचाई और दिशा पर टिका है, उन्हें नियंत्रित नहीं किया जा सकता। Google Maps 3D (Map3DElement) ऋणात्मक tilt का समर्थन करता है।
// −60 से 60 वाला स्लाइडर सीधे दे दें; ऋणात्मक मान पर भी वही कॉल currentPosition = currentPosition.copy(tilt = tilt) mapViewState.value?.moveCameraTo(currentPosition)
func setTilt(_ angle: Double, state: any MapViewStateProtocol) {
currentPosition = currentPosition.copy(tilt: angle)
state.moveCameraTo(cameraPosition: currentPosition)
}<SliderControl
label="Tilt" value={tilt} min={-60} max={60} step={1}
onChange={value => {
setTilt(value);
const next = cameraPositionRef.current.copy({ tilt: value });
cameraPositionRef.current = next;
mapViewState.moveCameraTo(next, 400);
}}
/>05 · VisibleRegion ― वास्तव में दिखाई देने वाली सीमा
कैमरे को झुकाने पर, स्क्रीन का आयत ज़मीन पर एक समलंब बन जाता है। केवल दक्षिण-पश्चिम और उत्तर-पूर्व के आयत (`bounds`) से, सामने और पीछे की चौड़ाई का अंतर नहीं दिखाया जा सकता है। `VisibleRegion` आयत के अलावा स्क्रीन के चारों कोनों की भूमि पर निर्देशांक रखता है, और झुके हुए कैमरे के साथ भी "वास्तव में दिखाई देने वाली सीमा" को संभालने में सक्षम बनाता है।
`near` स्क्रीन का निचला किनारा है, यानी कैमरे के करीब वाला भाग, और `far` ऊपरी किनारा है जो दूर की ओर है। `left` / `right` स्क्रीन के आधार पर हैं, इसलिए `bearing` से मैप को घुमाने पर अर्थ नहीं बदलता है। इन 4 बिंदुओं के होने के लिए, झुके हुए मैप में भी डेटा प्राप्ति की सीमा और स्रोत नोट के निर्धारण को सही ढंग से किया जा सकता है।
mapViewState.cameraPosition.visibleRegion?.let { region ->
val sw = region.bounds.southWest
val ne = region.bounds.northEast
// झुकी हुई स्क्रीन के चारों कोने — समलंब की तरह इस्तेमाल हो सकते हैं
val corners = listOf(region.nearLeft, region.nearRight, region.farLeft, region.farRight)
}if let region = cameraPosition.visibleRegion {
let bounds = region.bounds
let corners = [region.nearLeft, region.nearRight, region.farLeft, region.farRight]
}<MapViewContainer initialCamera={INIT_CAMERA} onCameraMove={setCameraPosition}>
{/* cameraPosition.visibleRegion की सामग्री क्रम से दिखाएँ */}
</MapViewContainer>
const visibleRegion = cameraPosition?.visibleRegion ?? null;
visibleRegion?.nearLeft?.toUrlValue(5);
visibleRegion?.farRight?.toUrlValue(5);