v13: pure Nominatim for districts/villages
This commit is contained in:
parent
1d55642858
commit
823ec856d9
125
index.html
125
index.html
@ -163,48 +163,103 @@ function onRegionChange(){
|
|||||||
const vsel=document.getElementById('villageSelect');
|
const vsel=document.getElementById('villageSelect');
|
||||||
dsel.innerHTML='<option value="">— загрузка —</option>';
|
dsel.innerHTML='<option value="">— загрузка —</option>';
|
||||||
vsel.innerHTML='<option value="">— выберите район —</option>';
|
vsel.innerHTML='<option value="">— выберите район —</option>';
|
||||||
districtList=[];regionRelId=null;
|
districtList=[];
|
||||||
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='⏳ '+name+'...';
|
st.textContent='⏳ районы '+name+'...';
|
||||||
// Пробуем найти регион через Nominatim (надёжнее всего)
|
// Ищем районы через Nominatim
|
||||||
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(name+' область')+'&countrycodes=kz&limit=3&type=administrative')
|
const queries=[
|
||||||
|
'районы '+name+' области',
|
||||||
|
'районы '+name+' облысы',
|
||||||
|
name+' район',
|
||||||
|
name+' аудан'
|
||||||
|
];
|
||||||
|
let done=false;
|
||||||
|
for(const q of queries){
|
||||||
|
if(done)break;
|
||||||
|
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(q)+'&countrycodes=kz&limit=30&type=administrative')
|
||||||
|
.then(r=>r.json())
|
||||||
|
.then(data=>{
|
||||||
|
if(done||!data||!data.length)return;
|
||||||
|
done=true;
|
||||||
|
const seen=new Set();
|
||||||
|
dsel.innerHTML='<option value="">— все —</option>';
|
||||||
|
data.forEach(item=>{
|
||||||
|
let n=item.display_name.split(',')[0].trim();
|
||||||
|
if(!n||seen.has(n)||n===name||n.toLowerCase().includes('город'))return;
|
||||||
|
seen.add(n);
|
||||||
|
const o=document.createElement('option');
|
||||||
|
o.value=n;o.textContent=n;
|
||||||
|
dsel.appendChild(o);
|
||||||
|
districtList.push({name:n,lat:item.lat,lon:item.lon});
|
||||||
|
});
|
||||||
|
st.textContent='✅ '+seen.size+' районов';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// fallback если ничего не нашли
|
||||||
|
setTimeout(()=>{
|
||||||
|
if(!done){
|
||||||
|
dsel.innerHTML='<option value="">— введите название района —</option>';
|
||||||
|
st.textContent='⚠ введите район вручную';
|
||||||
|
}
|
||||||
|
},3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDistrictSelect(){
|
||||||
|
const dname=document.getElementById('districtSelect').value;
|
||||||
|
const vsel=document.getElementById('villageSelect');
|
||||||
|
vsel.innerHTML='<option value="">⏳ сёла...</option>';
|
||||||
|
if(!dname||!districtList.length){
|
||||||
|
vsel.innerHTML='<option value="">— выберите район —</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dist=districtList.find(d=>d.name===dname);
|
||||||
|
if(!dist){
|
||||||
|
vsel.innerHTML='<option value="">— ошибка —</option>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
st.textContent='⏳ сёла '+dname+'...';
|
||||||
|
// Ищем сёла через Nominatim
|
||||||
|
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent(dname+' район село')+'&countrycodes=kz&limit=50')
|
||||||
.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){
|
vsel.innerHTML='<option value="">— выберите село —</option>';
|
||||||
st.textContent='⚠ районы не найдены через OSM';
|
if(!data||!data.length){
|
||||||
// fallback: через Nominatim
|
vsel.innerHTML='<option value="">— сёла не найдены —</option>';
|
||||||
fetch('https://nominatim.openstreetmap.org/search?format=json&q='+encodeURIComponent('районы '+name+' области')+'&countrycodes=kz&limit=30')
|
st.textContent='⚠ сёла не найдены';
|
||||||
.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;
|
return;
|
||||||
}
|
}
|
||||||
|
const villages=[];
|
||||||
|
data.forEach(item=>{
|
||||||
|
if(item.type==='village'||item.type==='hamlet'||item.type==='town'||item.type==='settlement'){
|
||||||
|
villages.push({name:item.display_name.split(',')[0].trim(),lat:item.lat,lon:item.lon});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
villages.sort((a,b)=>a.name.localeCompare(b.name,'ru'));
|
||||||
|
villages.forEach(v=>{
|
||||||
|
const o=document.createElement('option');
|
||||||
|
o.value=v.name;o.dataset.lat=v.lat;o.dataset.lon=v.lon;o.textContent=v.name;
|
||||||
|
vsel.appendChild(o);
|
||||||
|
});
|
||||||
|
st.textContent='✅ '+villages.length+' сёл';
|
||||||
|
})
|
||||||
|
.catch(()=>{
|
||||||
|
vsel.innerHTML='<option value="">— ошибка —</option>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVillageSelect(){
|
||||||
|
const vsel=document.getElementById('villageSelect');
|
||||||
|
const opt=vsel.options[vsel.selectedIndex];
|
||||||
|
if(!opt||!opt.dataset.lat)return;
|
||||||
|
const lat=parseFloat(opt.dataset.lat),lon=parseFloat(opt.dataset.lon);
|
||||||
|
if(!isNaN(lat)&&!isNaN(lon)){
|
||||||
|
map.setView([lat,lon],16);
|
||||||
|
showToast('📍 '+opt.value);
|
||||||
|
setTimeout(autoDetect,500);
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user