document.addEventListener('DOMContentLoaded', function() { const fileInput = document.getElementById('file-upload'); const fileInfo = document.getElementById('file-info'); const fileName = document.getElementById('file-name'); const fileSize = document.getElementById('file-size'); const removeFileBtn = document.getElementById('remove-file'); const analysisSection = document.getElementById('analysis-section'); const resultsSection = document.getElementById('results-section'); const analyzeBtn = document.getElementById('analyze-btn'); const exportExcelBtn = document.getElementById('export-excel'); const resultsTable = document.getElementById('results-table'); // Drag and drop functionality const dropZone = document.querySelector('.border-dashed'); ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, preventDefaults, false); }); // Helper function to format timber dimensions function formatTimberDimensions(width, height) { return `${(width*1000).toFixed(0)}x${(height*1000).toFixed(0)}`; } function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ['dragenter', 'dragover'].forEach(eventName => { dropZone.addEventListener(eventName, highlight, false); }); ['dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, unhighlight, false); }); function highlight() { dropZone.classList.add('border-blue-500'); dropZone.classList.add('bg-blue-50'); } function unhighlight() { dropZone.classList.remove('border-blue-500'); dropZone.classList.remove('bg-blue-50'); } dropZone.addEventListener('drop', handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; handleFiles(files); } fileInput.addEventListener('change', function() { handleFiles(this.files); }); function handleFiles(files) { if (files.length > 0) { const file = files[0]; if (file.name.endsWith('.ifc')) { fileName.textContent = file.name; fileSize.textContent = formatFileSize(file.size); fileInfo.classList.remove('hidden'); analysisSection.classList.remove('hidden'); resultsSection.classList.add('hidden'); } else { alert('Please upload a valid .ifc file'); } } } removeFileBtn.addEventListener('click', function() { fileInput.value = ''; fileInfo.classList.add('hidden'); analysisSection.classList.add('hidden'); resultsSection.classList.add('hidden'); }); function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } analyzeBtn.addEventListener('click', function() { // Simulate analysis (in a real app, this would use an IFC parser library) analyzeBtn.innerHTML = '🌀 Analyzing...'; analyzeBtn.disabled = true; setTimeout(() => { // Enhanced mock data with more detailed analysis const mockData = { elements: 156, properties: 412, materials: 24, quantities: 67, totalArea: 0, totalVolume: 0, groups: { 'Walls': [], 'Doors': [], 'Windows': [], 'Structural': [], 'Furniture': [], 'Plumbing': [], 'Electrical': [], 'HVAC': [], 'Other': [], 'Timber': [] }, timberTypes: { 'C24 45x195': [], 'C24 70x195': [], 'C24 95x195': [], 'GL24h 120x120': [], 'GL24h 160x160': [], 'GL24h 200x200': [] }, items: [ { id: '12345', type: 'Wall', name: 'Interior Wall 1', properties: 15, width: 0.2, height: 2.7, depth: 5.8, area: 15.66, volume: 3.132, material: 'Gypsum Board', group: 'Walls', location: 'Level 1', classification: 'Interior Partition', propertiesList: [ {name: 'Fire Rating', value: '60 min'}, {name: 'STC Rating', value: '45'}, {name: 'U-Value', value: '0.35 W/m²K'} ] }, { id: '12346', type: 'Door', name: 'Main Entrance', properties: 12, width: 1.0, height: 2.1, depth: 0.1, area: 2.1, volume: 0.21, material: 'Wood', group: 'Doors', location: 'Level 1', classification: 'Fire Exit', propertiesList: [ {name: 'Fire Rating', value: '90 min'}, {name: 'Material', value: 'Solid Core'}, {name: 'Swing', value: 'Double'}, {name: 'Finish', value: 'Stained Oak'} ] }, { id: '12347', type: 'Window', name: 'Living Room Window', properties: 14, width: 1.5, height: 1.2, depth: 0.2, area: 1.8, volume: 0.36, material: 'Aluminum/Glass', group: 'Windows', location: 'Level 1', classification: 'Fixed Glazing', propertiesList: [ {name: 'U-Value', value: '1.4 W/m²K'}, {name: 'SHGC', value: '0.35'}, {name: 'Glazing', value: 'Double Low-E'}, {name: 'Frame', value: 'Thermal Break'} ] }, { id: '12348', type: 'Slab', name: 'First Floor', properties: 18, width: 12.0, height: 0.3, depth: 8.0, area: 96.0, volume: 28.8, material: 'Concrete', group: 'Structural', location: 'Level 1', classification: 'Composite Deck', propertiesList: [ {name: 'Concrete Strength', value: '4000 psi'}, {name: 'Reinforcement', value: '#4 @ 12" OC'}, {name: 'Fire Rating', value: '2 hr'}, {name: 'Topping', value: '2" Lightweight'} ] }, { id: '12349', type: 'Column', name: 'Structural Column A', properties: 16, width: 0.4, height: 3.0, depth: 0.4, area: 4.8, volume: 0.48, material: 'Steel', group: 'Structural', location: 'Grid A-1', classification: 'HSS Column', propertiesList: [ {name: 'Shape', value: 'HSS6x6x1/4'}, {name: 'Material Grade', value: 'A500 Gr.B'}, {name: 'Fireproofing', value: 'Spray-applied'}, {name: 'Connection Type', value: 'Moment'} ] }, { id: '12350', type: 'Timber', name: 'Roof Beam 1', properties: 14, width: 0.045, height: 0.195, length: 4.8, area: 0.936, volume: 0.042, material: 'C24 45x195', group: 'Timber', location: 'Roof Level', classification: 'Structural Timber', propertiesList: [ {name: 'Grade', value: 'C24'}, {name: 'Section', value: '45x195 mm'}, {name: 'Moisture Content', value: '18%'}, {name: 'Treatment', value: 'Tanalith E'} ] }, { id: '12351', type: 'Timber', name: 'Floor Joist 1', properties: 14, width: 0.07, height: 0.195, length: 3.6, area: 0.702, volume: 0.049, material: 'C24 70x195', group: 'Timber', location: 'First Floor', classification: 'Structural Timber', propertiesList: [ {name: 'Grade', value: 'C24'}, {name: 'Section', value: '70x195 mm'}, {name: 'Moisture Content', value: '18%'}, {name: 'Treatment', value: 'Tanalith E'} ] }, { id: '12352', type: 'Timber', name: 'Wall Stud 1', properties: 14, width: 0.045, height: 0.195, length: 2.7, area: 0.526, volume: 0.024, material: 'C24 45x195', group: 'Timber', location: 'Wall A', classification: 'Structural Timber', propertiesList: [ {name: 'Grade', value: 'C24'}, {name: 'Section', value: '45x195 mm'}, {name: 'Moisture Content', value: '18%'}, {name: 'Treatment', value: 'Tanalith E'} ] }, { id: '12353', type: 'Timber', name: 'Glulam Beam', properties: 14, width: 0.16, height: 0.16, length: 5.4, area: 0.864, volume: 0.138, material: 'GL24h 160x160', group: 'Timber', location: 'Main Hall', classification: 'Structural Timber', propertiesList: [ {name: 'Grade', value: 'GL24h'}, {name: 'Section', value: '160x160 mm'}, {name: 'Moisture Content', value: '12%'}, {name: 'Fire Rating', value: 'R30'} ] }, ] }; // Calculate totals and group items mockData.items.forEach(item => { mockData.totalArea += item.area; mockData.totalVolume += item.volume; mockData.groups[item.group].push(item); // Group timber by type if (item.group === 'Timber' && mockData.timberTypes[item.material]) { mockData.timberTypes[item.material].push(item); } }); // Calculate timber summaries const timberSummaries = {}; for (const [type, items] of Object.entries(mockData.timberTypes)) { if (items.length > 0) { const totalLength = items.reduce((sum, item) => sum + item.length, 0); timberSummaries[type] = { count: items.length, totalLength: totalLength.toFixed(2), totalVolume: items.reduce((sum, item) => sum + item.volume, 0).toFixed(3), section: items[0].width*1000 + 'x' + items[0].height*1000 + ' mm' }; } } // Update counts and totals document.getElementById('elements-count').textContent = mockData.elements; document.getElementById('properties-count').textContent = mockData.properties; document.getElementById('materials-count').textContent = mockData.materials; document.getElementById('quantities-count').textContent = mockData.quantities; document.getElementById('total-volume').textContent = mockData.totalVolume.toFixed(3) + ' m³'; // Add timber summary section if (Object.keys(timberSummaries).length > 0) { const resultsContainer = document.querySelector('#results-section .max-w-4xl'); let timberHTML = `
| Type | Section | Count | Total Length | Total Volume |
|---|---|---|---|---|
| ${type} | ${summary.section} | ${summary.count} | ${summary.totalLength} m | ${summary.totalVolume} m³ |