v12: Nominatim first, Overpass districts, area fix

This commit is contained in:
Dauren777 2026-06-19 06:51:27 +00:00
parent 2dee3e51bc
commit 5928f7faad

View File

@ -167,24 +167,77 @@ function onRegionChange(){
if(!region){document.getElementById('locStatus').textContent='';return;} if(!region){document.getElementById('locStatus').textContent='';return;}
map.setView(region.center,9); map.setView(region.center,9);
const st=document.getElementById('locStatus'); const st=document.getElementById('locStatus');
st.textContent='⏳ поиск региона...'; st.textContent='⏳ '+name+'...';
// ШАГ 1: через Nominatim ищем ТОЛЬКО relation административной границы // Пробуем найти регион через Nominatim (надёжнее всего)
const q='[out:json];(rel["name:ru"="'+name+' область"]["boundary"="administrative"];rel["name"="'+name+' область"]["boundary"="administrative"];);out tags id;'; fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(name+' область')+'&countrycodes=kz&limit=3&type=administrative')
fetch('https://overpass-api.de/api/interpreter?data='+encodeURIComponent(q))
.then(r=>r.json()) .then(r=>r.json())
.then(list=>{
if(!list.length)return fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(name+' облысы')+'&countrycodes=kz&limit=3&type=administrative').then(r=>r.json());
return list;
})
.then(list=>{
if(!list||!list.length||!list[0].osm_id){st.textContent='⚠ регион не найден в Nominatim';return;}
const item=list[0];
regionRelId=item.osm_id;
st.textContent='⏳ районы '+name+'...';
// Ищем районы через Overpass: area(3600000000+osm_id)
const q='[out:json][timeout:20];area('+(3600000000+item.osm_id)+')->.a;(rel(area.a)["boundary"="administrative"]["admin_level"~"6|7|8"];);out tags id;';
return fetch('https://overpass-api.de/api/interpreter?data='+encodeURIComponent(q));
})
.then(r=>r&&r.json())
.then(data=>{ .then(data=>{
if(!data||!data.elements||!data.elements.length)throw new Error('регион не найден в OSM'); if(!data||!data.elements||!data.elements.length){
st.textContent='⚠ районы не найдены через OSM';
// fallback: через Nominatim
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent('районы '+name+' области')+'&countrycodes=kz&limit=30')
.then(r=>r.json()).then(nom=>{
dsel.innerHTML='<option value="">— все —</option>';
const seen=new Set();
nom.forEach(item=>{
let n=item.display_name.split(',')[0].trim();
if(!n||seen.has(n)||n===name)return;seen.add(n);
const o=document.createElement('option');
o.value=n;o.textContent=n;
dsel.appendChild(o);
districtList.push({name:n,osm_id:item.osm_id||0});
});
st.textContent='✅ Nominatim: '+seen.size;
});
return;
}
const seen=new Map();
data.elements.forEach(el=>{
if(!el.tags||!el.tags.name)return;
let clean=el.tags.name.replace(/\s*ауданы$/i,'').replace(/\s*районы$/i,'').replace(/\s*район$/i,'').trim();
if(clean&&!seen.has(clean))seen.set(clean,el.id);
});
dsel.innerHTML='<option value="">— все —</option>';
const sorted=[...seen.keys()].sort();
sorted.forEach(n=>{
const o=document.createElement('option');
o.value=n;o.textContent=n;
dsel.appendChild(o);
districtList.push({name:n,osm_id:seen.get(n)});
});
st.textContent='✅ '+sorted.length+' районов из OSM';
})
.catch(e=>{
st.textContent='⚠ ошибка: '+e.message;
});
}
const rel=data.elements[0]; const rel=data.elements[0];
regionRelId=rel.id; regionRelId=rel.id;
st.textContent='⏳ районы...'; st.textContent='✅ регион: '+rel.id+', ищу районы...';
// ШАГ 2: ищем районы (admin_level=6,7) внутри региона // ШАГ 2: районы (admin_level=6,7) внутри rel
const areaId=3600000000+rel.id; const q2='[out:json][timeout:20];area('+rel.id+')->.a;(rel(area.a)["boundary"="administrative"]["admin_level"~"6|7"];);out tags id;';
const q2='[out:json];area('+areaId+')->.a;(rel(area.a)["boundary"="administrative"]["admin_level"~"6|7"];);out tags id;';
return fetch('https://overpass-api.de/api/interpreter?data='+encodeURIComponent(q2)); return fetch('https://overpass-api.de/api/interpreter?data='+encodeURIComponent(q2));
}) })
.then(r=>r.json()) .then(r=>r&&r.json())
.then(data=>{ .then(data=>{
if(!data||!data.elements||!data.elements.length)throw new Error('районы не найдены'); if(!data||!data.elements||!data.elements.length){
st.textContent='⚠ районы не найдены через OSM, пробую Nominatim...';
return fetchNominatimDistricts(name);
}
const seen=new Map(); const seen=new Map();
data.elements.forEach(el=>{ data.elements.forEach(el=>{
if(!el.tags||!el.tags.name)return; if(!el.tags||!el.tags.name)return;
@ -202,34 +255,12 @@ function onRegionChange(){
st.textContent='✅ '+sorted.length+' районов'; st.textContent='✅ '+sorted.length+' районов';
}) })
.catch(e=>{ .catch(e=>{
dsel.innerHTML='<option value="">— ошибка —</option>'; st.textContent='⚠ ошибка OSM: '+e.message+', fallback...';
st.textContent='⚠ районы: '+e.message;
// fallback: поищем через Nominatim
fetchNominatimDistricts(name); fetchNominatimDistricts(name);
}); });
} }
function fetchNominatimDistricts(regionName){
const st=document.getElementById('locStatus');
st.textContent='⏳ районы через Nominatim...';
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(regionName+' район')+'&countrycodes=kz&limit=25')
.then(r=>r.json())
.then(data=>{
const dsel=document.getElementById('districtSelect');
dsel.innerHTML='<option value="">— все —</option>';
if(!data||!data.length){st.textContent='⚠ районы не найдены';return;}
const seen=new Set();
data.forEach(item=>{
let n=item.display_name.split(',')[0].trim();
if(!n||seen.has(n))return;seen.add(n);
const o=document.createElement('option');
o.value=n;o.textContent=n;
dsel.appendChild(o);
districtList.push({name:n,osm_id:item.osm_id});
});
st.textContent='✅ через Nominatim: '+seen.size;
});
}
function onDistrictSelect(){ function onDistrictSelect(){
const dname=document.getElementById('districtSelect').value; const dname=document.getElementById('districtSelect').value;