|
|
Line 1: |
Line 1: |
| /* Landrace.wiki – Interactive map bootstrap (Common.js) */ | | /* Landrace.wiki – Interactive map bootstrap (single, fixed block) */ |
| (function () { | | (function () { |
| var LVER = '1.9.4'; | | var LVER = '1.9.4'; |
| var CDN = 'https://unpkg.com/leaflet@' + LVER + '/dist/'; | | var CDN = 'https://unpkg.com/leaflet@' + LVER + '/dist/'; |
|
| |
|
| /* --- tiny helpers to load Leaflet --- */ | | console.log('[Landrace] Common.js boot'); |
| | |
| | /* --- load Leaflet --- */ |
| function addCSS(href, id) { | | function addCSS(href, id) { |
| if (id && document.getElementById(id)) return; | | if (id && document.getElementById(id)) return; |
Line 15: |
Line 17: |
| var s = document.createElement('script'); | | var s = document.createElement('script'); |
| s.src = src; s.onload = cb; | | s.src = src; s.onload = cb; |
| | s.onerror = function(){ console.error('[Landrace] Leaflet failed:', src); }; |
| document.head.appendChild(s); | | document.head.appendChild(s); |
| } | | } |
Line 27: |
Line 30: |
| function popup(kind, p) { | | function popup(kind, p) { |
| if (kind === 'accessions') { | | if (kind === 'accessions') { |
| var t = [p.accession_id, p.local_name].filter(Boolean).join(' — ');
| |
| var link = p.page_url ? `<br><a href="${p.page_url}">Open accession</a>` : '';
| |
| return `<b>${t}</b><br>${p.status||''}${link}`;
| |
| }
| |
| return `<b>${p.name||''}</b><br>${(p.level||kind)} • ${p.status||''}`;
| |
| }
| |
|
| |
| function initOne(el) {
| |
| if (el.dataset.init) return; el.dataset.init = '1';
| |
|
| |
| var map = L.map(el).setView([20, 85], 3);
| |
| L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution:'© OSM' }).addTo(map);
| |
|
| |
| // in-map legend (matches site colors)
| |
| var legend = L.control({ position:'bottomleft' });
| |
| legend.onAdd = function () {
| |
| var div = L.DomUtil.create('div', 'lw-legend-map');
| |
| var items = [
| |
| ['#2ecc71','Stable'], ['#f1c40f','Vulnerable'],
| |
| ['#e67e22','Endangered'], ['#e74c3c','Critical'],
| |
| ['#95a5a6','Lost']
| |
| ].map(([c,l]) => `<span class=
| |
|
| |
| /* Landrace.wiki – Interactive map bootstrap (safe hotfix) */
| |
| (function () {
| |
| var LVER = '1.9.4';
| |
| var CDN = 'https://unpkg.com/leaflet@' + LVER + '/dist/';
| |
|
| |
| function addCSS(href, id) {
| |
| if (id && document.getElementById(id)) return;
| |
| var l = document.createElement('link');
| |
| l.rel = 'stylesheet'; l.href = href; if (id) l.id = id;
| |
| document.head.appendChild(l);
| |
| }
| |
| function addJS(src, cb) {
| |
| if (window.L) return cb();
| |
| var s = document.createElement('script');
| |
| s.src = src; s.onload = cb; s.onerror = function(){ console.error('Leaflet failed to load:', src); };
| |
| document.head.appendChild(s);
| |
| }
| |
|
| |
| function statusColor(s) {
| |
| return ({Stable:'#2ecc71',Vulnerable:'#f1c40f',Endangered:'#e67e22',Critical:'#e74c3c',Lost:'#95a5a6'})[s] || '#3498db';
| |
| }
| |
| function popup(kind, p) {
| |
| if (kind === 'accessions') {
| |
| var t = [p.accession_id, p.local_name].filter(Boolean).join(' — ');
| |
| var link = p.page_url ? `<br><a href="${p.page_url}">Open accession</a>` : '';
| |
| return `<b>${t}</b><br>${p.status||''}${link}`;
| |
| }
| |
| return `<b>${p.name||''}</b><br>${(p.level||kind)} • ${p.status||''}`;
| |
| }
| |
|
| |
| function initOne(el) {
| |
| if (el.dataset.init) return; el.dataset.init = '1';
| |
|
| |
| // Ensure the map has a height even if CSS is cached/missing
| |
| if (el.clientHeight < 100) { el.style.height = '70vh'; }
| |
|
| |
| var map = L.map(el);
| |
| // Defer setView until we can possibly fit to data
| |
| L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution:'© OSM' }).addTo(map);
| |
|
| |
| // Simple legend
| |
| var legend = L.control({ position:'bottomleft' });
| |
| legend.onAdd = function () {
| |
| var div = L.DomUtil.create('div', 'lw-legend-map');
| |
| div.innerHTML = [
| |
| ['#2ecc71','Stable'], ['#f1c40f','Vulnerable'],
| |
| ['#e67e22','Endangered'], ['#e74c3c','Critical'], ['#95a5a6','Lost']
| |
| ].map(([c,l]) => `<span class="item"><span class="dot" style="background:${c}"></span>${l}</span>`).join('');
| |
| return div;
| |
| };
| |
| legend.addTo(map);
| |
|
| |
| var cfg = {
| |
| regions: { style: f => ({ color: statusColor(f.properties.status), weight: 1, fillOpacity: 0.15 }) },
| |
| populations: { pointToLayer: (f, ll) => L.circleMarker(ll, { radius: 5, color: statusColor(f.properties.status) }) },
| |
| accessions: { pointToLayer: (f, ll) => L.circleMarker(ll, { radius: 4, color: statusColor(f.properties.status) }) }
| |
| };
| |
|
| |
| var layers = [];
| |
| function maybeFit() {
| |
| try {
| |
| var group = L.featureGroup(layers);
| |
| var b = group.getBounds();
| |
| if (b && b.isValid()) {
| |
| map.fitBounds(b.pad(0.15));
| |
| } else {
| |
| // Fallback view (India/SEA)
| |
| map.setView([20, 85], 4);
| |
| }
| |
| } catch (e) {
| |
| map.setView([20, 85], 4);
| |
| }
| |
| // Make sure Leaflet recalculates size once container CSS is applied
| |
| setTimeout(function(){ map.invalidateSize(true); }, 0);
| |
| }
| |
|
| |
| var hadAnyData = false;
| |
| ['regions','populations','accessions'].forEach(function (kind) {
| |
| var url = el.dataset[kind];
| |
| if (!url) return;
| |
| fetch(url).then(function(r){
| |
| if (!r.ok) throw new Error(kind + ' fetch ' + r.status + ' ' + url);
| |
| return r.json();
| |
| }).then(function (g) {
| |
| hadAnyData = true;
| |
| var layer = L.geoJSON(g, Object.assign({
| |
| onEachFeature: (f, ly) => {
| |
| var p = f.properties || {};
| |
| ly.bindPopup(popup(kind, p));
| |
| var title = p.accession_id || p.name || '';
| |
| if (title) ly.bindTooltip(title, { direction:'top', offset:[0,-4], opacity:0.9 });
| |
| }
| |
| }, cfg[kind])).addTo(map);
| |
| layers.push(layer);
| |
| }).catch(function(err){
| |
| console.error('[Landrace.wiki map]', err);
| |
| }).finally(function(){
| |
| // Fit after each dataset tries, but only once
| |
| if (!el.dataset.fitted) {
| |
| el.dataset.fitted = '1';
| |
| maybeFit();
| |
| }
| |
| });
| |
| });
| |
|
| |
| // If no data-* URLs at all, still set a sane view
| |
| if (!el.dataset.regions && !el.dataset.populations && !el.dataset.accessions) {
| |
| map.setView([20, 85], 4);
| |
| setTimeout(function(){ map.invalidateSize(true); }, 0);
| |
| }
| |
| }
| |
|
| |
| function init(root) {
| |
| (root || document).querySelectorAll('.lw-map').forEach(initOne);
| |
| }
| |
|
| |
| addCSS(CDN + 'leaflet.css', 'leaflet-css');
| |
| addJS(CDN + 'leaflet.js', function () {
| |
| init();
| |
| if (window.mw && mw.hook) mw.hook('wikipage.content').add(function ($c) { init($c && $c[0] ? $c[0] : document); });
| |
| });
| |
| })();
| |