/** * Overpass UI: Query-Editor-Panel mit Template-Browser und BBox-Integration. */ const OverpassUI = { _panel: null, _editor: null, _templates: [], _categories: [], _activeCategory: null, _isLoading: false, _useBbox: true, init: function() { this._createPanel(); this._loadTemplates(); }, show: function() { if (!this._panel) this.init(); this._panel.style.display = 'block'; if (!OverpassLayer._points) OverpassLayer.start(Globe.viewer); }, hide: function() { if (this._panel) this._panel.style.display = 'none'; }, _createPanel: function() { var panel = document.getElementById('overpass-panel'); if (!panel) return; this._panel = panel; panel.innerHTML = '
' + '
OVERPASS QUERY
' + '' + '
' + '
' + '
' + '
' + '
OVERPASSQL EDITOR
' + '' + '
' + '' + '
' + '' + '' + ''; this._editor = document.getElementById('overpass-editor'); }, _loadTemplates: function() { var self = this; fetch('/api/overpass/templates') .then(function(r) { return r.json(); }) .then(function(data) { self._categories = data.categories || []; if (self._categories.length > 0) { self._activeCategory = self._categories[0].id; self._renderCategoryTabs(); self._renderTemplateList(); } }) .catch(function(e) { console.warn('Overpass Templates:', e); }); }, _renderCategoryTabs: function() { var el = document.getElementById('overpass-cat-tabs'); if (!el) return; var self = this; var html = ''; this._categories.forEach(function(cat) { var active = cat.id === self._activeCategory ? ' active' : ''; html += ''; }); el.innerHTML = html; }, _selectCategory: function(catId) { this._activeCategory = catId; this._renderCategoryTabs(); this._renderTemplateList(); }, _renderTemplateList: function() { var el = document.getElementById('overpass-template-list'); if (!el) return; var self = this; var cat = this._categories.find(function(c) { return c.id === self._activeCategory; }); if (!cat) { el.innerHTML = ''; return; } var html = ''; cat.templates.forEach(function(t) { html += ''; }); el.innerHTML = html; }, _applyTemplate: function(templateId) { var tpl = null; for (var i = 0; i < this._categories.length; i++) { var found = this._categories[i].templates.find(function(t) { return t.id === templateId; }); if (found) { tpl = found; break; } } if (tpl && this._editor) { this._editor.value = tpl.query; OverpassLayer.setColor(tpl.color); } }, _getBboxFromViewport: function() { if (!Globe.viewer) return null; var rect = Globe.viewer.camera.computeViewRectangle(); if (!rect) return null; return [ Cesium.Math.toDegrees(rect.south), Cesium.Math.toDegrees(rect.west), Cesium.Math.toDegrees(rect.north), Cesium.Math.toDegrees(rect.east), ]; }, _executeQuery: function() { if (this._isLoading || !this._editor) return; var query = this._editor.value.trim(); if (!query) return; var bbox = null; if (this._useBbox) { bbox = this._getBboxFromViewport(); } this._isLoading = true; var btn = document.getElementById('overpass-exec-btn'); if (btn) { btn.disabled = true; btn.textContent = 'LADE...'; } var resultEl = document.getElementById('overpass-result'); if (resultEl) { resultEl.style.display = 'block'; resultEl.textContent = 'Anfrage wird gesendet...'; resultEl.style.color = 'var(--text-dim)'; } var startTime = Date.now(); var self = this; fetch('/api/overpass/query', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: query, bbox: bbox }), }) .then(function(r) { if (r.status === 429) { return r.json().then(function(d) { throw new Error(d.detail || 'Rate-Limit erreicht'); }); } if (!r.ok) { return r.json().then(function(d) { throw new Error(d.detail || 'Fehler ' + r.status); }); } return r.json(); }) .then(function(data) { var elapsed = ((Date.now() - startTime) / 1000).toFixed(1); OverpassLayer.render(data); if (resultEl) { var text = data.total + ' Objekte (' + elapsed + 's)'; if (data.cached) text += ' [Cache]'; if (data.truncated) text += ' [max. ' + data.total + ' angezeigt]'; resultEl.textContent = text; resultEl.style.color = 'var(--accent)'; } var clearBtn = document.getElementById('overpass-clear-btn'); if (clearBtn) clearBtn.style.display = 'block'; }) .catch(function(e) { if (resultEl) { resultEl.textContent = 'Fehler: ' + e.message; resultEl.style.color = '#ff5252'; } }) .finally(function() { self._isLoading = false; if (btn) { btn.disabled = false; btn.textContent = 'AUSFUEHREN'; } }); }, _clearResults: function() { OverpassLayer.clear(); var resultEl = document.getElementById('overpass-result'); if (resultEl) { resultEl.style.display = 'none'; resultEl.style.color = 'var(--text-dim)'; } var clearBtn = document.getElementById('overpass-clear-btn'); if (clearBtn) clearBtn.style.display = 'none'; }, executeQueryDirect: function(query, bbox, color) { if (this._editor) this._editor.value = query; if (color) OverpassLayer.setColor(color); this._useBbox = !!bbox; var bboxCb = document.getElementById('overpass-bbox'); if (bboxCb) bboxCb.checked = this._useBbox; this.show(); this._executeQuery(); }, };