Architectural Sketch Plan Generator
Preliminary Floor Plan Layout (Scaled Dimensions)
Building Size:
0 x 0 ft
Residence Floor Plan
Architect/Designer: N/A | Date: ---
Scaled Floor Plan (Scale: 10 pixels/ft)
Room Schedule & Dimensions (Feet)
| ID | Area Name | Width (ft) | Height (ft) |
|---|
Generated by Architectural Sketch Plan Generator (Dimensions are approximate).
Project Context & Dimensions
Overall Drawing Scale (Defines Drawing Limits)
Maps to $500$ pixels wide.
Maps to $300$ pixels high.
Room & Element Editor
Define rooms/areas and their placement (X/Y coordinates in feet, measured from top-left corner).
Current Elements
List is empty.
"; return; } apgData.elements.forEach(el => { const row = document.createElement('div'); row.className = 'apg-element-row'; row.innerHTML = `
${el.name} (${el.type}) - ${el.w}x${el.h} ft
`;
outputs.elementListEditor.appendChild(row);
});
}
// --- 5. EVENT LISTENERS & ACTIONS ---
function attachListeners() {
// Meta Inputs
const metaInputs = Object.values(inputs).filter(i => !i.id.includes('element') && !i.id.includes('ft') && !i.id.includes('pos'));
metaInputs.forEach(inp => inp.addEventListener('input', renderAll));
// Add Element Button
document.getElementById('btn-add-element').addEventListener('click', addElement);
}
function addElement() {
const type = inputs.elementType.value;
const name = inputs.elementName.value.trim();
const w = parseFloat(inputs.widthFt.value) || 0;
const h = parseFloat(inputs.heightFt.value) || 0;
const x = parseFloat(inputs.xPos.value) || 0;
const y = parseFloat(inputs.yPos.value) || 0;
if (!name || w <= 0 || h <= 0) {
alert("Name, Width, and Height must be positive.");
return;
}
// Check bounds against max canvas size
if (x + w > apgData.meta.maxW || y + h > apgData.meta.maxH) {
alert(`Element exceeds the maximum canvas size of ${apgData.meta.maxW}x${apgData.meta.maxH} ft.`);
return;
}
const newElement = {
id: Date.now(),
type: type,
name: name,
w: w,
h: h,
x: x,
y: y
};
apgData.elements.push(newElement);
// Clear inputs for next entry (optional, depends on workflow)
inputs.elementName.value = "";
renderAll();
}
window.removeElement = function(id) {
if(confirm("Remove this element?")) {
apgData.elements = apgData.elements.filter(el => el.id !== id);
renderAll();
}
};
// --- 6. TAB NAVIGATION ---
window.apgSwitchTab = function(tabId) {
if (tabId === 'tab-plan') renderSVGPlan(); // Always force SVG update when viewing the plan
document.querySelectorAll('.apg-tab-pane').forEach(p => p.classList.remove('active'));
document.querySelectorAll('.apg-tab-btn').forEach(b => b.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
document.querySelector(`.apg-tab-btn[data-tab="${tabId}"]`).classList.add('active');
document.getElementById('arch-plan-tool').scrollIntoView({behavior: 'smooth'});
};
document.querySelectorAll('.apg-tab-btn').forEach(btn => {
btn.addEventListener('click', function() { apgSwitchTab(this.dataset.tab); });
});
// --- 7. PDF EXPORT ---
const btnDown = document.getElementById('apg-download-btn');
if(btnDown) {
btnDown.addEventListener('click', function() {
renderAll();
const element = document.getElementById('apg-render-area');
const filename = (inputs.projectTitle.value || 'Floor_Plan').replace(/\s+/g,'_');
const opt = {
margin: 0.4,
filename: `${filename}_Sketch_Plan.pdf`,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, useCORS: true },
jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
};
const origText = btnDown.innerText;
btnDown.innerText = "Generating Plan...";
html2pdf().set(opt).from(element).save().then(() => {
btnDown.innerText = origText;
});
});
}
// Start
init();
});
