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;}
map.setView(region.center,9);
const st=document.getElementById('locStatus');
st.textContent='⏳ поиск региона...';
// ШАГ 1: через Nominatim ищем ТОЛЬКО relation административной границы
const q='[out:json];(rel["name:ru"="'+name+' область"]["boundary"="administrative"];rel["name"="'+name+' область"]["boundary"="administrative"];);out tags id;';
fetch('https://overpass-api.de/api/interpreter?data='+encodeURIComponent(q))
st.textContent='⏳ '+name+'...';
// Пробуем найти регион через Nominatim (надёжнее всего)
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(name+' область')+'&countrycodes=kz&limit=3&type=administrative')
.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=>{
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];
regionRelId=rel.id;
st.textContent='⏳ районы...';
// ШАГ 2: ищем районы (admin_level=6,7) внутри региона
const areaId=3600000000+rel.id;
const q2='[out:json];area('+areaId+')->.a;(rel(area.a)["boundary"="administrative"]["admin_level"~"6|7"];);out tags id;';
st.textContent='✅ регион: '+rel.id+', ищу районы...';
// ШАГ 2: районы (admin_level=6,7) внутри rel
const q2='[out:json][timeout:20];area('+rel.id+')->.a;(rel(area.a)["boundary"="administrative"]["admin_level"~"6|7"];);out tags id;';
return fetch('https://overpass-api.de/api/interpreter?data='+encodeURIComponent(q2));
})
.then(r=>r.json())
.then(r=>r&&r.json())
.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();
data.elements.forEach(el=>{
if(!el.tags||!el.tags.name)return;
@ -202,34 +255,12 @@ function onRegionChange(){
st.textContent='✅ '+sorted.length+' районов';
})
.catch(e=>{
dsel.innerHTML='<option value="">— ошибка —</option>';
st.textContent='⚠ районы: '+e.message;
// fallback: поищем через Nominatim
st.textContent='⚠ ошибка OSM: '+e.message+', fallback...';
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(){
const dname=document.getElementById('districtSelect').value;