atabouraya

Estimator

Sep 2nd, 2025
276
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5.19 KB | Software | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8" />
  5.   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6.   <title>Compact Story Point Estimator</title>
  7.   <style>
  8.     body {
  9.       font-family: Arial, sans-serif;
  10.       background: #f9fafb;
  11.       margin: 0;
  12.       padding: 20px;
  13.     }
  14.     .container {
  15.       max-width: 700px;
  16.       margin: 0 auto;
  17.     }
  18.     h1 {
  19.       text-align: center;
  20.       font-size: 24px;
  21.       margin-bottom: 10px;
  22.     }
  23.     .formula {
  24.       font-size: 14px;
  25.       color: #333;
  26.       background: #fff;
  27.       border-radius: 10px;
  28.       padding: 10px;
  29.       margin-bottom: 20px;
  30.       line-height: 1.4;
  31.       box-shadow: 0 2px 5px rgba(0,0,0,0.05);
  32.     }
  33.     .card {
  34.       background: #fff;
  35.       border-radius: 10px;
  36.       padding: 12px 16px;
  37.       margin-bottom: 12px;
  38.       box-shadow: 0 1px 4px rgba(0,0,0,0.08);
  39.     }
  40.     .card-header {
  41.       display: flex;
  42.       justify-content: space-between;
  43.       align-items: center;
  44.       font-size: 16px;
  45.       margin-bottom: 6px;
  46.       font-weight: bold;
  47.     }
  48.     .weight {
  49.       font-size: 13px;
  50.       color: #666;
  51.     }
  52.     .slider-container {
  53.       display: flex;
  54.       align-items: center;
  55.       gap: 10px;
  56.     }
  57.     .slider-container input[type="range"] {
  58.       flex: 1;
  59.     }
  60.     .description {
  61.       font-size: 12px;
  62.       color: #555;
  63.       margin-top: 4px;
  64.       line-height: 1.3;
  65.     }
  66.     .result {
  67.       text-align: center;
  68.       font-size: 20px;
  69.       font-weight: bold;
  70.       margin-top: 20px;
  71.       padding: 12px;
  72.       background: #e0f2fe;
  73.       border-radius: 10px;
  74.     }
  75.   </style>
  76. </head>
  77. <body>
  78.   <div class="container">
  79.     <h1>Story Point Estimator</h1>
  80.  
  81.     <div class="formula">
  82.       <b>Equation:</b><br>
  83.       Weighted Score = ( Σ (Rating × Weight) - Min ) / (Max - Min)<br>
  84.       Effort (E) = 2 ^ (Weighted Score × 5)<br>
  85.       Final Story Points = Closest Fibonacci (1,2,3,5,8,13,21)
  86.     </div>
  87.  
  88.     <div id="categories"></div>
  89.     <div id="result" class="result">Story Points: 1</div>
  90.   </div>
  91.  
  92.   <script>
  93.     const categories = [
  94.       {
  95.         id: "technical",
  96.         name: "Technical Complexity",
  97.         weight: 30,
  98.         description: "1 = Simple logic / CRUD\n5 = Complex algorithm, multiple integrations"
  99.       },
  100.       {
  101.         id: "ux",
  102.         name: "UX & Platform Complexity",
  103.        weight: 20,
  104.        description: "1 = Standard UI, 1 platform\n5 = Custom UI, animations, multi-platform"
  105.      },
  106.      {
  107.        id: "quality",
  108.        name: "Quality & Risk Factors",
  109.        weight: 20,
  110.        description: "1 = Clear requirements, no risks\n5 = Unclear, risky, security-critical"
  111.      },
  112.      {
  113.        id: "performance",
  114.        name: "Performance & Scalability",
  115.        weight: 15,
  116.        description: "1 = No constraints\n5 = Realtime, high load, distributed"
  117.      },
  118.      {
  119.        id: "delivery",
  120.        name: "Delivery Effort",
  121.        weight: 15,
  122.        description: "1 = Easy testing & release\n5 = Heavy QA, multiple environments"
  123.      }
  124.    ];
  125.  
  126.     const fibonacci = [1, 2, 3, 5, 8, 13, 21];
  127.     const container = document.getElementById("categories");
  128.     const resultBox = document.getElementById("result");
  129.     const values = {};
  130.  
  131.     categories.forEach(cat => {
  132.       values[cat.id] = 1;
  133.  
  134.       const card = document.createElement("div");
  135.       card.className = "card";
  136.  
  137.       const header = document.createElement("div");
  138.       header.className = "card-header";
  139.       header.innerHTML = `<span>${cat.name}</span><span class="weight">Weight: ${cat.weight}%</span>`;
  140.       card.appendChild(header);
  141.  
  142.       const sliderContainer = document.createElement("div");
  143.       sliderContainer.className = "slider-container";
  144.  
  145.       const slider = document.createElement("input");
  146.       slider.type = "range";
  147.       slider.min = 1;
  148.       slider.max = 5;
  149.       slider.value = 1;
  150.  
  151.       const valueLabel = document.createElement("span");
  152.       valueLabel.textContent = "1";
  153.  
  154.       slider.oninput = () => {
  155.         values[cat.id] = parseInt(slider.value, 10);
  156.         valueLabel.textContent = slider.value;
  157.         calculate();
  158.       };
  159.  
  160.       sliderContainer.appendChild(slider);
  161.       sliderContainer.appendChild(valueLabel);
  162.       card.appendChild(sliderContainer);
  163.  
  164.       const desc = document.createElement("div");
  165.       desc.className = "description";
  166.       desc.textContent = cat.description;
  167.       card.appendChild(desc);
  168.  
  169.       container.appendChild(card);
  170.     });
  171.  
  172.     function calculate() {
  173.       const n = categories.length;
  174.       let weightedSum = 0;
  175.       categories.forEach(cat => {
  176.         weightedSum += values[cat.id] * cat.weight;
  177.       });
  178.       const min = 1 * 100; // all sliders at 1 × weights total (100%)
  179.       const max = 5 * 100; // all sliders at 5 × weights total (100%)
  180.       const normalized = (weightedSum - min) / (max - min);
  181.       const E = Math.pow(2, normalized * 5);
  182.       const closest = fibonacci.reduce((prev, curr) =>
  183.         Math.abs(curr - E) < Math.abs(prev - E) ? curr : prev
  184.      );
  185.      resultBox.textContent = "Story Points: " + closest;
  186.    }
  187.  
  188.    // Initial
  189.    calculate();
  190.  </script>
  191. </body>
  192. </html>
  193.  
Advertisement
Add Comment
Please, Sign In to add comment