Silver Steel Mills
Professional PEB (Pre-Engineered Building) Estimator
SILVER STEEL MILLS
silversteelmills.com | +92 324 9500004
PROJECT QUOTATION REPORT
Structure Layout Drawing
Estimated Costs Breakdown
This estimation is based on the provided rates and standard PEB engineering principles. Actual rates and material requirements may vary based on your project and market fluctuations. Use for reference only.
Terms and Conditions
1. Design Codes and Loads
All structural design loads and engineering codes are based on current construction regulations, as per Section 1. Any changes requested by the client will require a revised quotation, including updated costs and timelines.
2. Drawings and Approvals
This quotation and the latest drawings supersede all previous documents, discussions, or revisions. Any changes in parameters during or after drawing approval will result in revised costs and a new delivery schedule, subject to both technical and commercial approval.
3. Material Supply & Delivery
Materials will be delivered promptly upon 100% advance payment. Fabrication can be managed at both the factory and the site, depending on project needs. Storage space for delivered materials must be provided by the client.
4. Payment Terms
A) Material Supply
100% Advance Payment upon order confirmation.
B) Erection Work (Step-by-Step Payment Schedule)
| Stage | Payment | Description |
|---|---|---|
| 1 | 40% | Upon confirmation of erection order |
| 2 | 30% | After fabrication of main frames |
| 3 | 20% | After erection of roofing, cladding, and structural works |
| 4 | 10% | Upon final completion and client approval |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Silver Steel Mills Advanced Estimator</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #f3f4f6;
}
.pdf-container {
font-family: 'Inter', sans-serif;
padding: 2rem;
color: #1a202c;
}
.pdf-container .header {
text-align: center;
margin-bottom: 2rem;
}
.pdf-container h1, .pdf-container h2, .pdf-container h3 {
text-align: center;
}
.pdf-container .result-item {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e2e8f0;
padding-bottom: 0.75rem;
margin-bottom: 0.75rem;
}
.terms-table th, .terms-table td {
padding: 8px;
border: 1px solid #e2e8f0;
text-align: left;
}
#structure-visual {
border: 2px solid #e2e8f0;
border-radius: 0.75rem;
width: 100%;
height: 300px; /* Set a fixed height for the canvas container */
background-color: #fafafa;
}
</style>
</head>
<body class="p-4 bg-gray-100 min-h-screen flex items-center justify-center">
<div class="bg-white p-8 md:p-12 rounded-2xl shadow-2xl w-full max-w-4xl transform transition-all duration-500 hover:scale-105">
<h1 class="text-3xl font-bold text-center text-blue-900 mb-2">Silver Steel Mills</h1>
<h2 class="text-xl text-center text-gray-600 mb-8">Professional PEB (Pre-Engineered Building) Estimator</h2>
<div class="mb-6">
<label for="structure-type" class="block text-gray-700 font-semibold mb-2">Structure Type</label>
<select id="structure-type" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
<option value="dairy_shed">Dairy Shed (Light Duty)</option>
<option value="marquee_hall">Marquee Hall (Light Duty)</option>
<option value="warehouse">Warehouse (Heavy Duty)</option>
<option value="steel_shed">General Steel Shed (Medium Duty)</option>
<option value="prefabricated_home">Prefabricated Home (Light Duty)</option>
</select>
</div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6">
<div>
<label for="length" class="block text-gray-700 font-semibold mb-2">Length (feet)</label>
<input type="number" id="length" value="100" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
</div>
<div>
<label for="width" class="block text-gray-700 font-semibold mb-2">Width (feet)</label>
<input type="number" id="width" value="50" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
</div>
<div>
<label for="sideHeight" class="block text-gray-700 font-semibold mb-2">Eave Height (feet)</label>
<input type="number" id="sideHeight" value="15" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
</div>
<div>
<label for="centerHeight" class="block text-gray-700 font-semibold mb-2">Center Height (feet)</label>
<input type="number" id="centerHeight" value="20" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label for="baySpan" class="block text-gray-700 font-semibold mb-2">Bay Span (feet)</label>
<input type="number" id="baySpan" value="25" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
</div>
<div class="flex items-center justify-center p-4 rounded-lg border-2 border-gray-300 bg-gray-50">
<input type="checkbox" id="sidewallSheets" checked class="mr-2 h-5 w-5 rounded-md text-blue-600 focus:ring-blue-500">
<label for="sidewallSheets" class="text-gray-700 font-semibold">Include Sidewall Cladding?</label>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label for="purlinGauge" class="block text-gray-700 font-semibold mb-2">Purlin Gauge</label>
<select id="purlinGauge" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
<option value="16">16 Gauge (1.100 kg/ft)</option>
<option value="14">14 Gauge (1.310 kg/ft)</option>
</select>
</div>
<div>
<label for="glasswoolThickness" class="block text-gray-700 font-semibold mb-2">Glasswool Insulation</label>
<select id="glasswoolThickness" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
<option value="none">None</option>
<option value="25">25mm (PKR 35 / sqft)</option>
</select>
</div>
</div>
<div id="sheet-gauge-options" class="mb-6">
<label for="sheetGauge" class="block text-gray-700 font-semibold mb-2">Cladding Sheet Gauge</label>
<select id="sheetGauge" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
<option value="25">25 Gauge (0.417 kg/sft)</option>
<option value="26">26 Gauge (0.371 kg/sft)</option>
<option value="27">27 Gauge (0.331 kg/sft)</option>
</select>
</div>
<div id="sandwich-panel-options" class="mb-6 hidden">
<label for="sandwichPanelThickness" class="block text-gray-700 font-semibold mb-2">Sandwich Panel (EPS Thermopore)</label>
<select id="sandwichPanelThickness" class="w-full p-4 rounded-lg border-2 border-gray-300 focus:outline-none focus:border-blue-500 transition-colors">
<option value="50">50mm (PKR 350 / sqft)</option>
<option value="75">75mm (PKR 380 / sqft)</option>
<option value="100">100mm (PKR 410 / sqft)</option>
</select>
</div>
<div class="flex items-center justify-center p-4 rounded-lg border-2 border-gray-300 bg-gray-50 mb-6">
<input type="checkbox" id="includeLaborCharges" checked class="mr-2 h-5 w-5 rounded-md text-blue-600 focus:ring-blue-500">
<label for="includeLaborCharges" class="text-gray-700 font-semibold">Include Erection/Labor Charges?</label>
</div>
<button id="calculate-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-4 px-4 rounded-lg focus:outline-none focus:shadow-outline transition-colors duration-300 shadow-lg transform hover:-translate-y-1 hover:shadow-xl">
Calculate Quotation & Draw Layout
</button>
<div id="results" class="mt-10 p-8 bg-gray-50 rounded-xl border-2 border-gray-200 pdf-container">
<div class="header">
<h1 class="text-3xl font-bold text-blue-900">SILVER STEEL MILLS</h1>
<p class="text-sm text-gray-600">silversteelmills.com | +92 324 9500004</p>
<p class="text-lg font-bold text-gray-800 mt-6">PROJECT QUOTATION REPORT</p>
</div>
<div class="my-8">
<h3 class="text-xl font-semibold text-gray-800 mb-4 text-center">Structure Layout Drawing</h3>
<canvas id="structure-visual"></canvas>
</div>
<p id="error-message" class="text-red-500 font-semibold text-center hidden mb-4">
Please fill all fields correctly. Eave height must be greater than 5ft and less than the Center height, and Bay Span must be less than the total Length.
</p>
<h3 class="text-xl font-semibold text-gray-800 mb-4 text-left border-b pb-2">Estimated Costs Breakdown</h3>
<div class="space-y-4">
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Main Frame Steel Weight (kg) <span class="text-sm">(Columns & Rafters):</span></span>
<span id="mainframe-weight" class="font-bold text-gray-900 text-lg">0 kg</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Purlin Weight (kg):</span>
<span id="purlin-weight" class="font-bold text-gray-900 text-lg">0 kg</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Cladding Area (sq ft):</span>
<span id="sheet-area" class="font-bold text-gray-900 text-lg">0 sq ft</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium" id="material-label">Cladding Details:</span>
<span id="sheet-details" class="font-bold text-gray-900 text-lg">N/A</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Main Structure Cost (PKR):</span>
<span id="mainframe-cost" class="font-bold text-green-600 text-lg">PKR 0</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Purlin Cost (PKR):</span>
<span id="purlin-cost" class="font-bold text-green-600 text-lg">PKR 0</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium" id="sheeting-cost-label">Cladding/Panel Cost (PKR):</span>
<span id="sheet-cost" class="font-bold text-green-600 text-lg">PKR 0</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Insulation Cost (PKR):</span>
<span id="glasswool-cost" class="font-bold text-green-600 text-lg">PKR 0</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Total Material Cost (PKR):</span>
<span id="material-cost" class="font-bold text-green-600 text-lg">PKR 0</span>
</div>
<div class="flex justify-between items-center border-b pb-3 result-item">
<span class="text-gray-700 font-medium">Erection/Labor Cost (PKR):</span>
<span id="labor-cost" class="font-bold text-green-600 text-lg">PKR 0</span>
</div>
<div class="flex justify-between items-center result-item">
<span class="text-gray-700 font-medium">**Total Project Cost (PKR):**</span>
<span id="total-cost" class="font-bold text-3xl text-green-700">PKR 0</span>
</div>
</div>
<p class="text-sm text-center text-gray-500 mt-8 italic">
This estimation is based on the provided rates and standard PEB engineering principles. Actual rates and material requirements may vary based on your project and market fluctuations. Use for reference only.
</p>
<div class="mt-8 border-t pt-6">
<h3 class="text-xl font-semibold text-gray-800 mb-4 text-center">Terms and Conditions</h3>
<div class="text-sm text-gray-700 space-y-4">
<div>
<p class="font-bold mb-1">1. Design Codes and Loads</p>
<p>All structural design loads and engineering codes are based on current construction regulations, as per Section 1. Any changes requested by the client will require a revised quotation, including updated costs and timelines.</p>
</div>
<div>
<p class="font-bold mb-1">2. Drawings and Approvals</p>
<p>This quotation and the latest drawings supersede all previous documents, discussions, or revisions. Any changes in parameters during or after drawing approval will result in revised costs and a new delivery schedule, subject to both technical and commercial approval.</p>
</div>
<div>
<p class="font-bold mb-1">3. Material Supply & Delivery</p>
<p>Materials will be delivered promptly upon 100% advance payment. Fabrication can be managed at both the factory and the site, depending on project needs. Storage space for delivered materials must be provided by the client.</p>
</div>
<div>
<p class="font-bold mb-1">4. Payment Terms</p>
<h4 class="font-semibold mt-2 mb-1">A) Material Supply</h4>
<p>100% Advance Payment upon order confirmation.</p>
<h4 class="font-semibold mt-2 mb-1">B) Erection Work (Step-by-Step Payment Schedule)</h4>
<table class="terms-table w-full text-sm">
<thead>
<tr class="bg-gray-200">
<th>Stage</th>
<th>Payment</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td> <td>40%</td> <td>Upon confirmation of erection order</td>
</tr>
<tr>
<td>2</td> <td>30%</td> <td>After fabrication of main frames</td>
</tr>
<tr>
<td>3</td> <td>20%</td> <td>After erection of roofing, cladding, and structural works</td>
</tr>
<tr>
<td>4</td> <td>10%</td> <td>Upon final completion and client approval</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<button id="pdf-btn" class="w-full mt-4 bg-red-600 hover:bg-red-700 text-white font-bold py-4 px-4 rounded-lg focus:outline-none focus:shadow-outline transition-colors duration-300 shadow-lg transform hover:-translate-y-1 hover:shadow-xl">
Generate PDF Quotation
</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.min.js"></script>
<script>
const inputs = [
'length', 'width', 'sideHeight', 'centerHeight', 'baySpan',
'structure-type', 'sidewallSheets', 'purlinGauge',
'glasswoolThickness', 'sheetGauge', 'sandwichPanelThickness', 'includeLaborCharges'
];
inputs.forEach(id => {
const element = document.getElementById(id);
if (element) {
element.addEventListener('input', calculateCost);
element.addEventListener('change', calculateCost);
}
});
document.getElementById('calculate-btn').addEventListener('click', calculateCost);
document.getElementById('pdf-btn').addEventListener('click', generatePDF);
document.getElementById('structure-type').addEventListener('change', toggleMaterialOptions);
window.addEventListener('load', () => {
toggleMaterialOptions();
calculateCost();
});
const MAIN_FRAME_STEEL_PRICE_PER_KG_PKR = 270;
const MAIN_FRAME_WEIGHT_PER_FT_KG = 8.1;
const SECONDARY_STEEL_PRICE_PER_KG_PKR = 275;
const SHEETING_PRICE_PER_KG_PKR = 275;
const LABOR_RATE_PER_SQFT_PKR = 50;
const PURLIN_SPACING_FT = 5;
const PURLIN_OVERLAP_FT = 1;
const GAUGE_TO_MM = {'25': 0.51, '26': 0.46, '27': 0.41};
const PURLIN_WEIGHTS = {'16': 1.100, '14': 1.310};
const GLASSWOOL_COSTS = {'25': 35};
const SHEET_WEIGHTS = {'25': 0.417, '26': 0.371, '27': 0.331};
const SANDWICH_PANEL_COSTS = {'50': 350, '75': 380, '100': 410};
function toggleMaterialOptions() {
const structureType = document.getElementById('structure-type').value;
const sheetGaugeOptions = document.getElementById('sheet-gauge-options');
const sandwichPanelOptions = document.getElementById('sandwich-panel-options');
if (structureType === 'prefabricated_home') {
sheetGaugeOptions.classList.add('hidden');
sandwichPanelOptions.classList.remove('hidden');
} else {
sheetGaugeOptions.classList.remove('hidden');
sandwichPanelOptions.classList.add('hidden');
}
}
function visualizeStructure() {
const canvas = document.getElementById('structure-visual');
const ctx = canvas.getContext('2d');
const length = parseFloat(document.getElementById('length').value) || 0;
const width = parseFloat(document.getElementById('width').value) || 0;
const sideHeight = parseFloat(document.getElementById('sideHeight').value) || 0;
const centerHeight = parseFloat(document.getElementById('centerHeight').value) || 0;
const baySpan = parseFloat(document.getElementById('baySpan').value) || 0;
const hasSidewalls = document.getElementById('sidewallSheets').checked;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (width <= 0 || sideHeight <= 0 || centerHeight <= 0 || centerHeight <= sideHeight || length <= 0 || baySpan <= 0 || baySpan > length) {
ctx.font = "16px Arial";
ctx.fillStyle = "#ef4444";
ctx.textAlign = "center";
ctx.fillText("Provide valid dimensions to draw the layout.", canvas.width / 2, canvas.height / 2);
return;
}
const padding = 50;
const perspAngle = 0.5;
const lengthRatio = 0.4;
const totalProjectedWidth = width + length * perspAngle * lengthRatio;
const totalProjectedHeight = centerHeight + length * perspAngle * lengthRatio * 0.5;
const scale = Math.min((canvas.width - padding * 2) / totalProjectedWidth, (canvas.height - padding * 2) / totalProjectedHeight);
const scaledWidth = width * scale;
const scaledSideHeight = sideHeight * scale;
const scaledCenterHeight = centerHeight * scale;
const scaledLength = length * scale * lengthRatio;
const offsetX = (canvas.width - (scaledWidth + scaledLength * perspAngle)) / 2;
const offsetY = (canvas.height + scaledCenterHeight) / 2 + 30;
const drawFrame = (x_offset, y_offset) => {
const p1 = { x: offsetX + x_offset, y: offsetY + y_offset }; // bottom-left
const p2 = { x: offsetX + x_offset, y: offsetY - scaledSideHeight + y_offset }; // top-left
const p3 = { x: offsetX + scaledWidth / 2 + x_offset, y: offsetY - scaledCenterHeight + y_offset }; // top-center
const p4 = { x: offsetX + scaledWidth + x_offset, y: offsetY - scaledSideHeight + y_offset }; // top-right
const p5 = { x: offsetX + scaledWidth + x_offset, y: offsetY + y_offset }; // bottom-right
return [p1, p2, p3, p4, p5];
};
const persp = { x: scaledLength * perspAngle, y: -scaledLength * perspAngle * 0.5 };
const frontFrame = drawFrame(0, 0);
const backFrame = drawFrame(persp.x, persp.y);
const numberOfFrames = Math.floor(length / baySpan) + 1;
// --- Main Drawing Logic ---
// ALWAYS DRAW ROOF
ctx.strokeStyle = '#0284c7';
ctx.lineWidth = 1.5;
ctx.fillStyle = 'rgba(14, 165, 233, 0.1)';
// Roof Right
ctx.beginPath();
ctx.moveTo(frontFrame[2].x, frontFrame[2].y); ctx.lineTo(frontFrame[3].x, frontFrame[3].y);
ctx.lineTo(backFrame[3].x, backFrame[3].y); ctx.lineTo(backFrame[2].x, backFrame[2].y);
ctx.closePath();
ctx.fill(); ctx.stroke();
// Roof Left
ctx.beginPath();
ctx.moveTo(frontFrame[1].x, frontFrame[1].y); ctx.lineTo(frontFrame[2].x, frontFrame[2].y);
ctx.lineTo(backFrame[2].x, backFrame[2].y); ctx.lineTo(backFrame[1].x, backFrame[1].y);
ctx.closePath();
ctx.fill(); ctx.stroke();
// Corrugated lines on roof
ctx.strokeStyle = 'rgba(125, 211, 252, 0.3)';
ctx.lineWidth = 1;
for (let i = 0; i < 1; i += 0.05) {
let p_start_r = { x: frontFrame[2].x * (1 - i) + backFrame[2].x * i, y: frontFrame[2].y * (1 - i) + backFrame[2].y * i };
let p_end_r = { x: frontFrame[3].x * (1 - i) + backFrame[3].x * i, y: frontFrame[3].y * (1 - i) + backFrame[3].y * i };
ctx.beginPath(); ctx.moveTo(p_start_r.x, p_start_r.y); ctx.lineTo(p_end_r.x, p_end_r.y); ctx.stroke();
let p_start_l = { x: frontFrame[1].x * (1 - i) + backFrame[1].x * i, y: frontFrame[1].y * (1 - i) + backFrame[1].y * i };
let p_end_l = { x: frontFrame[2].x * (1 - i) + backFrame[2].x * i, y: frontFrame[2].y * (1 - i) + backFrame[2].y * i };
ctx.beginPath(); ctx.moveTo(p_start_l.x, p_start_l.y); ctx.lineTo(p_end_l.x, p_end_l.y); ctx.stroke();
}
if (hasSidewalls) {
ctx.strokeStyle = '#0284c7';
ctx.lineWidth = 1.5;
// Side Wall
ctx.fillStyle = 'rgba(14, 165, 233, 0.1)';
ctx.beginPath();
ctx.moveTo(frontFrame[3].x, frontFrame[3].y); ctx.lineTo(frontFrame[4].x, frontFrame[4].y);
ctx.lineTo(backFrame[4].x, backFrame[4].y); ctx.lineTo(backFrame[3].x, backFrame[3].y);
ctx.closePath();
ctx.fill(); ctx.stroke();
// Front Wall
ctx.fillStyle = 'rgba(14, 165, 233, 0.2)';
ctx.beginPath();
frontFrame.forEach(p => ctx.lineTo(p.x, p.y));
ctx.closePath();
ctx.fill(); ctx.stroke();
} else {
// Draw all frames
ctx.strokeStyle = '#334155';
ctx.lineWidth = 2;
for (let i = 0; i < numberOfFrames; i++) {
const progress = i / (numberOfFrames - 1);
const frame = drawFrame(persp.x * progress, persp.y * progress);
ctx.beginPath();
ctx.moveTo(frame[0].x, frame[0].y);
frame.forEach(p => ctx.lineTo(p.x, p.y));
ctx.stroke();
}
// Draw Girts (wall supports)
ctx.strokeStyle = '#64748b';
ctx.lineWidth = 1;
const girtCount = 3;
for (let i = 1; i <= girtCount; i++) {
const progress = i / (girtCount + 1);
// Right wall girts
const p_start_r = { x: frontFrame[4].x * (1 - progress) + frontFrame[3].x * progress, y: frontFrame[4].y * (1 - progress) + frontFrame[3].y * progress };
const p_end_r = { x: backFrame[4].x * (1 - progress) + backFrame[3].x * progress, y: backFrame[4].y * (1 - progress) + backFrame[3].y * progress };
ctx.beginPath(); ctx.moveTo(p_start_r.x, p_start_r.y); ctx.lineTo(p_end_r.x, p_end_r.y); ctx.stroke();
// Left wall girts
const p_start_l = { x: frontFrame[0].x * (1 - progress) + frontFrame[1].x * progress, y: frontFrame[0].y * (1 - progress) + frontFrame[1].y * progress };
const p_end_l = { x: backFrame[0].x * (1 - progress) + backFrame[1].x * progress, y: backFrame[0].y * (1 - progress) + backFrame[1].y * progress };
ctx.beginPath(); ctx.moveTo(p_start_l.x, p_start_l.y); ctx.lineTo(p_end_l.x, p_end_l.y); ctx.stroke();
}
}
// Labels
ctx.fillStyle = '#1e293b';
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'center';
ctx.fillText(`${width} ft (Width)`, (frontFrame[0].x + frontFrame[4].x) / 2, frontFrame[0].y + 20);
ctx.fillText(`${length} ft (Length)`, (frontFrame[4].x + backFrame[4].x) / 2 + 10, (frontFrame[4].y + backFrame[4].y) / 2 + 15);
ctx.textAlign = 'left';
ctx.fillText(`${sideHeight} ft (Eave)`, frontFrame[0].x - 45, frontFrame[0].y - scaledSideHeight/2);
}
function calculateCost() {
const structureType = document.getElementById('structure-type').value;
const length = parseFloat(document.getElementById('length').value);
const width = parseFloat(document.getElementById('width').value);
const sideHeight = parseFloat(document.getElementById('sideHeight').value);
const centerHeight = parseFloat(document.getElementById('centerHeight').value);
const baySpan = parseFloat(document.getElementById('baySpan').value);
const hasSidewallSheets = document.getElementById('sidewallSheets').checked;
const glasswoolThickness = document.getElementById('glasswoolThickness').value;
const purlinGauge = document.getElementById('purlinGauge').value;
const includeLaborCharges = document.getElementById('includeLaborCharges').checked;
visualizeStructure();
const errorMessage = document.getElementById('error-message');
if (isNaN(length) || isNaN(width) || isNaN(sideHeight) || isNaN(centerHeight) || isNaN(baySpan) ||
length <= 0 || width <= 0 || sideHeight <= 0 || centerHeight <= 0 || baySpan <= 0 || baySpan > length || centerHeight <= sideHeight) {
errorMessage.classList.remove('hidden');
return;
}
if (sideHeight < 5 || sideHeight > 50) {
errorMessage.classList.remove('hidden');
return;
}
errorMessage.classList.add('hidden');
const eaveHeight = sideHeight;
const roofHeightDifference = centerHeight - sideHeight;
const halfWidth = width / 2;
const slantHeight = Math.sqrt(Math.pow(halfWidth, 2) + Math.pow(roofHeightDifference, 2));
const effectiveSheetWidth = 39 / 12;
const numberOfSheets = Math.ceil(length / effectiveSheetWidth);
const totalSideOverlap = (numberOfSheets > 0 ? numberOfSheets - 1 : 0) * (3 / 12);
const effectiveRoofLength = length + totalSideOverlap;
const numberOfSheetRows = Math.ceil(slantHeight / 20);
const totalLengthOverlap = (numberOfSheetRows > 0 ? numberOfSheetRows - 1 : 0) * (4/12);
const effectiveRoofSlantHeight = slantHeight + totalLengthOverlap;
const roofArea = effectiveRoofLength * effectiveRoofSlantHeight * 2;
let sidewallArea = 0;
if (hasSidewallSheets) {
sidewallArea = 2 * (length + width) * eaveHeight;
}
const totalCladdingArea = roofArea + sidewallArea;
const numberOfFrames = Math.ceil(length / baySpan) + 1;
const lengthOfOneFrame = (sideHeight * 2) + (slantHeight * 2);
const totalFrameLength = lengthOfOneFrame * numberOfFrames;
const estimatedMainStructuralWeightKg = totalFrameLength * MAIN_FRAME_WEIGHT_PER_FT_KG;
const mainStructuralCost = estimatedMainStructuralWeightKg * MAIN_FRAME_STEEL_PRICE_PER_KG_PKR;
const purlinLinesPerSlope = Math.floor(slantHeight / PURLIN_SPACING_FT) + 1;
const totalPurlinLines = purlinLinesPerSlope * 2;
const numberOfBays = Math.ceil(length / baySpan);
const totalPurlinOverlapLength = totalPurlinLines * (numberOfBays - 1) * PURLIN_OVERLAP_FT;
const purlinTotalLength = (totalPurlinLines * length) + totalPurlinOverlapLength;
const estimatedPurlinWeightKg = purlinTotalLength * PURLIN_WEIGHTS[purlinGauge];
const purlinCost = estimatedPurlinWeightKg * SECONDARY_STEEL_PRICE_PER_KG_PKR;
let claddingCost = 0;
let materialLabel = "Cladding Sheet Cost (PKR):";
let materialDetails = "";
if (structureType === 'prefabricated_home') {
const sandwichPanelThickness = document.getElementById('sandwichPanelThickness').value;
claddingCost = totalCladdingArea * SANDWICH_PANEL_COSTS[sandwichPanelThickness];
materialLabel = "Sandwich Panel Cost (PKR):";
materialDetails = `Panel Thickness: ${sandwichPanelThickness}mm`;
} else {
const sheetGauge = document.getElementById('sheetGauge').value;
const estimatedSheetWeightKg = totalCladdingArea * SHEET_WEIGHTS[sheetGauge];
claddingCost = estimatedSheetWeightKg * SHEETING_PRICE_PER_KG_PKR;
materialDetails = `Sheet Gauge: ${sheetGauge} (${GAUGE_TO_MM[sheetGauge]} mm)`;
}
let glasswoolCost = (glasswoolThickness !== 'none') ? roofArea * GLASSWOOL_COSTS[glasswoolThickness] : 0;
const totalMaterialCost = mainStructuralCost + purlinCost + claddingCost + glasswoolCost;
let laborCost = includeLaborCharges ? totalCladdingArea * LABOR_RATE_PER_SQFT_PKR : 0;
const totalCost = totalMaterialCost + laborCost;
document.getElementById('mainframe-weight').textContent = `${estimatedMainStructuralWeightKg.toFixed(2)} kg`;
document.getElementById('purlin-weight').textContent = `${estimatedPurlinWeightKg.toFixed(2)} kg`;
document.getElementById('sheet-area').textContent = `${totalCladdingArea.toFixed(2)} sq ft`;
document.getElementById('sheet-details').textContent = materialDetails;
document.getElementById('mainframe-cost').textContent = `PKR ${mainStructuralCost.toFixed(2)}`;
document.getElementById('purlin-cost').textContent = `PKR ${purlinCost.toFixed(2)}`;
document.getElementById('sheeting-cost-label').textContent = materialLabel;
document.getElementById('sheet-cost').textContent = `PKR ${claddingCost.toFixed(2)}`;
document.getElementById('glasswool-cost').textContent = `PKR ${glasswoolCost.toFixed(2)}`;
document.getElementById('material-cost').textContent = `PKR ${totalMaterialCost.toFixed(2)}`;
document.getElementById('labor-cost').textContent = `PKR ${laborCost.toFixed(2)}`;
document.getElementById('total-cost').textContent = `PKR ${totalCost.toFixed(2)}`;
}
function generatePDF() {
const element = document.getElementById('results');
html2pdf(element, {
margin: 0.5,
filename: 'Silver_Steel_Quotation.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, logging: false, useCORS: true },
jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
});
}
</script>
</body>
</html>