Files
maps-saas/apps/dashboard/js/playground.js
T
2026-04-15 19:56:49 +03:00

156 lines
5.9 KiB
JavaScript

/**
* Playground Logic (Map Integration)
*/
const playground = {
map: null,
currentStyle: 'obsidian',
selectedKey: '',
init: (keys) => {
if (playground.map) return;
console.log('🗺️ Initializing Playground...');
playground.renderKeySelect(keys);
playground.bindEvents();
// Watch for section changes to trigger resize
window.addEventListener('hashchange', () => {
if (window.location.hash === '#playground' && playground.map) {
setTimeout(() => playground.map.resize(), 100);
}
});
if (keys.length > 0) {
playground.selectedKey = keys[0].key;
playground.loadMap();
}
},
renderKeySelect: (keys) => {
const select = document.getElementById('pg-key-select');
if (!select) return;
select.innerHTML = keys.map(k => `<option value="${k.key}">${k.name}</option>`).join('');
if (keys.length === 0) select.innerHTML = '<option value="">No keys available</option>';
},
bindEvents: () => {
const select = document.getElementById('pg-key-select');
if (select) {
select.addEventListener('change', (e) => {
playground.selectedKey = e.target.value;
playground.updateMap();
});
}
const searchInput = document.getElementById('pg-search');
if (searchInput) {
searchInput.addEventListener('keydown', async (e) => {
if (e.key === 'Enter' && searchInput.value) {
await playground.handleSearch(searchInput.value);
}
});
}
},
loadMap: async () => {
const container = document.getElementById('map');
if (!container || !playground.selectedKey) return;
try {
// Set RTL Text Plugin
if (maplibregl.getRTLTextPluginStatus() === 'unavailable') {
console.log('🌐 Loading MapLibre RTL Plugin...');
maplibregl.setRTLTextPlugin(
'js/plugins/mapbox-gl-rtl-text.js',
null,
true
);
}
console.log(`🛰️ Fetching Map Style for theme: ${playground.currentStyle}...`);
const styleUrl = `/api/maps/style.json?api_key=${playground.selectedKey}&theme=${playground.currentStyle}`;
const res = await fetch(styleUrl);
if (!res.ok) {
throw new Error(`Style fetch failed with status: ${res.status}`);
}
const styleData = await res.json();
console.log('🎨 Style fetched successfully, initializing MapLibre...');
playground.map = new maplibregl.Map({
container: 'map',
style: styleData,
center: [35.91, 31.95], // Amman, Jordan
zoom: 12,
attributionControl: false,
trackResize: true
});
playground.map.addControl(new maplibregl.NavigationControl(), 'top-right');
playground.map.on('load', () => {
console.log('✅ Map engine ready and tiles loading!');
// Wait slightly for container animation to finish
setTimeout(() => {
playground.map.resize();
const container = document.getElementById('map');
if (container && container.offsetWidth > 0) {
console.log('📏 Map container size verified:', container.offsetWidth, 'x', container.offsetHeight);
} else {
console.warn('⚠️ Map container has 0 width. Potential visibility issue.');
}
}, 500);
});
playground.map.on('error', (e) => {
console.error('❌ MapLibre Error Detail:', e.error || e);
if (e.error && e.error.message.includes('Style')) {
alert('Map Style Error: Please verify your API Key and Network connection.');
}
});
} catch (error) {
console.error('Failed to init map', error);
}
},
updateMap: async () => {
if (!playground.map) return;
try {
const styleUrl = `/api/maps/style.json?api_key=${playground.selectedKey}&theme=${playground.currentStyle}`;
const res = await fetch(styleUrl);
const styleData = await res.json();
playground.map.setStyle(styleData);
} catch (error) {
console.error('Failed to update style', error);
}
},
setStyle: (style) => {
playground.currentStyle = style;
// Update UI buttons
document.getElementById('style-obsidian').className = (style === 'obsidian') ? 'flex-1 py-3 text-xs font-bold rounded-xl bg-blue-600 text-white shadow-lg shadow-blue-500/20' : 'flex-1 py-3 text-xs font-bold rounded-xl bg-slate-900 text-slate-500';
document.getElementById('style-light').className = (style === 'light') ? 'flex-1 py-3 text-xs font-bold rounded-xl bg-blue-600 text-white shadow-lg shadow-blue-500/20' : 'flex-1 py-3 text-xs font-bold rounded-xl bg-slate-900 text-slate-500';
playground.updateMap();
},
handleSearch: async (query) => {
try {
const res = await fetch(`/api/geocoding/search?q=${encodeURIComponent(query)}`, {
headers: { 'x-api-key': playground.selectedKey }
});
if (res.ok) {
const data = await res.json();
if (data && data.length > 0) {
playground.map.flyTo({ center: [data[0].longitude, data[0].latitude], zoom: 14 });
}
}
} catch (err) {
console.error("Search failed", err);
}
}
};