Files
cpp-garmin-img-to-osm/data/BGMountains-POI-Explorer.html
T

6 lines
154 KiB
HTML
Raw Permalink Normal View History

2026-10-14 12:42:58 +00:00
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>BGMountains POI Explorer – bounds checked</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>
:root{color-scheme:light;--ink:#17212f;--muted:#637488;--bd:#d8e3ec;--bg:#f5f8fb;--primary:#0964c0}*{box-sizing:border-box}body{font:14px/1.55 system-ui,Segoe UI,Arial,sans-serif;background:var(--bg);color:var(--ink);margin:0}header{padding:25px clamp(16px,4vw,60px);background:#112b43;color:white}h1{font-size:26px;margin:0 0 3px}header p{color:#b8cddd;margin:0;max-width:950px}main{padding:18px clamp(16px,4vw,60px)}.toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:12px 0 16px}.toolbar input,.toolbar select{background:white;border:1px solid var(--bd);border-radius:8px;padding:10px;font-size:14px;min-width:220px}.stats{color:var(--muted);margin:8px 0}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(345px,1fr));gap:12px}.card{background:#fff;border:1px solid var(--bd);border-radius:12px;padding:15px;box-shadow:0 2px 4px #12203308}.head{display:flex;gap:12px;align-items:center}.pixel{image-rendering:pixelated;width:52px;height:52px;object-fit:contain;border-radius:7px;border:1px solid var(--bd);background:white;padding:3px}.blank{display:grid;place-items:center;background:#f0f3f7;color:#85919f;font-size:11px;text-align:center}.code{font:bold 17px ui-monospace,Consolas,monospace}.sub,.small{font-size:12px;color:var(--muted)}.tag{display:inline-block;background:#ebf5ff;color:#125b9f;border-radius:5px;font:12px ui-monospace,monospace;padding:4px;margin:4px 5px 0 0;word-break:break-all}.pill{display:inline-block;background:#e9f8f0;color:#23633a;border-radius:20px;padding:2px 8px;font-size:11px}.unknown{background:#fff2df;color:#935b16}.samples{border-top:1px solid var(--bd);margin-top:9px;padding-top:8px}.loc{font:12px ui-monospace,monospace}.example{display:flex;align-items:center;justify-content:space-between;gap:5px;padding:6px 0;border-bottom:1px solid #eef1f5}.ex-name{font-size:12px;color:#516177;max-width:220px;overflow-wrap:anywhere}.buttons{display:flex;gap:3px}button,a.geo{font-size:11px;border:1px solid var(--bd);background:#f7fafd;padding:5px 7px;border-radius:6px;cursor:pointer;color:#135b9f;text-decoration:none}.minor{color:var(--muted);font-size:12px}footer{padding:28px 0;color:var(--muted);font-size:12px}#data{display:none}
</style></head><body><header><h1>BGMountains POI icon and type explorer</h1><p>Locally browsable, based on the original IMG, its extracted 16×16 Garmin TYP icons, and the supplied official Garmin legend. Coordinates are source-decoded, not field verified. v0.6 rejects extended records outside their TRE subdivisions.</p></header><main><div class="toolbar"><input id="q" type="search" placeholder="Search code, Bulgarian name, tags…" aria-label="Search POI types"><select id="status"><option value="all">All retained types</option><option value="verified">Verified icon ↔ legend only</option><option value="unknown">Unverified / investigate</option><option value="extended">Extended codes only</option></select><select id="sort"><option value="most">Most occurrences</option><option value="code">Hex type ascending</option><option value="named">Most named</option></select></div><div id="summary" class="stats"></div><div id="grid" class="grid"></div><footer>Sample coordinate links open a public basemap only; they do not upload map data. Use the Copy control and paste the coordinates into GPXSee showing the original Garmin IMG to verify the mapped symbol and nearby source labels. Known errors and all corrected rules are recorded in the accompanying CSV audit.</footer></main><script>const data=[{"code": "0x200", "count": 2, "named": 2, "legend": "Capital City", "bg": "Столица", "tags": "place=city;capital=yes", "rawtype": "classic", "status": "icon_legend_verified", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAQUlEQVQ4jWNgGPKAEY/cfxLUEtSMS4xozUQbgq7gPw4xogwghs3ARMhJhAALHjlGJNsojgFi5AgqxKqZZglpCAEAJPgS+hBD8eEAAAAASUVORK5CYII=", "samples": [{"lat": "41.0612941", "lon": "28.8116670", "name": "Истанбул", "map": "02235106"}, {"lat": "42.6954675", "lon": "23.3326221", "name": "София", "map": "02234047"}], "qa": ""}, {"code": "0x800", "count": 51, "named": 51, "legend": "Large City", "bg": "Град >75 000", "tags": "place=city", "rawtype": "classic", "status": "icon_legend_verified", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAL0lEQVQ4jWNgGAWMeOT+E6mOoGZsfJI04xVnItMwog0g2e+4bMbpEprFwiggAQAA/5AJAfu9Lm0AAAAASUVORK5CYII=", "samples": [{"lat": "43.9025259", "lon": "22.2788572", "name": "Зайчар", "map": "02234009"}, {"lat": "43.3169031", "lon": "21.8945074", "name": "Ниш", "map": "02234032"}, {"lat": "42.4246931", "lon": "25.6255674", "name": "Стара Загора", "map": "02235052"}, {"lat": "41.4337349", "lon": "22.0119452", "name": "Кавадарци", "map": "02234093"}, {"lat": "44.0004802", "lon": "22.8833199", "name": "Видин", "map": "02334142"}], "qa": ""}, {"code": "0x900", "count": 283, "named": 283, "legend": "Town", "bg": "Град <75 000", "tags": "place=town", "rawtype": "classic", "status": "icon_legend_verified", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKElEQVQ4jWNgGAU0B/+hmGzN2Ngka8ZrCBOpJpPrCorCgWzNo4BIAAB2ygn51rw42QAAAABJRU5ErkJggg==", "samples": [{"lat": "42.0570374", "lon": "24.5459247", "name": "Перущица", "map": "02235062"}, {"lat": "40.8942676", "lon": "26.1739397", "name": "Ферес", "map": "02235113"}, {"lat": "41.3800907", "lon": "25.0934172", "name": "Златоград", "map": "02235087"}, {"lat": "43.3485103", "lon": "26.2265968", "name": "Попово", "map": "02235017"}, {"lat": "42.5014901", "lon": "22.4737144", "name": "Босилеград", "map": "02234057"}], "qa": ""}, {"code": "0xd00", "count": 6610, "named": 6609, "legend": "", "bg": "", "tags": "", "rawtype": "classic", "status": "not_on_legend", "icon": null, "samples": [{"lat": "41.6287208", "lon": "23.7694144", "name": "Балдево", "map": "02234096"}, {"lat": "43.4385252", "lon": "26.5020704", "name": "Островче", "map": "02235018"}, {"lat": "43.5053658", "lon": "27.2674227", "name": "Красен дол", "map": "02235019"}, {"lat": "41.4777446", "lon": "26.1179996", "name": "Свирачи", "map": "02235089"}, {"lat": "41.8935943", "lon": "21.6824412", "name": "Катлан
const q=document.querySelector('#q'),status=document.querySelector('#status'),sort=document.querySelector('#sort'),grid=document.querySelector('#grid'),summary=document.querySelector('#summary');function safe(s){return String(s??'').replace(/[&<>\"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',"'":'&#39;'}[c]));}
function render(){const query=q.value.toLocaleLowerCase(),filter=status.value;let list=data.filter(d=>{let matches=[d.code,d.legend,d.bg,d.tags,d.status,...d.samples.map(s=>s.name)].join(' ').toLocaleLowerCase().includes(query);return matches&&(filter==='all'||(filter==='verified'&&d.status==='icon_legend_verified')||(filter==='unknown'&&d.status!=='icon_legend_verified')||(filter==='extended'&&d.rawtype==='extended'));});list.sort(sort.value==='code'?(a,b)=>parseInt(a.code,16)-parseInt(b.code,16):sort.value==='named'?(a,b)=>b.named-a.named:(a,b)=>b.count-a.count);summary.textContent=`Showing ${list.length} of ${data.length} types; ${list.reduce((s,d)=>s+d.count,0).toLocaleString()} total POI records in this selection.`;grid.innerHTML=list.map(d=>`<article class="card"><div class="head">${d.icon?`<img class="pixel" src="${d.icon}" alt="Extracted POI bitmap for ${d.code}">`:'<span class="pixel blank">No TYP<br>icon</span>'}<div><div class="code">${safe(d.code)} <span class="pill ${d.status==='icon_legend_verified'?'':'unknown'}">${safe(d.status.replaceAll('_',' '))}</span></div><div><strong>${safe(d.bg||d.legend||'Unclassified')}</strong> ${d.bg&&d.legend?` / ${safe(d.legend)}`:''}</div><div class="small">${d.count.toLocaleString()} POIs · ${d.named.toLocaleString()} named · ${safe(d.rawtype)}</div></div></div><div>${d.tags?d.tags.split(';').map(t=>`<span class="tag">${safe(t)}</span>`).join(''):'<span class="minor">No safe semantic mapping determined</span>'}</div>${d.qa?`<p class="minor">${safe(d.qa)}</p>`:''}<div class="samples"><div class="sub">Sample coordinates from original IMG:</div>${d.samples.map(s=>{let lat=encodeURIComponent(s.lat),lon=encodeURIComponent(s.lon);let url=`https://www.openstreetmap.org/?mlat=${lat}&mlon=${lon}#map=17/${lat}/${lon}`;return `<div class="example"><div><div class="loc">${safe(s.lat)}, ${safe(s.lon)}</div><div class="ex-name">${safe(s.name||'Unnamed')} · mapset ${safe(s.map)}</div></div><div class="buttons"><button data-copy="${safe(s.lat)}, ${safe(s.lon)}">Copy</button><a class="geo" href="${url}" target="_blank" rel="noopener noreferrer">Map ↗</a></div></div>`}).join('')}</div></article>`).join('');document.querySelectorAll('[data-copy]').forEach(b=>b.addEventListener('click',()=>navigator.clipboard?.writeText(b.dataset.copy).then(()=>{b.textContent='Copied';setTimeout(()=>b.textContent='Copy',1100)}).catch(()=>{prompt('Copy coordinates:',b.dataset.copy)})));}
[q,status,sort].forEach(el=>el.addEventListener(el===q?'input':'change',render));render();</script></body></html>