Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Koordinata tartibi: eng ko'p uchraydigan xato
- 2.1 Kim qaysi tartibda
- 2.2 Bitta ichki format
- 3. API kalit: sir emas, cheklov
- 3.1 Kalit qanday ishlaydi
- 3.2 Kalitni cheklash
- 3.3 Narx va shartlar (2026-oktabr holati)
- 4. Yandex Maps JS API 3: reactify
- 4.1 Ulash
- 4.2 Xarita va marker
- 4.3 SSR
- 5. Google Maps: @vis.gl/react-google-maps
- 6. Limitni tejash: kesh va debounce
- 7. MapLibre: vektor xarita, o'z provayderingiz bilan
- 7.1 Raster va vektor plitka
- 7.2 Kanon tajribasi nimani ko'rsatdi
- 8. Google va Yandex: CSP va maxfiylik narxi
- 9. Kalitsiz yo'l: xarita ilovasini havola bilan ochish
- 10. Marshrut va geokoder: qayerda ishlaydi
- 11. Hujumchi nigohi
- 12. Ko'p uchraydigan xatolar
- 13. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): GeoJSON'dan markerlar ro'yxati
- 3-mashq (qiyin): debounce + kesh
- 4-mashq: tajriba qadami (ixtiyoriy)
- 14. Real ishda
- Xulosa
- Manbalar
Yandex Maps, Google Maps va MapLibre React'da: API kalit, geokoder, marshrut va narx
Qisqacha: Yandex Maps va Google Maps — tijoriy xizmatlar: xarita, manzil qidirish (geokoder) va marshrut beradi, lekin API kalit va shartnoma talab qiladi. Kalit brauzerda ochiq turadi — uni sir emas, cheklov himoya qiladi (sayt manzili, kunlik limit). MapLibre — ochiq kodli vektor xarita dvigateli, plitka provayderi bilan ishlaydi (masalan, kalitsiz OpenFreeMap). Eng ko'p xato — koordinata tartibi: Leaflet va Google
lat, lng, Yandex, MapLibre va GeoJSONlng, lat. Bu darsdagi Yandex va Google kodi ishga tushirilmagan: kurs uchun hisob va kalit ochilmadi — kod hujjat bo'yicha yozilgan.
Bu darsda
- Yandex Maps JS API 3 ni React'ga reactify bilan qanday ulashni bilasiz.
- Google Maps'ni @vis.gl/react-google-maps bilan, MapLibre'ni react-map-gl bilan ulash kodini o'qiysiz.
- API kalitni qanday cheklash va limitni qanday tejashni tushuntirasiz.
- Koordinatalarni bitta ichki formatda saqlab, har kutubxonaga to'g'ri tartibda berasiz.
- Kalitsiz yo'lni — xarita ilovasini havola bilan ochishni — qo'llaysiz.
Oldin bilishingiz kerak: Xaritalar I: Leaflet va OpenStreetMap, Vite III: env o'zgaruvchilar, Brauzer xavfsizlik modeli, debounce va throttle.
1. Nega bu kerak?
O'tgan darsda «Bahor» filiallarini Leaflet va OpenStreetMap bilan ko'rsatdik. Jasur aka xursand, lekin uchta yangi talab bor.
Birinchisi — manzil qidirish. Mehmon "Chilonzor 9-kvartal, 12-uy" deb yozadi, xarita o'sha uyni topishi kerak. Matndan koordinata topish — geokoder ishi.
Ikkinchisi — marshrut. "Uydan filialgacha qanday boraman, necha daqiqa?". Bu — yo'llar tarmog'ini biladigan xizmat.
Uchinchisi — tanish ko'rinish. Toshkentdagi ko'p odamlar telefonda Yandex Xarita yoki Google Maps ishlatadi. O'zbekiston uchun ko'cha va uy ma'lumotini ko'pchilik dasturchilar Yandex'da to'liqroq deb hisoblaydi. Bu — tajribadan kelgan gap, biz uni o'lchamadik. O'z shahringiz uchun ikkala xaritada bir xil manzillarni qidirib, solishtirib ko'ring.
Bularning hammasi tijoriy xizmat: kalit, limit, shartnoma. Hayotiy o'xshatish — elektr hisoblagichi. Kalit — hisoblagich raqami: kim ishlatsa, sizning hisobingizga yoziladi. Shuning uchun uni yashirish emas, "faqat mening uyimda ishlaydi" deb cheklash kerak.
Diqqat: Kurs uchun Yandex va Google'da hisob ochilmadi va kalit olinmadi. Bu darsdagi Yandex va Google kodi rasmiy hujjat bo'yicha yozilgan va ishga tushirilmagan. Kanon faqat Google kutubxonasining hajmini o'lchadi (+14.5 KB), MapLibre esa kalitsiz sinaldi.
2. Koordinata tartibi: eng ko'p uchraydigan xato
2.1 Kim qaysi tartibda
Bir nuqta — ikki son. Lekin kutubxonalar ularni turlicha kutadi:
| Kutubxona / format | Ko'rinishi | Tartib |
|---|---|---|
| Leaflet | [41.31, 69.28] |
lat, lng |
| Google Maps | { lat: 41.31, lng: 69.28 } |
nomli maydonlar |
| Yandex Maps 3 | [69.28, 41.31] |
lng, lat |
| MapLibre, GeoJSON | [69.28, 41.31] |
lng, lat |
| Yandex geokoder javobi | "69.28 41.31" (satr) |
lng, lat |
Yandex hujjatidagi misolda Moskva markazi [37.588144, 55.733842] deb yozilgan — avval uzoqlik (37), keyin kenglik (55). GeoJSON standarti (RFC 7946) ham [lng, lat] ni talab qiladi. Matematikadagi (x, y) ga o'xshaydi: x — sharq-g'arb, y — shimol-janub.
Tartibni adashtirsangiz, xato chiqmaydi. Toshkent [41.31, 69.28] → lng 41.31, lat 69.28 — bu Shimoliy Muz okeani. Marker jim-jit noto'g'ri joyga tushadi.
2.2 Bitta ichki format
Davo — ilova ichida bitta format ({ lat, lng } obyekti, nomli maydonlar) va har kutubxona uchun kichik o'giruvchi funksiya. Geokoder satrini ham shu yerda o'qiymiz. Javob — Yandex hujjatidagi tuzilma bo'yicha yasalgan soxta javob (haqiqiy so'rov kalit talab qiladi):
// ilova ichidagi yagona format
const branch = { lat: 41.364, lng: 69.287 };
const toLeaflet = (p) => [p.lat, p.lng];
const toGoogle = (p) => ({ lat: p.lat, lng: p.lng });
const toYandex = (p) => [p.lng, p.lat];
const toGeoJson = (p) => ({
type: "Point",
coordinates: [p.lng, p.lat],
});
console.log("Leaflet:", toLeaflet(branch));
console.log("Google:", toGoogle(branch));
console.log("Yandex:", toYandex(branch));
console.log("GeoJSON:", JSON.stringify(toGeoJson(branch)));
// Yandex geokoder javobi (soxta, hujjatdagi tuzilma bo'yicha)
const answer = {
response: {
GeoObjectCollection: {
featureMember: [
{
GeoObject: {
name: "Amir Temur xiyoboni",
Point: { pos: "69.279737 41.311151" },
},
},
],
},
},
};
function parseYandex(json) {
const first = json.response.GeoObjectCollection.featureMember[0];
if (!first) return null;
const [lng, lat] = first.GeoObject.Point.pos.split(" ").map(Number);
return { name: first.GeoObject.name, lat, lng };
}
console.log(parseYandex(answer));Konsolda:
Leaflet: [ 41.364, 69.287 ]
Google: { lat: 41.364, lng: 69.287 }
Yandex: [ 69.287, 41.364 ]
GeoJSON: {"type":"Point","coordinates":[69.287,41.364]}
{ name: 'Amir Temur xiyoboni', lat: 41.311151, lng: 69.279737 }parseYandex da destrukturlash tartibi — [lng, lat]. Bu yagona joyda to'g'ri yozilsa, ilovaning qolgan qismi tartib haqida o'ylamaydi.
Yandex hujjatining matni pos maydoni "longitude latitude" ekanini aytadi. Lekin o'sha sahifadagi Dubay misolida raqamlar teskari ko'rinadi ("25.197300 55.274243" — Dubayning kengligi 25). Hujjat ham xato qilishi mumkin. Shuning uchun birinchi haqiqiy javobni taniqli joy (masalan, Amir Temur xiyoboni) bilan tekshiring.
Tekshirib ko'ring: Kimdir Yandex xaritasiga
center: [41.31, 69.28]berdi. Xarita qayerni ko'rsatadi?
Javob
Yandex [lng, lat] kutadi: uzoqlik 41.31, kenglik 69.28. Kenglik 69 — Shimoliy qutb doirasidan ham shimolda, Rossiyaning Arktika qirg'og'i yoki Barens dengizi atrofi. Toshkent emas. Xato chiqmaydi — shuning uchun bunday xatoni test yoki taniqli nuqta bilan ushlash kerak.
3. API kalit: sir emas, cheklov
3.1 Kalit qanday ishlaydi
Xarita skripti kalit bilan yuklanadi: https://api-maps.yandex.ru/v3/?apikey=KALIT&lang=ru_RU. Brauzer bu manzilni ochadi — demak, kalit har kim ko'radigan joyda: sahifa kodi, Network paneli. Uni env o'zgaruvchiga yashirish ham yordam bermaydi: VITE_ bilan boshlangan qiymat build paytida JS faylga yoziladi.
sequenceDiagram
participant B as Brauzer (sizning sayt)
participant X as Xarita xizmati
participant H as Hisob va limit
B->>X: skript / plitka, apikey=K, Referer: sayt
X->>H: K kimniki? Referer ruxsatmi? limit qoldimi?
H-->>X: ha
X-->>B: xarita
Note over X,H: har so'rov — hisobingizgaDiagrammaning ikkinchi qadamiga qarang: xizmat kalitdan tashqari Referer (so'rov qaysi saytdan kelgani) ni ham tekshiradi — agar siz shunday sozlagan bo'lsangiz.
3.2 Kalitni cheklash
Yandex Developer kabinetida ham, Google Cloud Console'da ham kalitga cheklov qo'yiladi:
- Sayt manzili (HTTP Referer) —
https://example.com/*dan boshqa joyda kalit ishlamaydi. Kimdir kalitingizni ko'chirib, o'z saytiga qo'ysa — rad etiladi. - API cheklovi — kalit faqat kerakli xizmatga (masalan, faqat Maps JavaScript API) ishlaydi.
- Kunlik limit va byudjet ogohlantirishi — kutilmagan hisob kelmasin.
Brauzerdagi kalit va server kaliti — alohida. Geokoder yoki marshrutni serverdan chaqirsangiz, u kalit sir saqlanadi va brauzerga hech qachon chiqmaydi. Bu backend qismlarida (25-qismdan) yoziladi.
3.3 Narx va shartlar (2026-oktabr holati)
Raqamlar tez-tez o'zgaradi — loyiha boshlashdan oldin rasmiy sahifani o'qing.
- Google Maps Platform — 2025-yil 1-martdan oylik $200 kredit o'rniga har xizmatga (SKU) alohida bepul chegara keldi. Dynamic Maps (interaktiv veb-xarita) — "Essentials" toifasi, oyiga 10 000 bepul yuklash. Undan keyin — har 1 000 yuklash uchun to'lov: 100 000 tagacha $7, ko'paygan sari arzonlashadi (rasmiy "Pricing" sahifasi, 2026-10). Kalit olish uchun Google Cloud'da billing hisobi (to'lov kartasi) ochiladi.
- Yandex Maps API — bepul foydalanish shartlari bor, lekin cheklovli: loyiha ommaviy va bepul ochiq bo'lishi, ma'lumotni saqlamaslik, transportni real vaqtda kuzatmaslik. Yopiq tizim, monitoring yoki sotiladigan mahsulot uchun — tijoriy litsenziya. Tariflar sahifasida (yandex.ru/maps-api/tariffs, 2026-10) JavaScript API va Geokoder "bepul foydalanish shartlari bajarilsa — bepul" deb belgilangan; tijoriy JavaScript API litsenziyasi — yiliga 195 000 ₽ dan. Bepul kunlik chegara u sahifada aniq yozilmagan — amaldagi shartni yandex.ru/legal/maps_api da tekshiring.
- MapLibre — kutubxonaning o'zi bepul (BSD litsenziya). Pul plitka uchun: OpenFreeMap ochiq nusxasi kalitsiz va "ko'rishlar soniga cheklovsiz" deydi (xayriya hisobidan ishlaydi). MapTiler, Stadia kabi provayderlar — kalit va tarif bilan.
- Mapbox GL JS — 2-versiyadan yopiq litsenziya va access token. MapLibre aynan shu paytda, Mapbox GL JS 1-versiyasidan ochiq nusxa (fork) bo'lib chiqqan.
4. Yandex Maps JS API 3: reactify
4.1 Ulash
Yandex 3-versiyasi npm paket emas — skript <script> bilan yuklanadi. React uchun Yandex'ning o'zi @yandex/ymaps3-reactify modulini beradi: u xarita obyektlarini React komponentlariga aylantiradi. Hujjatdagi tartib:
<!-- index.html: kalit va til -->
<script
src="https://api-maps.yandex.ru/v3/?apikey=KALIT&lang=ru_RU"
></script>// lib/ymaps3.ts — hujjat bo'yicha, ishga tushirilmagan
import React from "react";
import ReactDom from "react-dom";
const [ymaps3React] = await Promise.all([
ymaps3.import("@yandex/ymaps3-reactify"),
ymaps3.ready,
]);
export const reactify = ymaps3React.reactify.bindTo(React, ReactDom);
export const {
YMap,
YMapDefaultSchemeLayer,
YMapDefaultFeaturesLayer,
YMapMarker,
} = reactify.module(ymaps3);ymaps3 — skript yaratgan global obyekt. ymaps3.ready — API to'liq yuklanganini kutadigan Promise. Top-level await modul darajasida ishlaydi (modul semantikasi) — bu fayl import qilinganda xarita tayyor bo'ladi.
Tur fayllari uchun Yandex @yandex/ymaps3-types paketini beradi (npm i -D), shunda ymaps3 global'i TypeScript'da taniladi.
4.2 Xarita va marker
import {
YMap,
YMapDefaultSchemeLayer,
YMapDefaultFeaturesLayer,
YMapMarker,
reactify,
} from "./lib/ymaps3";
// diqqat: [lng, lat]
const LOCATION = { center: [69.2797, 41.3111], zoom: 12 };
const YUNUSOBOD = [69.287, 41.364];
export function BranchMapYandex() {
return (
<div style={{ height: 320 }}>
<YMap location={reactify.useDefault(LOCATION)}>
<YMapDefaultSchemeLayer />
<YMapDefaultFeaturesLayer />
<YMapMarker coordinates={reactify.useDefault(YUNUSOBOD)}>
<button type="button">Yunusobod</button>
</YMapMarker>
</YMap>
</div>
);
}Uchta narsaga qarang:
- Ikki qatlam —
YMapDefaultSchemeLayer(xaritaning o'zi) vaYMapDefaultFeaturesLayer(markerlar shu qatlamga tushadi). Ikkinchisisiz marker ko'rinmaydi. - Marker ichi — oddiy JSX. Tugma, rasm, matn — har narsa. Leaflet'dagi
bindPopup(html)muammosi bu yerda yo'q: kontent React elementi. reactify.useDefault(...)— hujjat ogohlantiradi: reactify komponentlari boshqarilmaydi, xarita o'z holatini o'zi saqlaydi. Har render'da yangilocationobyekti bersangiz, xarita foydalanuvchi siljitgan joydan "sakrab" qaytadi.useDefaultqiymatni bir marta beradi — xuddidefaultValuekabi. Ikkinchi argument — bog'liqliklar massivi: u o'zgarsa, qiymat yangilanadi.
O'tgan darsdagi react-leaflet center tuzog'i bilan solishtiring: g'oya bir xil. Xarita kutubxonalari o'z ichki holatiga ega, React esa uni faqat boshlang'ich qiymat bilan boshqaradi.
4.3 SSR
Hujjatning Next.js misoli ochiq aytadi: reactify moduli server render'ni qo'llamaydi. Shuning uchun u "use client" komponentda, useEffect ichida yuklanadi va tayyor bo'lguncha hech narsa chizilmaydi. Leaflet dagi window is not defined saboqining o'zi.
5. Google Maps: @vis.gl/react-google-maps
Google'ning o'zi React kutubxonasi chiqarmaydi, lekin vis.gl jamoasining @vis.gl/react-google-maps paketini rasmiy hujjatlarda tavsiya qiladi. Kanon o'lchagan versiya — 1.10.1, hajmi +14.5 KB (xaritaning asosiy kodi Google serveridan keladi — bu raqamga kirmaydi).
import {
APIProvider,
Map,
AdvancedMarker,
InfoWindow,
useAdvancedMarkerRef,
} from "@vis.gl/react-google-maps";
const KEY = import.meta.env.VITE_GOOGLE_MAPS_KEY; // ochiq kalit!
function Branch() {
const [markerRef, marker] = useAdvancedMarkerRef();
return (
<>
<AdvancedMarker
position={{ lat: 41.364, lng: 69.287 }}
ref={markerRef}
/>
<InfoWindow anchor={marker}>Yunusobod, 9:00–23:00</InfoWindow>
</>
);
}
export function BranchMapGoogle() {
return (
<APIProvider apiKey={KEY}>
<Map
style={{ height: 320 }}
defaultCenter={{ lat: 41.3111, lng: 69.2797 }}
defaultZoom={12}
mapId="DEMO_MAP_ID"
>
<Branch />
</Map>
</APIProvider>
);
}APIProvider— Google skriptini kalit bilan yuklaydi, bolalarga kontekst beradi.defaultCenter,defaultZoom— nomidan ko'rinib turibdi: boshlang'ich qiymat. Boshqariladigan variant ham bor (center+onCameraChanged).AdvancedMarkerfaqatmapIdli xaritada ishlaydi (Google Cloud'dagi xarita uslubi).DEMO_MAP_ID— hujjatdagi sinov qiymati.
Geokoder va boshqa xizmatlar useMapsLibrary hook'i bilan, kerak bo'lganda yuklanadi:
import { useEffect, useMemo } from "react";
import { useMapsLibrary } from "@vis.gl/react-google-maps";
function useGeocode(address: string) {
const lib = useMapsLibrary("geocoding"); // avval null
const geocoder = useMemo(() => lib && new lib.Geocoder(), [lib]);
useEffect(() => {
if (!geocoder || !address) return;
void geocoder.geocode({ address }).then(({ results }) => {
const loc = results[0]?.geometry.location;
console.log(loc?.lat(), loc?.lng());
});
}, [geocoder, address]);
}Har geocode chaqiruvi — pullik so'rov. Har harf yozilganda chaqirsangiz, "Chilonzor" so'zi 9 ta so'rovga tushadi. Keyingi bo'limda buni tejaymiz.
6. Limitni tejash: kesh va debounce
Geokoder so'rovi qimmat va limitli. Ikki oddiy usul:
- Kesh — bir xil manzilni ikkinchi marta so'ramaslik. Manzilni normallashtiramiz (bo'sh joy, katta-kichik harf), keyin
Mapga saqlaymiz. - Debounce — foydalanuvchi yozishni to'xtatgandan keyingina so'rash (debounce va throttle).
Kesh g'oyasini soxta geokoder bilan sinab ko'ramiz — u har chaqiruvni sanaydi:
let calls = 0;
// soxta geokoder: haqiqiysi — pullik tarmoq so'rovi
async function geocodeRemote(query) {
calls++;
return { query, lat: 41.2756, lng: 69.2034 };
}
const cache = new Map();
async function geocode(query) {
const key = query.trim().toLowerCase().replace(/\s+/g, " ");
if (!cache.has(key)) cache.set(key, geocodeRemote(key));
return cache.get(key);
}
const inputs = ["Chilonzor", "chilonzor ", "CHILONZOR", " Chilonzor"];
await Promise.all(inputs.map(geocode));
console.log("so'rovlar:", inputs.length, "→ tarmoqqa:", calls);Konsolda:
so'rovlar: 4 → tarmoqqa: 1E'tibor bering: keshga natija emas, Promise saqlanadi. To'rt so'rov bir paytda kelsa ham, birinchisi boshlagan so'rovni qolganlari kutadi — tarmoqqa bitta boradi. Natijani saqlasak, birinchi javob kelguncha qolgan uchtasi ham tarmoqqa ketardi.
Google va Yandex shartlari javobni uzoq saqlashni cheklaydi. Brauzer xotirasidagi qisqa kesh (sahifa ochiq turgan paytda) — bir sessiya ichidagi takrorni yo'qotadi. Uzoq muddatli kesh kerak bo'lsa, avval shartnomani o'qing.
Tekshirib ko'ring: Debounce'ni 300 ms ga sozladik. Foydalanuvchi "Chilonzor" ni sekin, har harfdan keyin yarim soniya o'ylab yozdi. Nechta so'rov ketadi va nima qilish mumkin?
Javob
To'qqizta: har pauza 300 ms dan uzun, debounce har harfdan keyin "yozish tugadi" deb hisoblaydi. Yechimlar: kamida 3 harf bo'lganda qidirish, debounce'ni 500 ms ga oshirish va kesh (orqaga o'chirib qayta yozilgan so'z tarmoqqa bormaydi). Eng tejamkori — taklif (autocomplete) o'rniga "Qidirish" tugmasi: bitta so'rov.
7. MapLibre: vektor xarita, o'z provayderingiz bilan
7.1 Raster va vektor plitka
Leaflet plitkalari — tayyor rasm (PNG). Bu — raster plitka. Vektor plitka esa rasm emas, ma'lumot: "bu yerda yo'l, bu yerda bino, nomi shu". Brauzer uni o'zi chizadi (WebGL bilan). Natija: silliq zoom, xaritani burish va qiyshaytirish (3D ko'rinish), uslubni (ranglar, til) brauzerda almashtirish.
MapLibre GL JS — shunday vektor dvigatel. React o'rami — react-map-gl (vis.gl jamoasi), 8-versiyadan MapLibre uchun alohida kirish nuqtasi bor:
import Map, {
Marker,
NavigationControl,
} from "react-map-gl/maplibre";
import { setWorkerUrl } from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
// Vite: ishchi (worker) faylini o'zimiz beramiz
import workerUrl from
"maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
setWorkerUrl(workerUrl);
export function BranchMapLibre() {
return (
<Map
initialViewState={{
longitude: 69.2797,
latitude: 41.3111,
zoom: 11,
}}
style={{ height: 320 }}
mapStyle="https://tiles.openfreemap.org/styles/liberty"
>
<NavigationControl position="top-right" />
<Marker longitude={69.287} latitude={41.364}>
<button type="button">Yunusobod</button>
</Marker>
</Map>
);
}mapStyle— uslub fayli (JSON): qaysi plitka serveridan, qanday ranglar bilan. OpenFreeMap — kalitsiz, ro'yxatdan o'tishsiz (o'z saytida shunday yozilgan).initialViewState— yana "boshlang'ich qiymat". Boshqariladigan rejim —viewState+onMove.setWorkerUrl— MapLibre og'ir hisoblarni Web Worker'da qiladi (Web Worker). MapLibre hujjatida Vite uchun aynan shu qator (?worker&url) bor: oddiy?urlbilan build'da ishchi o'z qo'shni faylini topa olmaydi va "vektor plitkalar yuklanmaydi". Bu qatorni biz sinamadik — hujjat bo'yicha.
7.2 Kanon tajribasi nimani ko'rsatdi
Kanon MapLibre 6.13.0 + react-map-gl 8.1.3 ni demo uslub (demotiles.maplibre.org) bilan, kalitsiz sinadi:
xarita-maplibre JS 358220 (+ 283.7 KB) CSS 10382
CSP: require-trusted-types-for×3, connect-src×1
xato: … 'TrustedScriptURL' … ; Failed to construct 'Worker' …
CSP'siz: tashqi demotiles.maplibre.org
CSP'siz xato: Error: Worker failed to load. Check that the worker URL is correct.Uch saboq:
- Hajm — +283.7 KB JS va +10.4 KB CSS. Bu o'lchangan kutubxonalar ichida eng og'irlaridan. Faqat xarita sahifasida kech yuklang.
- Trusted Types —
new Worker(url)ham TT nazoratida: oddiy satr emas,TrustedScriptURLkerak. Uslubni boshqa saytdan olish uchun esaconnect-srcga uning manzili. - CSP'siz ham konsolda "Worker failed to load" chiqdi. Tajribada
setWorkerUrlsozlanmagan edi — yuqoridagi hujjat qatori aynan shu holat uchun. Plitkalar chizilganini tajriba tekshirmagan, shuning uchun "ishladi" deb aytmaymiz.
8. Google va Yandex: CSP va maxfiylik narxi
Tashqi xarita — tashqi skript. U sizning sahifangizda sizning huquqingiz bilan ishlaydi (Frontend xavfsizligi).
CSP. Google'ning rasmiy CSP qo'llanmasi nonce'li qat'iy siyosatni tavsiya qiladi. Uning namunasida script-src da 'unsafe-eval' va blob:, worker-src blob:, img-src va connect-src da *.googleapis.com, *.gstatic.com, frame-src *.google.com bor. vazifalar siyosati (script-src 'self', nonce yo'q, unsafe-eval yo'q) bilan bu to'g'ridan-to'g'ri sig'maydi. Trusted Types haqida qo'llanma umuman gapirmaydi. Yandex skriptini kanon o'lchamadi.
Maxfiylik. Xarita ochilishi bilan foydalanuvchi brauzeri Google yoki Yandex serveriga so'rov yuboradi: IP manzil, sahifa manzili (Referer), qurilma ma'lumoti. Joylashuv tugmasi bo'lsa — koordinata ham. Maxfiylik siyosatingizda buni yozing. Agar xarita sahifaning asosiy qismi bo'lmasa — "Xaritani ko'rsatish" tugmasi bilan, foydalanuvchi so'raganda yuklang.
9. Kalitsiz yo'l: xarita ilovasini havola bilan ochish
Ko'p saytga to'liq xarita kerak emas. "Filial qayerda va qanday boraman" — telefondagi xarita ilovasi buni yaxshiroq qiladi. Yandex, Google va OSM manzil (URL) orqali nuqta ochishni qo'llaydi — kalitsiz, to'lovsiz, skriptsiz:
const BRANCHES = [
{ name: "Yunusobod", lat: 41.364, lng: 69.287 },
{ name: "Chilonzor", lat: 41.2756, lng: 69.2034 },
];
// tartib: Yandex — lng,lat; Google va OSM — lat,lng
function mapLinks({ lat, lng }) {
return [
["Yandex", `https://yandex.uz/maps/?pt=${lng},${lat}&z=16&l=map`],
[
"Google",
`https://www.google.com/maps/search/?api=1&query=${lat},${lng}`,
],
[
"OSM",
`https://www.openstreetmap.org/?mlat=${lat}&mlon=${lng}` +
`#map=16/${lat}/${lng}`,
],
];
}
export default function App() {
console.log(mapLinks(BRANCHES[0])[0][1]);
return (
<ul>
{BRANCHES.map((b) => (
<li key={b.name}>
{b.name}:{" "}
{mapLinks(b).map(([label, href]) => (
<a key={label} href={href} target="_blank" rel="noopener">
{label}{" "}
</a>
))}
</li>
))}
</ul>
);
}Konsolda:
https://yandex.uz/maps/?pt=69.287,41.364&z=16&l=mapEkranda:
Yunusobod: Yandex Google OSM
Chilonzor: Yandex Google OSMHavolani bosing — xarita yangi tabda ochiladi (natija oynasi havolani tashqariga ochishga ruxsat bersa). Telefonda Yandex Xarita yoki Google Maps ilovasi o'rnatilgan bo'lsa, odatda ilova ochiladi. Bu yerda ham koordinata tartibi farq qiladi — Yandex'ning pt parametri lng,lat. Google'ning "Maps URLs" usuli hujjatda kalitsiz deb yozilgan.
Narxi nolga yaqin: skript yo'q, CSP o'zgarmaydi, foydalanuvchi bosmaguncha hech qanday so'rov yo'q. Ko'p hollarda filiallar ro'yxati + shu havolalar + o'tgan darsdagi Leaflet xaritasi yetarli.
10. Marshrut va geokoder: qayerda ishlaydi
Marshrut (routing) — yo'llar grafida eng qisqa yo'l (Dijkstra kabi algoritmlar). Har xizmat buni alohida, alohida narx bilan beradi:
| Xizmat | Marshrut | Geokoder |
|---|---|---|
| Routes API | Geocoding API | |
| Yandex | Router API (tijoriy) | HTTP Geocoder (geocode-maps.yandex.ru/v1/) |
| Ochiq | OSRM, GraphHopper, Valhalla (o'z serveringizda) | Nominatim (OSM; o'z siyosati bor) |
Frontend vazifasi — natijani ko'rsatish: marshrut chizig'i (GeoJSON LineString), masofa va vaqt. Hisoblash — server yoki xizmatda. Ochiq yechimlarning ommaviy demo serverlari ham foydalanish siyosatiga ega — production uchun o'z serveringiz.
11. Hujumchi nigohi
Kalitingiz sahifa kodida ochiq. Hujumchi nima qila oladi?
- Kalitni o'g'irlash. Boshqa saytga qo'yadi — xarita yuklanishlari sizning hisobingizga. Himoya: HTTP Referer cheklovi. Lekin Referer'ni brauzerdan tashqaridagi skript soxtalashtira oladi. Shuning uchun qo'shimcha: API cheklovi (faqat Maps JavaScript API) va kunlik limit.
- Limitni tugatish. Bot geokoderingizni minglab marta chaqiradi — kunlik limit tugaydi, haqiqiy mehmonlar xaritasiz qoladi. Himoya: geokoder so'rovlarini o'z serveringiz orqali o'tkazish, so'rovlar chegarasi (rate limit) va kesh.
- Server kalitini frontendga qo'yish. Cheklovsiz "server" kalit JS faylga tushsa — u har qanday API'ni, har qanday hajmda chaqira oladi. Qoida: brauzerga faqat cheklangan "brauzer" kaliti chiqadi.
Kalit o'g'irlanganini sezsangiz — kabinetda yangisini yarating va eskisini o'chiring. Kod tarixida (git) qolgan kalit ham o'g'irlangan hisoblanadi.
12. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| marker okeanda yoki Arktikada | lat/lng tartibi adashgan |
bitta ichki format + o'giruvchi funksiya |
| Yandex markeri ko'rinmaydi | YMapDefaultFeaturesLayer qo'shilmagan |
ikkala standart qatlam |
| Yandex xarita siljitilgach "sakraydi" | har render'da yangi location |
reactify.useDefault |
Google: AdvancedMarker chizilmaydi |
mapId yo'q |
xaritaga mapId |
| Google xaritasi "For development purposes only" | kalit yoki billing sozlanmagan | Cloud Console'da billing va kalit |
| geokoder hisobi kutilmaganda katta | har harfda so'rov | kesh, debounce, kamida 3 harf |
MapLibre: Worker failed to load |
ishchi fayl manzili yo'q | setWorkerUrl(…?worker&url) |
CSP: TrustedScriptURL |
Worker yoki tashqi skript TT'da | TT siyosati yoki boshqa yechim |
| kalit boshqa saytda ishlatilmoqda | Referer cheklovi yo'q | kalitni cheklang, almashtiring |
13. Mashqlar
Mashqlar kurs/mashqlar/21/07-xaritalar-ii/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): bo'sh joylarni to'ldiring
- GeoJSON
coordinatesda birinchi son: - Yandex reactify'da prop'ni bir marta beruvchi funksiya:
reactify. - Google
AdvancedMarkeruchun xaritaga kerak prop: - Kalitni boshqa saytda ishlatishdan himoya qiluvchi cheklov: HTTP
- Manzildan koordinata topadigan xizmat:
Yechim
- lng — GeoJSON (RFC 7946):
[uzoqlik, kenglik]. - useDefault — reactify komponentlari boshqarilmaydi, qiymat bir marta beriladi.
- mapId — AdvancedMarker faqat bulutli uslubli xaritada.
- Referer — so'rov qaysi saytdan kelgani; kabinetda ruxsat etilgan manzillar ro'yxati.
- geokoder — matn → koordinata (teskarisi — teskari geokodlash).
2-mashq (o'rta): GeoJSON'dan markerlar ro'yxati
Server filiallarni GeoJSON FeatureCollection ko'rinishida beradi (koordinatalar [lng, lat]):
const geo = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: { name: "Sergeli" },
geometry: { type: "Point", coordinates: [69.219, 41.227] },
},
{
type: "Feature",
properties: { name: "Yunusobod" },
geometry: { type: "Point", coordinates: [69.287, 41.364] },
},
],
};Komponent yozing: har filial uchun <li> — Sergeli: 41.227, 69.219 (lat, lng — Leaflet tartibida) va yonida Yandex havolasi (pt=lng,lat). Ro'yxat shimoldan janubga tartiblangan bo'lsin (kenglik kamayib boradi).
Ishora: massiv destructuring — const [lng, lat] = f.geometry.coordinates, tartiblash — toSorted.
Yechim
const geo = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: { name: "Sergeli" },
geometry: { type: "Point", coordinates: [69.219, 41.227] },
},
{
type: "Feature",
properties: { name: "Yunusobod" },
geometry: { type: "Point", coordinates: [69.287, 41.364] },
},
],
};
export default function App() {
const points = geo.features
.map((f) => {
const [lng, lat] = f.geometry.coordinates;
return { name: f.properties.name, lat, lng };
})
.toSorted((a, b) => b.lat - a.lat);
return (
<ul>
{points.map((p) => (
<li key={p.name}>
{`${p.name}: ${p.lat}, ${p.lng} `}
<a href={`https://yandex.uz/maps/?pt=${p.lng},${p.lat}`}>
Yandex
</a>
</li>
))}
</ul>
);
}Ekranda:
Yunusobod: 41.364, 69.287 Yandex
Sergeli: 41.227, 69.219 YandexDestrukturlash bitta joyda [lng, lat] ni nomli maydonlarga aylantirdi — qolgan kod faqat p.lat, p.lng bilan ishlaydi. Yunusobod shimolda 41.364-bob, shuning uchun birinchi.
3-mashq (qiyin): debounce + kesh
createSearch(remote, wait) funksiyasini yozing. U search(query) ni qaytarsin: oxirgi chaqiruvdan wait ms o'tgachgina remote(query) ni chaqiradi (debounce), bir xil normallashtirilgan so'rovni ikkinchi marta yubormaydi (kesh). Sinov: "C", "Ch", "Chi" ketma-ket (har biri orasida 50 ms), keyin 400 ms dan keyin yana "chi". wait — 300. Tarmoqqa nechta so'rov ketdi?
Ishora: setTimeout/clearTimeout (taymerlar), kesh — Set yoki Map.
Yechim
function createSearch(remote, wait) {
let timer;
const seen = new Set();
return function search(query) {
clearTimeout(timer);
timer = setTimeout(() => {
const key = query.trim().toLowerCase();
if (seen.has(key)) return;
seen.add(key);
remote(key);
}, wait);
};
}
const sent = [];
const search = createSearch((q) => sent.push(q), 300);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
search("C");
await sleep(50);
search("Ch");
await sleep(50);
search("Chi");
await sleep(400);
search("chi");
await sleep(400);
console.log("tarmoqqa:", sent);Konsolda:
tarmoqqa: [ 'chi' ]Uch harf tez yozildi — debounce faqat oxirgisini ("Chi") yubordi. 400 ms dan keyingi "chi" normallashtirilgach keshda bor edi — tarmoqqa bormadi. To'rt chaqiruv → bitta so'rov. Haqiqiy kodda keshga natijani ham saqlang, shunda keshdan qaytgan so'rov ham ekranga javob beradi.
4-mashq: tajriba qadami (ixtiyoriy)
Agar o'zingizda Yandex yoki Google kaliti bo'lsa (o'zingiz ochasiz, kurs talab qilmaydi): alohida Vite loyihada (kurs/tajriba/xarita-ii/) shu darsdagi komponentlardan birini ishga tushiring. Kalitga sayt manzili cheklovini qo'ying va boshqa portdan (masalan, localhost:5174) ochib ko'ring. Kalit yo'q bo'lsa — MapLibre + OpenFreeMap variantini qiling.
Yechim
Tekshiruv ro'yxati:
- Kalit
.env.localda (VITE_…),.gitignoreda — git'ga tushmaydi. Lekin build'dan keyin u JS faylda ochiq — buni DevTools'da qidirib ko'ring. - Referer cheklovi
http://localhost:5173/*bo'lsa, 5174 portdan xarita xato beradi (konsolda xizmatning rad javobi). - Koordinata tartibi: Yandex —
[lng, lat], Google —{ lat, lng }. - MapLibre:
setWorkerUrlqatorisiz build'da xarita bo'sh qolishi mumkin; qator bilan — plitkalar chiziladi.npm run buildda MapLibre chunk'i kanondagidek ~280 KB gzip atrofida.
14. Real ishda
- Yetkazib berish, taksi, logistika — O'zbekistonda ko'pincha Yandex: manzil qidirish va marshrut. Tijoriy litsenziya — shartnoma bilan.
- Xalqaro mahsulotlar — Google Maps, ayniqsa Places (joy qidirish, sharhlar) kerak bo'lsa.
- O'z dizaynli, ko'p ma'lumotli xaritalar (ko'chmas mulk, statistika) — MapLibre + o'z yoki tijoriy vektor plitkalar.
- Oddiy "biz qayerdamiz" sahifalari — havola yoki statik rasm: skript va kalitsiz.
- Intervyu savollari: "API kalitni frontendda qanday himoyalaysiz?", "lat va lng tartibi qayerda farq qiladi?", "geokoder xarajatini qanday kamaytirasiz?", "raster va vektor plitka farqi?".
Xulosa
- Yandex, Google — kalit, limit, shartnoma; kalit brauzerda ochiq, himoya — Referer va API cheklovi, kunlik limit. Server kaliti brauzerga chiqmaydi.
- Koordinatalar: Leaflet
[lat, lng], Google{ lat, lng }, Yandex, MapLibre, GeoJSON[lng, lat]— ilova ichida bitta format. - Yandex 3: skript +
@yandex/ymaps3-reactify,reactify.useDefault, ikki standart qatlam; SSR yo'q. - Google:
@vis.gl/react-google-maps—APIProvider,Map(defaultCenter),AdvancedMarker(mapId),useMapsLibrary. - MapLibre: vektor plitkalar,
react-map-gl/maplibre, Vite'dasetWorkerUrl; kanonda +283.7 KB va Trusted Types'da Worker to'sildi. - Geokoderni kesh (Promise'ni saqlang) va debounce bilan tejang; ko'p hollarda kalitsiz havola yetarli.
Keyingi dars: Markdown render qilish — vazifalar dagi vazifaga izoh qo'shamiz: react-markdown, GFM, xavfsizlik va kech yuklash.
Manbalar
- Yandex Maps JS API 3: "Connecting via reactify", "Integration with Next.js", Geocoder API "Response format" — yandex.com/maps-api/docs; foydalanish shartlari — yandex.ru/legal/maps_api
- vis.gl: "React Google Maps" (
APIProvider,AdvancedMarker,useMapsLibrary) — visgl.github.io/react-google-maps - Google Maps Platform: "Pricing overview" (2025-03-01 o'zgarishi), "Content Security Policy guide", "Maps URLs" — developers.google.com/maps
- MapLibre GL JS: "Installation: Vite" (
setWorkerUrl), "CSP directives" — maplibre.org; react-map-gl 8: "Get started with MapLibre" — visgl.github.io/react-map-gl - OpenFreeMap: "Quick start" — openfreemap.org
- RFC 7946: The GeoJSON Format (koordinata tartibi)
- Kanon:
natijalar/tajriba/kutubxonalar-21.txt,tajriba/kutubxonalar/src/k/xarita-google.tsx,xarita-maplibre.tsx(2026-10-17)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!