
Objectif Créer un **calculateur** permettant aux utilisateurs de savoir combien de **sacs de ragréage VPI** sont nécessaires pour une surface donnée, en fonction : * de la **surface de la pièce (m²)**, * de **l’épaisseur moyenne du ragréage (mm)**, * du **type de ragréage VPI choisi**. --- ## 🖥️ Interface Utilisateur (UI) ### 1. **Champs de saisie** : | Champ | Type | Détail | | ---------------------- | ------------------------------------ | ----------------------------------------- | | Surface (m²) | Champ numérique | Valeur positive décimale autorisée | | Épaisseur moyenne (mm) | Champ numérique | Valeur positive décimale autorisée | | Produit VPI | Menu déroulant (select) | Liste dynamique des produits ragréage VPI | | Marge de sécurité (%) | Slider (0% à 15%) ou champ numérique | Valeur facultative, par défaut 5% | --- ### 2. **Bouton de calcul** * Texte : `Calculer` * Action : déclenche le calcul --- ### 3. **Résultat affiché** | Élément | Contenu | | ------------------------------------------------------- | -------------------------------------------------- | | Nombre de sacs nécessaires | Valeur arrondie à l'entier supérieur | | Quantité totale de ragréage nécessaire (kg) | Nombre décimal | | Détail du produit choisi (nom, rendement, poids du sac) | Texte | | (Facultatif) Coût estimé si tarif du sac connu | Affiché uniquement si champ "prix unitaire" rempli | --- ## 🧠 Logique de calcul ### 1. Formule générale ``` volume_total_m3 = surface_m2 * épaisseur_mm / 1000 poids_total_kg = volume_total_m3 * densité_kg_m3 (donnée du produit VPI) nombre_de_sacs = poids_total_kg / poids_sac_kg nombre_de_sacs_final = arrondi supérieur(nombre_de_sacs * (1 + marge_de_sécurité/100)) ``` --- ## 📦 Données à intégrer : Produits VPI (base de référence) Voici un **exemple de structure JSON** pour la base de produits (à compléter ou connecter dynamiquement via un fichier ou une API si disponible) : ```json [ { "nom": "VPI RAGREAGE 400", "type": "Ragréage autolissant intérieur", "poids_sac_kg": 25, "rendement_m2_pour_10mm": 1.5, "densité_kg_m3": 1800 }, { "nom": "VPI RAGREAGE 500", "type": "Ragréage fibré extérieur", "poids_sac_kg": 25, "rendement_m2_pour_10mm": 1.4, "densité_kg_m3": 1900 }, { "nom": "VPI RAGREAGE 600", "type": "Ragréage à prise rapide", "poids_sac_kg": 20, "rendement_m2_pour_10mm": 1.2, "densité_kg_m3": 1850 } ] ``` ⚠️ À vérifier dans les **fiches techniques VPI** (sur leur site) pour les valeurs exactes. --- ## 📈 Exemple de calcul **Entrées utilisateur :** * Surface = 30 m² * Épaisseur = 8 mm * Produit = "VPI RAGREAGE 500" * Marge de sécurité = 5 % **Calcul :** 1. `volume = 30 × 8 / 1000 = 0.24 m³` 2. `poids_total = 0.24 × 1900 = 456 kg` 3. `nombre_de_sacs = 456 / 25 = 18.24` 4. `nombre_de_sacs_final = 18.24 × 1.05 = 19.15 → 20 sacs` --- ## 🔌 Extensions possibles * 🧾 Ajout champ "prix unitaire" pour estimation du coût * 🖨️ Bouton “Imprimer le résultat” * 📊 Graphique visuel pour visualiser la quantité nécessaire - Initial Deployment
da95101
verified
<html lang="fr"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Calculateur de ragréage VPI</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
.slider-thumb::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
appearance: none; | |
width: 20px; | |
height: 20px; | |
background: #3b82f6; | |
cursor: pointer; | |
border-radius: 50%; | |
} | |
.slider-thumb::-moz-range-thumb { | |
width: 20px; | |
height: 20px; | |
background: #3b82f6; | |
cursor: pointer; | |
border-radius: 50%; | |
} | |
.result-card { | |
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); | |
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); | |
} | |
.product-card { | |
transition: all 0.3s ease; | |
} | |
.product-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 min-h-screen"> | |
<div class="container mx-auto px-4 py-8"> | |
<!-- Header --> | |
<header class="text-center mb-12"> | |
<h1 class="text-3xl md:text-4xl font-bold text-gray-800 mb-2"> | |
<i class="fas fa-calculator text-blue-500 mr-2"></i> | |
Calculateur de ragréage VPI | |
</h1> | |
<p class="text-gray-600 max-w-2xl mx-auto"> | |
Calculez le nombre de sacs nécessaires pour votre projet de ragréage en fonction de la surface, de l'épaisseur et du produit VPI choisi. | |
</p> | |
</header> | |
<!-- Calculator Section --> | |
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> | |
<!-- Input Form --> | |
<div class="bg-white rounded-xl shadow-md p-6 lg:col-span-2"> | |
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> | |
<i class="fas fa-edit text-blue-500 mr-2"></i> | |
Paramètres du projet | |
</h2> | |
<form id="calculatorForm"> | |
<!-- Surface Input --> | |
<div class="mb-6"> | |
<label for="surface" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-ruler-combined text-blue-500 mr-1"></i> | |
Surface à ragréer (m²) | |
</label> | |
<div class="relative"> | |
<input type="number" id="surface" step="0.01" min="0" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" | |
placeholder="Ex: 30.5" required> | |
<div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none"> | |
<span class="text-gray-500">m²</span> | |
</div> | |
</div> | |
</div> | |
<!-- Thickness Input --> | |
<div class="mb-6"> | |
<label for="thickness" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-arrows-alt-v text-blue-500 mr-1"></i> | |
Épaisseur moyenne du ragréage (mm) | |
</label> | |
<div class="relative"> | |
<input type="number" id="thickness" step="0.1" min="0" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" | |
placeholder="Ex: 8.5" required> | |
<div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none"> | |
<span class="text-gray-500">mm</span> | |
</div> | |
</div> | |
</div> | |
<!-- Product Selection --> | |
<div class="mb-6"> | |
<label for="product" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-boxes text-blue-500 mr-1"></i> | |
Produit VPI | |
</label> | |
<select id="product" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" required> | |
<option value="" disabled selected>Sélectionnez un produit</option> | |
<!-- Options will be populated by JavaScript --> | |
</select> | |
</div> | |
<!-- Safety Margin Slider --> | |
<div class="mb-8"> | |
<label for="safetyMargin" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-shield-alt text-blue-500 mr-1"></i> | |
Marge de sécurité | |
<span id="safetyMarginValue" class="text-blue-600 font-medium">5%</span> | |
</label> | |
<div class="flex items-center space-x-4"> | |
<input type="range" id="safetyMargin" min="0" max="15" value="5" | |
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-thumb"> | |
<span class="text-gray-500 text-sm">0%</span> | |
<span class="text-gray-500 text-sm">15%</span> | |
</div> | |
</div> | |
<!-- Unit Price (Optional) --> | |
<div class="mb-6"> | |
<label for="unitPrice" class="block text-sm font-medium text-gray-700 mb-1"> | |
<i class="fas fa-tag text-blue-500 mr-1"></i> | |
Prix unitaire (optionnel) | |
</label> | |
<div class="relative"> | |
<input type="number" id="unitPrice" step="0.01" min="0" | |
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" | |
placeholder="Ex: 25.99"> | |
<div class="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none"> | |
<span class="text-gray-500">€</span> | |
</div> | |
</div> | |
</div> | |
<!-- Calculate Button --> | |
<button type="submit" | |
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition duration-300 flex items-center justify-center"> | |
<i class="fas fa-calculator mr-2"></i> | |
Calculer | |
</button> | |
</form> | |
</div> | |
<!-- Results Section --> | |
<div id="resultsContainer" class="hidden"> | |
<div class="result-card rounded-xl p-6 h-full"> | |
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> | |
<i class="fas fa-chart-bar text-blue-500 mr-2"></i> | |
Résultats du calcul | |
</h2> | |
<div class="space-y-4"> | |
<!-- Number of Bags --> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h3 class="text-sm font-medium text-gray-500">Nombre de sacs nécessaires</h3> | |
<p id="bagsNeeded" class="text-2xl font-bold text-blue-600">0</p> | |
</div> | |
<div class="bg-blue-100 p-3 rounded-full"> | |
<i class="fas fa-shopping-bag text-blue-600 text-xl"></i> | |
</div> | |
</div> | |
</div> | |
<!-- Total Quantity --> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h3 class="text-sm font-medium text-gray-500">Quantité totale nécessaire</h3> | |
<p id="totalQuantity" class="text-xl font-bold text-gray-800">0 kg</p> | |
</div> | |
<div class="bg-gray-100 p-3 rounded-full"> | |
<i class="fas fa-weight text-gray-600 text-xl"></i> | |
</div> | |
</div> | |
</div> | |
<!-- Product Details --> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<h3 class="text-sm font-medium text-gray-500 mb-2">Détails du produit</h3> | |
<div id="productDetails" class="text-gray-700"> | |
<p class="font-medium" id="productName">-</p> | |
<p class="text-sm" id="productType">-</p> | |
<p class="text-sm mt-1"><span class="font-medium">Rendement:</span> <span id="productYield">-</span> m²/sac pour 10mm</p> | |
<p class="text-sm"><span class="font-medium">Poids du sac:</span> <span id="productWeight">-</span> kg</p> | |
</div> | |
</div> | |
<!-- Estimated Cost --> | |
<div id="estimatedCostContainer" class="hidden bg-white p-4 rounded-lg shadow-sm"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h3 class="text-sm font-medium text-gray-500">Coût estimé</h3> | |
<p id="estimatedCost" class="text-xl font-bold text-green-600">0 €</p> | |
</div> | |
<div class="bg-green-100 p-3 rounded-full"> | |
<i class="fas fa-euro-sign text-green-600 text-xl"></i> | |
</div> | |
</div> | |
</div> | |
<!-- Visual Representation --> | |
<div class="bg-white p-4 rounded-lg shadow-sm"> | |
<h3 class="text-sm font-medium text-gray-500 mb-3">Répartition</h3> | |
<div class="flex items-center justify-center h-32"> | |
<div id="visualBags" class="flex flex-wrap justify-center gap-2"> | |
<!-- Bags will be visualized here --> | |
</div> | |
</div> | |
</div> | |
<!-- Print Button --> | |
<button id="printButton" | |
class="w-full mt-4 bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-2 px-4 rounded-lg transition duration-300 flex items-center justify-center"> | |
<i class="fas fa-print mr-2"></i> | |
Imprimer le résultat | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Product Information (Initially shown, hidden after calculation) --> | |
<div id="productInfo" class="lg:col-span-1"> | |
<div class="bg-white rounded-xl shadow-md p-6"> | |
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> | |
<i class="fas fa-info-circle text-blue-500 mr-2"></i> | |
Produits VPI disponibles | |
</h2> | |
<div class="space-y-4"> | |
<!-- Product cards will be populated by JavaScript --> | |
</div> | |
<div class="mt-6 p-4 bg-blue-50 rounded-lg"> | |
<h3 class="text-sm font-medium text-blue-800 mb-2 flex items-center"> | |
<i class="fas fa-lightbulb text-blue-600 mr-2"></i> | |
Conseil professionnel | |
</h3> | |
<p class="text-xs text-blue-700"> | |
Pour des résultats optimaux, prévoyez toujours une marge de sécurité de 5-10% pour tenir compte des pertes et des variations d'épaisseur. | |
</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Product data | |
const products = [ | |
{ | |
"id": 1, | |
"nom": "VPI RAGREAGE 400", | |
"type": "Ragréage autolissant intérieur", | |
"poids_sac_kg": 25, | |
"rendement_m2_pour_10mm": 1.5, | |
"densité_kg_m3": 1800, | |
"description": "Idéal pour les sols intérieurs, offre une excellente planéité et facilite la pose des revêtements.", | |
"color": "bg-blue-100 text-blue-800" | |
}, | |
{ | |
"id": 2, | |
"nom": "VPI RAGREAGE 500", | |
"type": "Ragréage fibré extérieur", | |
"poids_sac_kg": 25, | |
"rendement_m2_pour_10mm": 1.4, | |
"densité_kg_m3": 1900, | |
"description": "Parfait pour les applications extérieures, résistant aux intempéries grâce à ses fibres.", | |
"color": "bg-green-100 text-green-800" | |
}, | |
{ | |
"id": 3, | |
"nom": "VPI RAGREAGE 600", | |
"type": "Ragréage à prise rapide", | |
"poids_sac_kg": 20, | |
"rendement_m2_pour_10mm": 1.2, | |
"densité_kg_m3": 1850, | |
"description": "Temps de prise accéléré pour les projets nécessitant une intervention rapide.", | |
"color": "bg-orange-100 text-orange-800" | |
} | |
]; | |
// DOM elements | |
const calculatorForm = document.getElementById('calculatorForm'); | |
const productSelect = document.getElementById('product'); | |
const safetyMarginSlider = document.getElementById('safetyMargin'); | |
const safetyMarginValue = document.getElementById('safetyMarginValue'); | |
const resultsContainer = document.getElementById('resultsContainer'); | |
const productInfo = document.getElementById('productInfo'); | |
const productDetails = document.getElementById('productDetails'); | |
const bagsNeeded = document.getElementById('bagsNeeded'); | |
const totalQuantity = document.getElementById('totalQuantity'); | |
const productName = document.getElementById('productName'); | |
const productType = document.getElementById('productType'); | |
const productYield = document.getElementById('productYield'); | |
const productWeight = document.getElementById('productWeight'); | |
const estimatedCostContainer = document.getElementById('estimatedCostContainer'); | |
const estimatedCost = document.getElementById('estimatedCost'); | |
const visualBags = document.getElementById('visualBags'); | |
const printButton = document.getElementById('printButton'); | |
const productCardsContainer = document.querySelector('#productInfo .space-y-4'); | |
// Initialize the app | |
function init() { | |
// Populate product select dropdown | |
products.forEach(product => { | |
const option = document.createElement('option'); | |
option.value = product.id; | |
option.textContent = `${product.nom} (${product.type})`; | |
productSelect.appendChild(option); | |
}); | |
// Populate product cards | |
products.forEach(product => { | |
const card = document.createElement('div'); | |
card.className = `product-card bg-white p-4 rounded-lg border border-gray-200 ${product.color.replace('text', 'border')}`; | |
card.innerHTML = ` | |
<h3 class="font-medium mb-1">${product.nom}</h3> | |
<p class="text-xs text-gray-600 mb-2">${product.type}</p> | |
<div class="flex justify-between text-sm"> | |
<div> | |
<p><span class="font-medium">Poids:</span> ${product.poids_sac_kg} kg</p> | |
<p><span class="font-medium">Rendement:</span> ${product.rendement_m2_pour_10mm} m²/sac (10mm)</p> | |
</div> | |
<div class="flex items-center"> | |
<span class="px-2 py-1 rounded-full ${product.color} text-xs font-medium">VPI</span> | |
</div> | |
</div> | |
`; | |
productCardsContainer.appendChild(card); | |
}); | |
// Update safety margin value display | |
safetyMarginSlider.addEventListener('input', () => { | |
safetyMarginValue.textContent = `${safetyMarginSlider.value}%`; | |
}); | |
// Handle form submission | |
calculatorForm.addEventListener('submit', calculate); | |
// Handle print button | |
printButton.addEventListener('click', () => { | |
window.print(); | |
}); | |
} | |
// Calculation function | |
function calculate(e) { | |
e.preventDefault(); | |
// Get input values | |
const surface = parseFloat(document.getElementById('surface').value); | |
const thickness = parseFloat(document.getElementById('thickness').value); | |
const productId = parseInt(document.getElementById('product').value); | |
const safetyMargin = parseInt(document.getElementById('safetyMargin').value) / 100; | |
const unitPrice = parseFloat(document.getElementById('unitPrice').value) || 0; | |
// Find selected product | |
const selectedProduct = products.find(p => p.id === productId); | |
// Perform calculations | |
const volume = surface * thickness / 1000; // m³ | |
const totalWeight = volume * selectedProduct.densité_kg_m3; // kg | |
const bags = totalWeight / selectedProduct.poids_sac_kg; | |
const bagsWithMargin = bags * (1 + safetyMargin); | |
const roundedBags = Math.ceil(bagsWithMargin); | |
// Calculate estimated cost if unit price is provided | |
const totalCost = roundedBags * unitPrice; | |
// Display results | |
bagsNeeded.textContent = roundedBags; | |
totalQuantity.textContent = `${totalWeight.toFixed(2)} kg`; | |
productName.textContent = selectedProduct.nom; | |
productType.textContent = selectedProduct.type; | |
productYield.textContent = selectedProduct.rendement_m2_pour_10mm; | |
productWeight.textContent = selectedProduct.poids_sac_kg; | |
// Show/hide estimated cost | |
if (unitPrice > 0) { | |
estimatedCost.textContent = `${totalCost.toFixed(2)} €`; | |
estimatedCostContainer.classList.remove('hidden'); | |
} else { | |
estimatedCostContainer.classList.add('hidden'); | |
} | |
// Visual representation of bags | |
visualBags.innerHTML = ''; | |
const maxBagsToShow = 20; | |
const bagsToShow = roundedBags <= maxBagsToShow ? roundedBags : maxBagsToShow; | |
for (let i = 0; i < bagsToShow; i++) { | |
const bag = document.createElement('div'); | |
bag.className = 'w-8 h-10 bg-blue-200 rounded flex items-center justify-center'; | |
bag.innerHTML = '<i class="fas fa-shopping-bag text-blue-600 text-xs"></i>'; | |
visualBags.appendChild(bag); | |
} | |
if (roundedBags > maxBagsToShow) { | |
const moreBags = document.createElement('div'); | |
moreBags.className = 'w-8 h-10 bg-blue-100 rounded flex items-center justify-center text-xs font-medium'; | |
moreBags.textContent = `+${roundedBags - maxBagsToShow}`; | |
visualBags.appendChild(moreBags); | |
} | |
// Show results and hide product info | |
resultsContainer.classList.remove('hidden'); | |
productInfo.classList.add('hidden'); | |
// Scroll to results | |
resultsContainer.scrollIntoView({ behavior: 'smooth' }); | |
} | |
// Initialize the app when DOM is loaded | |
document.addEventListener('DOMContentLoaded', init); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Onyx4291/vpi" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |