class UnitManager { constructor() { this.currentUnit = 'px'; // Default unit this.pixelsPerUnit = { 'px': 1, 'cm': 37.795275591, // 1 cm = ~37.8 pixels at 96 DPI 'm': 3779.5275591, // 1 meter = ~3780 pixels at 96 DPI 'ft': 1152, // 1 foot = 1152 pixels at 96 DPI 'in': 96 // 1 inch = 96 pixels at 96 DPI }; this.unitLabels = { 'px': 'px', 'cm': 'cm', 'm': 'm', 'ft': 'ft', 'in': 'in' }; this.setupEventListeners(); } setupEventListeners() { const unitsSelect = document.getElementById('unitsSelect'); if (unitsSelect) { unitsSelect.addEventListener('change', (e) => { this.setUnit(e.target.value); }); } } setUnit(unit) { if (this.pixelsPerUnit[unit]) { this.currentUnit = unit; this.updateAllMeasurements(); console.log(`Units changed to: ${unit}`); } } getCurrentUnit() { return this.currentUnit; } // Convert pixels to current unit pixelsToUnit(pixels) { return pixels / this.pixelsPerUnit[this.currentUnit]; } // Convert current unit to pixels unitToPixels(value) { return value * this.pixelsPerUnit[this.currentUnit]; } // Convert between any two units convertUnits(value, fromUnit, toUnit) { const pixels = value * this.pixelsPerUnit[fromUnit]; return pixels / this.pixelsPerUnit[toUnit]; } // Format a value with the current unit formatValue(pixels, precision = 2) { const value = this.pixelsToUnit(pixels); return `${value.toFixed(precision)}${this.unitLabels[this.currentUnit]}`; } // Parse a value string (e.g., "10cm", "5ft") to pixels parseValue(valueString) { const match = valueString.match(/^([\d.]+)\s*([a-zA-Z]+)$/); if (match) { const value = parseFloat(match[1]); const unit = match[2].toLowerCase(); if (this.pixelsPerUnit[unit]) { return this.unitToPixels(value); } } // If no unit specified, assume current unit const value = parseFloat(valueString); return isNaN(value) ? 0 : this.unitToPixels(value); } // Update all measurements in the UI updateAllMeasurements() { // Update wall thickness display const wallThicknessSlider = document.getElementById('wallThicknessSliderTop'); const wallThicknessValue = document.getElementById('wallThicknessValueTop'); if (wallThicknessSlider && wallThicknessValue) { const pixels = parseInt(wallThicknessSlider.value); wallThicknessValue.textContent = this.formatValue(pixels); } // Update any other measurements in the UI this.updateGridSize(); this.updateMeasurementLabels(); } // Update grid size based on current unit updateGridSize() { if (window.app && window.app.canvasManager) { // Adjust grid size to be meaningful in current unit let gridSize; switch (this.currentUnit) { case 'px': gridSize = 20; break; case 'cm': gridSize = this.unitToPixels(10); // 10cm grid break; case 'm': gridSize = this.unitToPixels(1); // 1m grid break; case 'ft': gridSize = this.unitToPixels(1); // 1ft grid break; case 'in': gridSize = this.unitToPixels(12); // 12in (1ft) grid break; default: gridSize = 20; } window.app.canvasManager.gridSize = gridSize; if (window.app.canvasManager.showGrid) { window.app.redraw(); } } } // Update measurement labels throughout the UI updateMeasurementLabels() { // Update any existing measurement displays const measurementElements = document.querySelectorAll('[data-measurement]'); measurementElements.forEach(element => { const pixels = parseFloat(element.dataset.measurement); if (!isNaN(pixels)) { element.textContent = this.formatValue(pixels); } }); } // Get appropriate precision for current unit getPrecision() { switch (this.currentUnit) { case 'px': return 0; // Whole pixels case 'cm': return 1; // 1 decimal place case 'm': return 2; // 2 decimal places case 'ft': return 2; // 2 decimal places case 'in': return 1; // 1 decimal place default: return 2; } } // Get reasonable step size for input controls getStepSize() { switch (this.currentUnit) { case 'px': return 1; case 'cm': return 0.1; case 'm': return 0.01; case 'ft': return 0.1; case 'in': return 0.1; default: return 1; } } // Create a formatted input for measurements createMeasurementInput(value, onChange) { const input = document.createElement('input'); input.type = 'number'; input.step = this.getStepSize(); input.value = this.pixelsToUnit(value).toFixed(this.getPrecision()); input.className = 'w-20 px-2 py-1 text-sm border border-gray-300 rounded'; const unitLabel = document.createElement('span'); unitLabel.textContent = this.unitLabels[this.currentUnit]; unitLabel.className = 'text-sm text-gray-600 ml-1'; input.addEventListener('change', (e) => { const pixels = this.unitToPixels(parseFloat(e.target.value) || 0); onChange(pixels); }); const container = document.createElement('div'); container.className = 'flex items-center'; container.appendChild(input); container.appendChild(unitLabel); return container; } }