No cities
';
let poiList = kingdom.pois.length > 0 ? `
${kingdom.pois.map(p => `- ${p.name} (POI)
`).join('')}
` : '
No POIs
';
kingdomEl.innerHTML = `
${kingdom.name} (Kingdom)
Cities:
${cityList}
Points of Interest:
${poiList}
`;
kingdomContainer.appendChild(kingdomEl);
});
continentEl.appendChild(kingdomContainer);
mapContainer.appendChild(continentEl);
});
}
function updateDropdowns() {
// Update continent dropdown
continentSelectForKingdom.innerHTML = '
';
world.continents.forEach(c => {
continentSelectForKingdom.innerHTML += `
`;
});
// Update kingdom dropdown
kingdomSelectForCity.innerHTML = '
';
world.continents.forEach(c => {
c.kingdoms.forEach(k => {
kingdomSelectForCity.innerHTML += `
`;
});
});
}
function handleAddContinent() {
const name = document.getElementById('continent-name').value;
const color = document.getElementById('continent-color').value;
if (!name) return;
world.continents.push({
id: crypto.randomUUID(),
name: name,
color: color,
kingdoms: []
});
document.getElementById('continent-name').value = '';
updateDropdowns();
}
function handleAddKingdom() {
const continentId = continentSelectForKingdom.value;
const name = document.getElementById('kingdom-name').value;
const color = document.getElementById('kingdom-color').value;
if (!name || !continentId) return;
const continent = world.continents.find(c => c.id === continentId);
if (continent) {
continent.kingdoms.push({
id: crypto.randomUUID(),
name: name,
color: color,
cities: [],
pois: []
});
}
document.getElementById('kingdom-name').value = '';
updateDropdowns();
}
function handleAddLocation() {
const kingdomId = kingdomSelectForCity.value;
const name = document.getElementById('location-name').value;
const type = document.getElementById('location-type').value;
if (!name || !kingdomId) return;
let kingdom = null;
for (const continent of world.continents) {
kingdom = continent.kingdoms.find(k => k.id === kingdomId);
if (kingdom) break;
}
if (kingdom) {
if (type === 'city') {
kingdom.cities.push({ id: crypto.randomUUID(), name: name });
} else {
kingdom.pois.push({ id: crypto.randomUUID(), name: name });
}
}
document.getElementById('location-name').value = '';
}
function handleClearData() {
if (confirm("Are you sure you want to delete all world data? This cannot be undone.")) {
world.continents = [];
world.worldName = "New World";
worldNameInput.value = "New World";
renderDashboard();
updateDropdowns();
switchTab(0);
}
}
async function generatePdf() {
downloadPdfBtn.textContent = 'Generating...';
downloadPdfBtn.disabled = true;
// Ensure dashboard is rendered before PDF
renderDashboard();
try {
const canvas = await html2canvas(pdfContent, {
scale: 2,
backgroundColor: '#f9fafb'
});
const imgData = canvas.toDataURL('image/png');
const { jsPDF } = window.jspdf;
// Use standard A4 landscape format for better compatibility
const pdf = new jsPDF({
orientation: 'landscape',
unit: 'pt',
format: 'a4'
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const canvasAspectRatio = canvasHeight / canvasWidth;
// Calculate image dimensions to fit within PDF page
let imgWidth = pdfWidth - 20; // Add some margin
let imgHeight = imgWidth * canvasAspectRatio;
// If height is still too large, scale based on height
if (imgHeight > pdfHeight - 20) {
imgHeight = pdfHeight - 20; // Add some margin
imgWidth = imgHeight / canvasAspectRatio;
}
// Center the image
const xOffset = (pdfWidth - imgWidth) / 2;
const yOffset = (pdfHeight - imgHeight) / 2;
pdf.addImage(imgData, 'PNG', xOffset, yOffset, imgWidth, imgHeight);
pdf.save(`${world.worldName}-World-Plan.pdf`);
} catch (error) {
console.error("PDF generation failed:", error);
alert("Could not generate PDF. Please try again.");
} finally {
downloadPdfBtn.textContent = 'Download World Plan as PDF';
downloadPdfBtn.disabled = false;
}
}
// --- INITIALIZATION ---
function initialize() {
// Set initial config values
worldNameInput.value = world.worldName;
mapSizeSelect.value = world.mapSize;
// Initial render
renderDashboard();
updateDropdowns();
switchTab(0);
// Event Listeners
tabs.forEach((tab, index) => tab.addEventListener('click', () => switchTab(index)));
prevBtn.addEventListener('click', () => switchTab(currentTab - 1));
nextBtn.addEventListener('click', () => switchTab(currentTab + 1));
refreshDashboardBtn.addEventListener('click', () => {
renderDashboard();
updateDropdowns();
});
downloadPdfBtn.addEventListener('click', generatePdf);
// Data Listeners
addContinentBtn.addEventListener('click', handleAddContinent);
addKingdomBtn.addEventListener('click', handleAddKingdom);
addLocationBtn.addEventListener('click', handleAddLocation);
clearAllDataBtn.addEventListener('click', handleClearData);
}
initialize();
});