Skip to content

Tire Pressure Calculator – Reference Notes

Ce fichier sert uniquement de notes et de référence pour le portage du calculateur de pression dans le backend (voir src/lib/tools/tire-pressure.ts). Il ne fait pas partie du code exécuté par Next.js.


Script JavaScript d’origine (nettoyé)

// Script de référence pour le calculateur de pression des pneus
// Tu peux coller ici le code JavaScript complet dont tu parles.
// Je m’en servirai ensuite pour adapter/améliorer le composant TirePressureTool.

// ========================================
// TIRE PRESSURE CALCULATOR
// Code JavaScript nettoyé
// ========================================

document.addEventListener("DOMContentLoaded", () => {
  // Ajouter les options de largeur de pneu (20-65mm)
  function addMeasuredTireOptions() {
    let select = document.getElementById("tire-width");
    for (let i = 20; i <= 65; i += 1) {
      let option = document.createElement("option");
      option.value = i;
      option.text = i + "mm";
      select.add(option);
    }
  }

  addMeasuredTireOptions();

  // Récupération des éléments du formulaire
  let weightUnit = "";
  let weightInput = document.getElementById("weight");
  let weightUnitRadios = document.getElementsByName("weight-unit");
  let surfaceConditionInput = document.getElementById("surface-condition");
  let tireWidthInput = document.getElementById("tire-width");
  let tireDiameterInput = document.getElementById("tire-diameter");
  let speedInput = document.getElementById("speed");
  let weightDistInput = document.getElementById("weightDist");
  let tireTypeInput = document.getElementById("tire-type");
  let validFormText = document.getElementById("invalid-form-text");
  let pinchFlatRec = document.getElementById("pinch-flat-rec");
  let submitButton = document.getElementById("submit");

  // ========================================
  // VALIDATION DU FORMULAIRE
  // ========================================

  function validateForm() {
    let valid = true;
    let weight = weightInput.value;
    let surfaceCondition = surfaceConditionInput.value;
    let tireWidth = tireWidthInput.value;
    let tireDiameter = tireDiameterInput.value;
    let speed = speedInput.value;
    let weightDist = weightDistInput.value;
    let tireType = tireTypeInput.value;
    let weightWarning = document.getElementById("weight-warning");

    // Conversion du poids en kg
    if (!weightUnitRadios[0].checked) {
      weightUnit = "kg";
      weight = Number(weight);
    } else {
      weightUnit = "lbs";
      weight = Number(weight) * 0.453592;
    }

    console.log(weight);

    // Validation du poids
    if (weight == "" || weight == null || weight < 0) {
      weightInput.classList.add("invalid-form");
      valid = false;
    } else if (weightInput.classList.contains("invalid-form")) {
      weightInput.classList.remove("invalid-form");
    }

    // Validation de la plage de poids (34-205 kg)
    if (weight < 34 || weight > 205) {
      weightWarning.classList.remove("hide");
      weightInput.classList.add("invalid-form");
      valid = false;
    } else if (!weightWarning.classList.contains("hide")) {
      weightWarning.classList.add("hide");
      weightInput.classList.remove("invalid-form");
    }

    // Validation des autres champs
    if (surfaceCondition == "null") {
      surfaceConditionInput.classList.add("invalid-form");
      valid = false;
    } else if (surfaceConditionInput.classList.contains("invalid-form")) {
      surfaceConditionInput.classList.remove("invalid-form");
    }

    if (tireWidth == "null") {
      tireWidthInput.classList.add("invalid-form");
      valid = false;
    } else if (tireWidthInput.classList.contains("invalid-form")) {
      tireWidthInput.classList.remove("invalid-form");
    }

    if (tireDiameter == "null") {
      tireDiameterInput.classList.add("invalid-form");
      valid = false;
    } else if (tireDiameterInput.classList.contains("invalid-form")) {
      tireDiameterInput.classList.remove("invalid-form");
    }

    if (speed == "null") {
      speedInput.classList.add("invalid-form");
      valid = false;
    } else if (speedInput.classList.contains("invalid-form")) {
      speedInput.classList.remove("invalid-form");
    }

    if (weightDist == "null") {
      weightDistInput.classList.add("invalid-form");
      valid = false;
    } else if (weightDistInput.classList.contains("invalid-form")) {
      weightDistInput.classList.remove("invalid-form");
    }

    if (tireType == "null") {
      tireTypeInput.classList.add("invalid-form");
      valid = false;
    } else if (tireTypeInput.classList.contains("invalid-form")) {
      tireTypeInput.classList.remove("invalid-form");
    }

    if (valid == false) {
      validFormText.classList.add("show");
      validFormText.classList.remove("hide");
      return false;
    } else {
      validFormText.classList.add("hide");
      validFormText.classList.remove("show");
    }

    return valid;
  }

  // ========================================
  // CALCUL K1 (basé sur la condition de surface)
  // ========================================

  function calculateK1() {
    switch (surfaceConditionInput.value) {
      case "track-indoor-wood":
        return 354;
      case "track-outdoor-wood":
        return 294;
      case "new-pavement":
        return 261;
      case "worn-pavement":
        return 246.5;
      case "cat1-gravel":
        return 235.5;
      case "poor-pavement":
        return 225;
      case "cat2-gravel":
        return 212.5;
      case "cobblestone":
        return 199;
      case "cat3-gravel":
        return 187;
      case "cat4-gravel":
        return 170;
    }
  }

  // ========================================
  // CALCUL DE LA PRESSION AU POINT CENTRAL (CPP)
  // ========================================

  function calcCPP(K) {
    let width = Number(tireWidthInput.value);
    let diameter = Number(tireDiameterInput.value);

    console.log("width", width, "diameter", diameter);

    let num =
      (-0.0006 * width ** 3 + 0.0079 * width ** 2 - 0.4102 * width + 12.725) *
      -226.44;
    let denom =
      ((-0.5 * 9.81) / (K * (20 / width)) + (width + diameter / 2)) ** 2 -
      (width + diameter / 2) ** 2;

    console.log("num", num, "denom", denom);

    return num / denom;
  }

  // ========================================
  // COEFFICIENT DE VITESSE
  // ========================================

  function calcSpeedCoeff(speed) {
    let y0 = 10,
      x0 = 0.97,
      y1 = 33,
      x1 = 1.03;
    let num = x1 * speed - x1 * y0 - x0 * speed + x0 * y0 + y1 * x0 - x0 * y0;
    let denom = y1 - y0;
    return num / denom;
  }

  // ========================================
  // COEFFICIENT DE DISTRIBUTION DU POIDS
  // ========================================

  function calcWeightDist() {
    let weightDistObj = {
      front: 0,
      back: 0,
    };

    switch (weightDistInput.value) {
      case "tr-tt-track":
        weightDistObj.front = 1;
        weightDistObj.back = 1;
        break;
      case "road":
        weightDistObj.front = 0.985;
        weightDistObj.back = 1.01;
        break;
      case "gravel":
        weightDistObj.front = 0.975;
        weightDistObj.back = 1.02;
        break;
      case "mountain":
        weightDistObj.front = 0.97;
        weightDistObj.back = 1.03;
        break;
    }

    return weightDistObj;
  }

  // ========================================
  // COEFFICIENT DU TYPE DE PNEU
  // ========================================

  function calcTireType() {
    let tireTypeObj = {
      front: 0,
      back: 0,
    };

    switch (tireTypeInput.value) {
      case "high-perf-tubeless-latex":
        tireTypeObj.front = 1;
        tireTypeObj.back = 1;
        break;
      case "mid-range-tubeless-latex":
        tireTypeObj.front = 0.97;
        tireTypeObj.back = 0.97;
        break;
      case "mid-range-butyl":
        tireTypeObj.front = 0.94;
        tireTypeObj.back = 0.94;
        break;
      case "puncture-resistant-tubeless-latex":
        tireTypeObj.front = 0.91;
        tireTypeObj.back = 0.91;
        break;
    }

    return tireTypeObj;
  }

  // ========================================
  // FONCTIONS UTILITAIRES
  // ========================================

  function round(value, precision) {
    var multiplier = Math.pow(100, precision || 0) / 5;
    return Math.round(value * multiplier) / multiplier;
  }

  function roundHalf(num) {
    return Math.round(num * 2) / 2;
  }

  // ========================================
  // GESTIONNAIRE DE SOUMISSION
  // ========================================

  submitButton.addEventListener("click", submitHandle);

  function submitHandle(e) {
    e.preventDefault();
    console.log(e);

    // Conversion du poids
    if (!weightUnitRadios[0].checked) {
      weightUnit = "kg";
      var weight = Number(weightInput.value);
    } else {
      weightUnit = "lbs";
      var weight = Number(weightInput.value) * 0.453592;
    }

    if (validateForm()) {
      // Calculs principaux
      let K1 = calculateK1();
      let K = 0.5 * (weight - 50) + K1;
      let CPP = calcCPP(K);
      let speedCoeff = calcSpeedCoeff(Number(speedInput.value));
      let weightDistCoeff = calcWeightDist();
      let tireTypeCoeff = calcTireType();

      let speedVal = Number(speedInput.value) * 0.44704; // mph to m/s
      let tireWidthVal = Number(tireWidthInput.value);

      console.log(
        "weight",
        weight,
        "K1",
        K1,
        "K",
        K,
        "CPP",
        CPP,
        "speedCoeff",
        speedCoeff,
        "weightDistCoeff",
        weightDistCoeff,
        "tireTypeCoeff",
        tireTypeCoeff,
      );

      // PRESSIONS FINALES
      let finalPressures = {
        front: CPP * speedCoeff * weightDistCoeff.front * tireTypeCoeff.front,
        back: CPP * speedCoeff * weightDistCoeff.back * tireTypeCoeff.back,
      };

      // ========================================
      // DÉTECTION DU RISQUE DE PINCEMENT (PINCH FLAT)
      // ========================================

      let KE = 0.5 * weight * speedVal ** 2; // Énergie cinétique
      let RE =
        0.5 *
        (0.8 * tireWidthVal) *
        Math.sqrt(K ** 2 - (0.8 * tireWidthVal) ** 2); // Énergie de résistance
      let PF = 2 * RE - KE; // Facteur de pincement

      // Calcul de la largeur recommandée
      let Wnum1 = -2.56 * K ** 2;
      let Wsqrtnum2 = 6.5536 * K ** 4;
      let Wsqrtnum3 =
        6.5536 *
        (-16000 - 800 * weight * speedVal ** 2 - weight ** 2 * speedVal ** 4);
      let Wnum = Wnum1 + Math.sqrt(Wsqrtnum2 + Wsqrtnum3);
      let Wdenom = 3.2768;
      let W = Math.sqrt(-Wnum / Wdenom);

      // Pressions alternatives pour éviter les pincements
      let PNewNum =
        Math.sqrt(
          (25 * weight ** 2 * speedVal ** 4 +
            2000 * weight * speedVal ** 2 +
            4000) /
            (64 * tireWidthVal ** 2),
        ) +
        0.64 * tireWidthVal ** 2;
      let PNewDenom = K;
      let PfrontNew = (PNewNum / PNewDenom) * finalPressures.front;
      let PbackNew = (PNewNum / PNewDenom) * finalPressures.back;

      console.log("KE:", KE, "RE:", RE, "2*RE", 2 * RE, "PF", PF);
      console.log("W:", W);

      // Avertissement de risque de pincement
      if (PF >= -500 && PF <= 0) {
        pinchFlatRec.innerHTML = `Your selections put you at an <span style='font-weight: 700;'>increased</span> risk for pinch flats. To run your optimal
                    pressures with a reduced pinch flat risk, we recommend selecting a tire with a measured width of <span style="font-weight: 700;" id="w-rec">${Math.ceil(W)}mm.</span>
                    <br><br>
                    If that tire width is not possible on your frame, we recommend running non-optimal front and rear pressures of <span style='font-weight: 700;'>${roundHalf(PfrontNew)} PSI</span>
                    and <span style='font-weight: 700;'>${roundHalf(PbackNew)} PSI</span> to protect your rims and tires.`;
      } else if (PF < -500) {
        pinchFlatRec.innerHTML = `Your selections put you at an <span style='font-weight: 700;'>EXTREME</span> risk for pinch flats. To run your optimal pressures with a reduced pinch flat risk, we
                            recommend selecting a tire with a measured width of <span style="font-weight: 700;" id="w-rec">${Math.ceil(W)}mm.</span>
                            <br><br>
                            If that tire width is not possible on your frame, we recommend running
                            non-optimal front and rear pressures of <span style='font-weight: 700;'>${roundHalf(PfrontNew)} PSI</span> and <span style='font-weight: 700;'>${roundHalf(PbackNew)} PSI</span> to protect your
                            rims and tires.`;
      } else {
        pinchFlatRec.innerHTML = "";
      }

      console.log("KE:", KE, "RE:", RE);
      console.log("W:", W);

      if (KE >= 2 * RE) {
        console.log("Condition for pinch flat hit");
      }

      // ========================================
      // AFFICHAGE DES RÉSULTATS
      // ========================================

      let frontPress = document.getElementById("front-press");
      let backPress = document.getElementById("back-press");
      let frontPressBar = document.getElementById("front-press-bar");
      let backPressBar = document.getElementById("back-press-bar");
      let backPressHeader = document.getElementById("back-press-header");
      let frontPressHeader = document.getElementById("front-press-header");
      let pressureBox1 = document.getElementById("pressure-box1");
      let pressureBox2 = document.getElementById("pressure-box2");

      // Afficher les résultats
      frontPress.classList.remove("hide");
      backPress.classList.remove("hide");
      frontPressBar.classList.remove("hide");
      backPressBar.classList.remove("hide");
      backPressHeader.classList.remove("hide");
      frontPressHeader.classList.remove("hide");
      pressureBox1.classList.remove("hide");
      pressureBox2.classList.remove("hide");

      let frontVal = document.getElementById("front-val");
      let backVal = document.getElementById("back-val");
      let frontValBar = document.getElementById("front-val-bar");
      let backValBar = document.getElementById("back-val-bar");
      let hooklessWarning = document.getElementById("hookless-warning");

      // Afficher les pressions calculées
      frontVal.innerHTML = roundHalf(finalPressures.front, 4);
      backVal.innerHTML = roundHalf(finalPressures.back, 4);
      frontValBar.innerHTML = round(finalPressures.front * 0.0689476, 1); // PSI to BAR
      backValBar.innerHTML = round(finalPressures.back * 0.0689476, 1); // PSI to BAR

      // ========================================
      // AVERTISSEMENT HOOKLESS (>70 PSI)
      // ========================================

      let frontPSI = roundHalf(finalPressures.front);
      let rearPSI = roundHalf(finalPressures.back);

      if (frontPSI > 70 || rearPSI > 70) {
        hooklessWarning.classList.remove("hide");
      } else {
        hooklessWarning.classList.add("hide");
      }

      // Soumettre les données (optionnel - pour Klaviyo marketing)
      // submitFormDataToKlaviyo();

      return finalPressures;
    } else {
      // Cacher les résultats si validation échoue
      let frontPress = document.getElementById("front-press");
      let backPress = document.getElementById("back-press");
      let frontPressBar = document.getElementById("front-press-bar");
      let backPressBar = document.getElementById("back-press-bar");

      frontPress.classList.add("hide");
      backPress.classList.add("hide");
      frontPressBar.classList.add("hide");
      backPressBar.classList.add("hide");
    }
  }
}); // Fin DOMContentLoaded

// ========================================
// FONCTION OPTIONNELLE - Ouvrir popup info
// ========================================

function openTireTypePopup(url) {
  window.open(
    url,
    "popUpWindow",
    "height=500,width=500,left=100,top=100,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes",
  );
}
//fin du script

/* Code HTML du fomrulaire (référence, non exécuté)
        ... (voir ancienne version pour le HTML complet) ...
        */