Compare commits
	
		
			No commits in common. "server" and "map" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										15
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							|  | @ -1,15 +0,0 @@ | ||||||
| { |  | ||||||
|     // Use IntelliSense to learn about possible attributes. |  | ||||||
|     // Hover to view descriptions of existing attributes. |  | ||||||
|     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |  | ||||||
|     "version": "0.2.0", |  | ||||||
|     "configurations": [ |  | ||||||
|         { |  | ||||||
|             "type": "chrome", |  | ||||||
|             "request": "launch", |  | ||||||
|             "name": "Launch Chrome against localhost", |  | ||||||
|             "url": "http://localhost:8080", |  | ||||||
|             "webRoot": "${workspaceFolder}" |  | ||||||
|         } |  | ||||||
|     ] |  | ||||||
| } |  | ||||||
|  | @ -10,7 +10,8 @@ | ||||||
|     html,body,#map {height:100%;margin:0} |     html,body,#map {height:100%;margin:0} | ||||||
|     .coords{position:absolute;left:6px;bottom:6px;z-index:1000;background:rgba(255,255,255,.85); |     .coords{position:absolute;left:6px;bottom:6px;z-index:1000;background:rgba(255,255,255,.85); | ||||||
|       padding:3px 6px;font-size:12px;border-radius:4px;font-family:system-ui,Segoe UI,Arial} |       padding:3px 6px;font-size:12px;border-radius:4px;font-family:system-ui,Segoe UI,Arial} | ||||||
|       .center-dot{position:absolute;top:50%;left:50%;width:5px;height:5px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 2px rgba(0,0,0,.35);pointer-events:none;z-index:1001} |       .center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 6px rgba(0,0,0,.35);pointer-events:none;z-index:1001} | ||||||
|  |       .center-dot{position:absolute;top:50%;left:50%;width:10px;height:10px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 6px rgba(0,0,0,.35);pointer-events:none;z-index:1001} | ||||||
|     .copy-btn{position:absolute;left:6px;bottom:36px;z-index:1000;background:#ef4444;color:#fff;border:0;border-radius:6px;padding:6px 10px;font:600 12px/1 system-ui,Segoe UI,Arial;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.25)} |     .copy-btn{position:absolute;left:6px;bottom:36px;z-index:1000;background:#ef4444;color:#fff;border:0;border-radius:6px;padding:6px 10px;font:600 12px/1 system-ui,Segoe UI,Arial;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.25)} | ||||||
|     .copy-btn:active{transform:translateY(1px)} |     .copy-btn:active{transform:translateY(1px)} | ||||||
|   </style> |   </style> | ||||||
|  | @ -179,8 +180,7 @@ if (hash.length >= 2) { | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|   </script> |   </script> | ||||||
|   <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> |  | ||||||
|   <script src="markers.js"></script> |  | ||||||
| 
 | 
 | ||||||
|  |   <script src="markers.js"></script> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
							
								
								
									
										117
									
								
								markers.js
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								markers.js
									
									
									
									
									
								
							|  | @ -1,40 +1,91 @@ | ||||||
| let Data_api = "/webhook/data"; | // === CONFIG ===
 | ||||||
| let freight = null; | const WIKI_API = 'https://wiki.arenos.danielnagel.at/api.php'; // dein Wiki-Host (mit index.php)
 | ||||||
| let testing = true; | const CATEGORY_TITLE = 'Kategorie:Orte';                          // Hauptkategorie
 | ||||||
| 
 | const MAX_PAGES = 500;                                            // genug Luft
 | ||||||
| let ReqData = { Places: "Stadte"} |  | ||||||
| 
 |  | ||||||
| // Post to n8n Server to get Data from Grist in JSON format.
 |  | ||||||
| async function GetMarkerData() { |  | ||||||
|    |  | ||||||
|   try { |  | ||||||
|     const res = await axios.post(Data_api, ReqData); |  | ||||||
|     console.log (res.data); |  | ||||||
|     RenderMarkers(res.data); |  | ||||||
| 
 |  | ||||||
|   } catch (err) { |  | ||||||
|     console.error (err); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|  | // Hilfsfunktion: MediaWiki API-URL bauen
 | ||||||
|  | function apiURL(params) { | ||||||
|  |   const u = new URL(WIKI_API); | ||||||
|  |   u.search = new URLSearchParams({ ...params, format: 'json', origin: '*' }).toString(); | ||||||
|  |   return u.toString(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //Render Map Markers with the Position from Grist Database
 | // 1) Alle Mitglieder einer Kategorie holen
 | ||||||
| function RenderMarkers(rows){ | async function fetchCategoryMembers(categoryTitle) { | ||||||
|   if (!Array.isArray(rows)) { |   const url = apiURL({ | ||||||
|     console.error('Erwarte ein Array, bekam:', rows); |     action: 'query', | ||||||
|     return; |     list: 'categorymembers', | ||||||
|   } |     cmtitle: categoryTitle, | ||||||
| 
 |     cmlimit: String(MAX_PAGES) | ||||||
|   rows.forEach((row) => { |  | ||||||
|     const x = Number(row.X); |  | ||||||
|     const y = Number(row.Y); |  | ||||||
|     if (!Number.isFinite(x) || !Number.isFinite(y)) return; |  | ||||||
| 
 |  | ||||||
|     L.marker([y, x])        // [lat, lng] -> [Y, X]
 |  | ||||||
|       .addTo(map) |  | ||||||
|       .bindPopup(`<b>${row.Name ?? ''}</b>`); |  | ||||||
|   }); |   }); | ||||||
|  |   const res = await fetch(url); | ||||||
|  |   if (!res.ok) throw new Error(`categorymembers failed: ${res.status}`); | ||||||
|  |   const data = await res.json(); | ||||||
|  |   return data?.query?.categorymembers || []; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // 2) Gerendertes HTML einer Seite holen (damit <div class="place-data"> drin ist)
 | ||||||
|  | async function fetchPageHTML(title) { | ||||||
|  |   const url = apiURL({ | ||||||
|  |     action: 'parse', | ||||||
|  |     page: title, | ||||||
|  |     prop: 'text' | ||||||
|  |   }); | ||||||
|  |   const res = await fetch(url); | ||||||
|  |   if (!res.ok) throw new Error(`parse failed for ${title}: ${res.status}`); | ||||||
|  |   const data = await res.json(); | ||||||
|  |   const html = data?.parse?.text?.['*'] || ''; | ||||||
|  |   const div = document.createElement('div'); | ||||||
|  |   div.innerHTML = html; | ||||||
|  |   return div; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 3) Daten aus dem versteckten Div extrahieren
 | ||||||
|  | function extractPlaceData(container) { | ||||||
|  |   const node = container.querySelector('.place-data'); | ||||||
|  |   if (!node) return null; | ||||||
|  |   const name = node.getAttribute('data-name') || ''; | ||||||
|  |   const xStr = node.getAttribute('data-x') || ''; | ||||||
|  |   const yStr = node.getAttribute('data-y') || ''; | ||||||
|  |   const desc = node.getAttribute('data-description') || ''; | ||||||
|  |   const link = node.getAttribute('data-link') || ''; | ||||||
|  |   const x = parseFloat(xStr); | ||||||
|  |   const y = parseFloat(yStr); | ||||||
|  |   if (Number.isNaN(x) || Number.isNaN(y)) return null; | ||||||
|  |   return { name, x, y, desc, link }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 4) Marker laden + hinzufügen
 | ||||||
|  | async function loadWikiMarkers(map) { | ||||||
|  |   try { | ||||||
|  |     const pages = await fetchCategoryMembers(CATEGORY_TITLE); | ||||||
|  | 
 | ||||||
|  |     // Optionales Bounding, falls du später auto-fit willst
 | ||||||
|  |     const layers = []; | ||||||
|  |     for (const p of pages) { | ||||||
|  |       try { | ||||||
|  |         const html = await fetchPageHTML(p.title); | ||||||
|  |         const d = extractPlaceData(html); | ||||||
|  |         if (!d) continue; | ||||||
|  | 
 | ||||||
|  |         // Leaflet: Bei CRS.Simple = [y, x]
 | ||||||
|  |         const m = L.marker([d.y, d.x]).addTo(map); | ||||||
|  |         const wikiLink = d.link || `https://wiki.arenos.danielnagel.at/index.php/${encodeURIComponent(p.title)}`; | ||||||
|  |         const popup = ` | ||||||
|  |           <b>${d.name || p.title}</b><br> | ||||||
|  |           ${d.desc ? `${d.desc}<br>` : ''} | ||||||
|  |           <a href="${wikiLink}" target="_blank" rel="noopener">Open in Wiki</a> | ||||||
|  |         `;
 | ||||||
|  |         m.bindPopup(popup); | ||||||
|  |         layers.push(m); | ||||||
|  | 
 | ||||||
|  |       } catch (e) { | ||||||
|  |         console.warn('skip page due to parse error:', p.title, e); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   } catch (e) { | ||||||
|  |     console.error('Failed to load wiki markers:', e); | ||||||
|  |   } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| GetMarkerData(); |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user