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) ...
*/