/** * INTEGRATION PATCH FOR STDDEV RANGES * ==================================== * * This shows how to integrate the StdDev calculator into the existing * Direct Calculation button handler in roll_calculator.html * * CHANGES: * 1. Load stddev data from article-data.json when article is selected * 2. Modify the d-calc button handler to use ranges * 3. Update Forklift checker to use worst-case weight * 4. Keep everything backward compatible */ // =================================================================== // PATCH 1: STORE STDDEV IN HIDDEN FIELDS DURING ARTICLE SELECTION // =================================================================== // Add this to populateArticleDropdowns_v14() in rollcalc_improvements.js // In the article selection handler for d-art: /* if (match) { console.log('[Article Select] Found:', match.nr, '- Thickness:', match.thickness, 'Area Weight:', match.area_weight); // 1. Auto-fill Thickness document.getElementById('d-th').value = match.thickness; // 2. Auto-fill Area Weight if (match.area_weight && match.area_weight > 0) { document.getElementById('d-aw').value = match.area_weight; } // 3. Auto-fill Roll Width var widthMatch = match.name.match(/(\d+[,\.]\d+)\s*x\s*\d+/); if (widthMatch) { var width = widthMatch[1].replace(',', '.'); document.getElementById('de-wi').value = width; } // NEW: Store stddev values in hidden attributes document.getElementById('d-th').dataset.stddev = match.thickness_stddev || 0; document.getElementById('d-aw').dataset.stddev = match.area_weight_stddev || 0; console.log('[StdDev] Stored:', { thickness_stddev: match.thickness_stddev, area_weight_stddev: match.area_weight_stddev }); setTimeout(function() { triggerAutoWeightCalculation(); }, 50); } */ // =================================================================== // PATCH 2: MODIFY d-calc BUTTON HANDLER FOR DIAMETER MODE // =================================================================== // Replace the diameter calculation section in the d-calc click handler: /* OLD CODE (diameter mode): if (mode === 'diameter') { if (!d_mm || !t_mm || !L_m) { alert('Please enter d, t and L.'); return; } const D_nom = Math.sqrt(d_mm*d_mm + (4*L_m*1000*t_mm)/Math.PI); resLabel.textContent = 'Roll Diameter (D)'; resVal.textContent = D_nom.toFixed(1) + ' mm'; if (tol) { const D_min = Math.sqrt(d_mm*d_mm + (4*L_m*1000*(t_mm-tol))/Math.PI); const D_max = Math.sqrt(d_mm*d_mm + (4*L_m*1000*(t_mm+tol))/Math.PI); resRange.textContent = 'Min: ' + D_min.toFixed(1) + ' mm | Max: ' + D_max.toFixed(1) + ' mm'; } else { resRange.textContent = ''; } document.getElementById('d-di').value = D_nom.toFixed(1); calculatedLength = L_m; } NEW CODE (with stddev): */ // Example replacement for diameter mode: function calculateDiameterWithStddev(d_mm, t_mm, t_stddev, L_m, tol) { if (!d_mm || !t_mm || !L_m) { alert('Please enter d, t and L.'); return false; } // Get stddev from data attribute (set during article selection) const thField = document.getElementById('d-th'); const actualStddev = t_stddev || parseFloat(thField?.dataset.stddev || 0); const resBox = document.getElementById('d-result'); const resLabel = document.getElementById('d-res-label'); const resVal = document.getElementById('d-res-val'); const resRange = document.getElementById('d-res-range'); const diField = document.getElementById('d-di'); // Use StdDev calculator const diameterRanges = window.StdDevCalculator.calculateDiameterRanges( d_mm, t_mm, actualStddev, L_m ); resLabel.textContent = 'Roll Diameter (D)'; resVal.textContent = diameterRanges.nom.toFixed(1) + ' mm'; // Show ±2σ range const d_low = Math.min(diameterRanges.min, diameterRanges.max); const d_high = Math.max(diameterRanges.min, diameterRanges.max); let rangeText = `Range (±2σ): ${d_low.toFixed(1)} – ${d_high.toFixed(1)} mm`; if (tol && tol > 0) { const d_tol_min = diameterRanges.nom - tol; const d_tol_max = diameterRanges.nom + tol; rangeText += ` | Tol: ${d_tol_min.toFixed(1)} – ${d_tol_max.toFixed(1)} mm`; } resRange.textContent = rangeText; diField.value = diameterRanges.nom.toFixed(1); resBox.style.display = 'block'; console.log('[StdDev-Calc] Diameter with ranges:', diameterRanges); return { calculatedLength: L_m, diameterRanges: diameterRanges }; } // =================================================================== // PATCH 3: MODIFY WEIGHT CALCULATION FOR STDDEV RANGES // =================================================================== // Replace the weight calculation in calcWeight(): /* OLD: function calcWeight(length) { const wi = parseFloat(document.getElementById('de-wi').value) || 0; const aw = parseFloat(document.getElementById('d-aw').value) || 0; if (wi > 0 && aw > 0 && length > 0) { const w = (aw * length * wi / 1000).toFixed(1); document.getElementById('d-wo').value = w; return parseFloat(w); } document.getElementById('d-wo').value = ''; return null; } NEW: */ function calcWeightWithStddev(length) { const wi = parseFloat(document.getElementById('de-wi').value) || 0; const aw = parseFloat(document.getElementById('d-aw').value) || 0; const awField = document.getElementById('d-aw'); const awStddev = parseFloat(awField?.dataset.stddev || 0); if (wi > 0 && aw > 0 && length > 0) { // Calculate weight ranges const weightRanges = window.StdDevCalculator.calculateWeightRanges( aw, awStddev, length, wi ); // Store in field and data attributes const woField = document.getElementById('d-wo'); woField.value = weightRanges.nom.toFixed(1); woField.dataset.weight_nom = weightRanges.nom.toFixed(1); woField.dataset.weight_min = weightRanges.min.toFixed(1); woField.dataset.weight_max = weightRanges.max.toFixed(1); console.log('[StdDev-Weight] Calculated ranges:', { nom: weightRanges.nom.toFixed(1), min: weightRanges.min.toFixed(1), max: weightRanges.max.toFixed(1) }); return weightRanges; } document.getElementById('d-wo').value = ''; return null; } // =================================================================== // PATCH 4: UPDATE FORKLIFT CHECKER TO USE WORST-CASE // =================================================================== // In ForkliftChecker.evaluate(), use worst-case weight: /* OLD: evaluate(weightKg, coreMm, category) { const box = document.getElementById('forkliftCheck'); // ... check if weightKg > limit } NEW: */ function evaluateForkliftWithWorstCase(coreMm, category) { const woField = document.getElementById('d-wo'); if (!woField) return true; // Get worst-case weight const weight_nom = parseFloat(woField.value) || 0; const weight_max = parseFloat(woField.dataset.weight_max) || weight_nom; // Use maximum for safety const weightToCheck = Math.max(weight_nom, weight_max); console.log('[Forklift-StdDev] Using worst-case weight:', { nominal: weight_nom.toFixed(1), worst_case: weight_max.toFixed(1), checking: weightToCheck.toFixed(1) }); if (window.ForkliftChecker) { return window.ForkliftChecker.evaluate(weightToCheck, coreMm, category); } return true; } // =================================================================== // COMPLETE EXAMPLE: NEW d-calc HANDLER WITH STDDEV // =================================================================== /* document.getElementById('d-calc').addEventListener('click', () => { const mode = document.querySelector('.mode-btn.active')?.dataset.mode || 'diameter'; const d_mm = parseFloat(document.getElementById('d-co').value) || 0; const t_mm = parseFloat(document.getElementById('d-th').value) || 0; const tol = parseFloat(document.getElementById('d-tol').value) || 0; const L_m = parseFloat(document.getElementById('d-le').value) || 0; const D_mm = parseFloat(document.getElementById('d-di').value) || 0; const category = (document.getElementById('d-cat')?.value || '').toLowerCase(); if (mode === 'diameter') { // Use new function with stddev const result = calculateDiameterWithStddev(d_mm, t_mm, null, L_m, tol); if (!result) return; const calculatedLength = result.calculatedLength; const diameterRanges = result.diameterRanges; // Calculate weight with stddev const weightRanges = calcWeightWithStddev(calculatedLength); // Evaluate forklift with worst-case weight evaluateForkliftWithWorstCase(d_mm, category); // Store for Load Optimizer (use nominal) if (weightRanges) { window.loadOptimizerUI.optimizer.setRollData({ rollDiameter: diameterRanges.nom, coreDiameter: d_mm, rollWidth: parseFloat(document.getElementById('de-wi').value) || 0, rollWeight: weightRanges.nom, // Nominal for optimizer m2PerRoll: calculatedLength * (parseFloat(document.getElementById('de-wi').value) || 0), productLength: calculatedLength }); } } // ... handle other modes ... }); */ // =================================================================== // EXPORT FUNCTIONS // =================================================================== window.StdDevIntegration = { calculateDiameterWithStddev: calculateDiameterWithStddev, calcWeightWithStddev: calcWeightWithStddev, evaluateForkliftWithWorstCase: evaluateForkliftWithWorstCase }; console.log('[StdDevIntegration] Integration functions ready');