|
|
Line 30: |
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';
| |
|
| |
| // Ensure height even if CSS is cached/missing
| |
| if (el.clientHeight < 100) { el.style.height = '70vh'; }
| |
|
| |
| var map = L.map(el);
| |
| L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution:'© OSM' }).addTo(map);
| |
|
| |
| // Legend
| |
| 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(function (x) {
| |
| var c = x[0], l = x[1];
| |
| return '<span class="item"><span class="dot" style="background:'+c+'"></span>'+l+'</span>';
| |
| }).join('');
| |
| div.innerHTML = items;
| |
| return div;
| |
| };
| |
| legend.addTo(map);
| |
|
| |
| var cfg = {
| |
| regions: { style: function (f) { return { color: statusColor(f.properties.status), weight: 1, fillOpacity: 0.15 }; } },
| |
| populations: { pointToLayer: function (f, ll) { return L.circleMarker(ll, { radius: 5, color: statusColor(f.properties.status) }); } },
| |
| accessions: { pointToLayer: function (f, ll) { return L.circleMarker(ll, { radius: 4, color: statusColor(f.properties.status) }); } }
| |
| };
| |
|
| |
| var layers = [];
| |
| function maybeFit() {
| |
| try {
| |
| var group = L.featureGroup(layers), b = group.getBounds();
| |
| if (b && b.isValid()) { map.fitBounds(b.pad(0.15)); }
| |
| else { map.setView([20, 85], 4); }
| |
| } catch (e) { map.setView([20, 85], 4); }
| |
| setTimeout(function(){ map.invalidateSize(true); }, 0);
| |
| }
| |
|
| |
| ['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+' '+r.status+' '+url);
| |
| return r.json();
| |
| }).then(function (g) {
| |
| var layer = L.geoJSON(g, Object.assign({
| |
| onEachFeature: function (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 map]', err);
| |
| }).finally(function(){
| |
| if (!el.dataset.fitted) { el.dataset.fitted = '1'; maybeFit(); }
| |
| });
| |
| });
| |
|
| |
| if (!el.dataset.regions && !el.dataset.populations && !el.dataset.accessions) {
| |
| map.setView([20, 85], 4);
| |
| setTimeout(function(){ map.invalidateSize(true); }, 0);
| |
| }
| |
| }
| |
|
| |
| function init(root) {
| |
| var nodes = (root || document).querySelectorAll('.lw-map');
| |
| console.log('[Landrace] .lw-map containers:', nodes.length);
| |
| Array.prototype.forEach.call(nodes, initOne);
| |
| }
| |
|
| |
| addCSS(CDN + 'leaflet.css', 'leaflet-css');
| |
| addJS(CDN + 'leaflet.js', function () {
| |
| console.log('[Landrace] Leaflet ready:', !!window.L);
| |
| init();
| |
| if (window.mw && mw.hook) {
| |
| mw.hook('wikipage.content').add(function ($c) {
| |
| init($c && $c[0] ? $c[0] : document);
| |
| });
| |
| }
| |
| });
| |
| })();
| |