Sfoglia il codice sorgente

Improvements to the parameters form and the results window. Some limit to prevent server ow browser crashes. Some nicer UI. The optmizer is now basically working.

Iñigo Valentin 5 anni fa
parent
commit
e73a4f1352
3 ha cambiato i file con 250 aggiunte e 116 eliminazioni
  1. 36 43
      application/action/optimize.php
  2. 156 64
      application/view/optimizer_unit.php
  3. 58 9
      public/css/optimizer.css

+ 36 - 43
application/action/optimize.php

@@ -30,7 +30,7 @@
         $HARD_LIMIT = 100;
 
         // Increase max execution time.
-        set_time_limit(30);
+        set_time_limit(60);
         
         $candidates = [
             1 => [],
@@ -99,7 +99,7 @@
         ];
 
         // Get Buld query:
-        $s = "
+        $base_s = "
           SELECT
             id,
             slot
@@ -109,19 +109,19 @@
             type IN (
         ";
         foreach ($sets as $set){
-            $s .= ($set . ",");
+            $base_s .= ($set . ",");
         }
-        $s .= "-1) AND ";
+        $base_s .= "-1) AND ";
         switch ($source){
             case 0: // Storage only (or itself)
-                $s .= "
+                $base_s .= "
                   (
                     assigned_to = $unit_id OR
                     assigned_to IS NULL
                   )";
                 break;
             case 1: // Units in no teams (or itself)
-                $s .= "
+                $base_s .= "
                   (
                     assigned_to = $unit_id OR
                     assigned_to IS NULL OR 
@@ -130,7 +130,7 @@
                 ";
                 break;
             case 2: // Units in teams with 0 score (or itself)
-                $s .= "
+                $base_s .= "
                   (
                     assigned_to = $unit_id OR
                     assigned_to IS NULL OR 
@@ -151,41 +151,28 @@
                 // TODO
                 break;
             case 4: // All runes - dont filter
-                $s .= " 1 = 1 ";
+                $base_s .= " 1 = 1 ";
                 break;
             default: // Invalid options - return nothing
-                $s .= " 1 = 0 ";
+                $base_s .= " 1 = 0 ";
         }
-        // Even slots stats
-        $s .= "
-          AND
-          (
-            slot <> 2 OR
-            (
-              slot = 2 AND
-              main_stat = " . $stats[0] . "
-            )
-          ) AND
-          (
-            slot <> 4 OR
-            (
-              slot = 4 AND
-              main_stat = " . $stats[1] . "
-            )
-          ) AND
-          (
-            slot <> 6 OR
-            (
-              slot = 6 AND
-              main_stat = " . $stats[2] . "
-            )
-          )
-        ";
-        $q = $db->query($s);
+        $s_order = " ORDER BY stars DESC, original_quality DESC, max_efficiency DESC, efficiency DESC, level DESC";
+
+        $s = ["", "", "", "", "", "", ""];
+        $s[1] = $base_s . " AND slot = 1 " . $s_order . " LIMIT 25";
+        $s[3] = $base_s . " AND slot = 3 " . $s_order . " LIMIT 25";
+        $s[5] = $base_s . " AND slot = 5 " . $s_order . " LIMIT 25";
+        $s[2] = $base_s . " AND slot = 2 AND main_stat = " . $stats[0] . $s_order . " LIMIT 20";
+        $s[4] = $base_s . " AND slot = 4 AND main_stat = " . $stats[1] . $s_order . " LIMIT 20";
+        $s[6] = $base_s . " AND slot = 6 AND main_stat = " . $stats[2] . $s_order . " LIMIT 20";
+
         $total_candidates = 0;
-        while ($r = $q->fetchArray(SQLITE3_ASSOC)){
-            array_push($candidates[$r["slot"]], new Rune($r["id"]));
-            $total_candidates ++;
+        for ($i = 1; $i <= 6; $i ++){
+            $q = $db->query($s[$i]);
+            while ($r = $q->fetchArray(SQLITE3_ASSOC)){
+                array_push($candidates[$i], new Rune($r["id"]));
+                $total_candidates ++;
+            }
         }
         $max_combinations = sizeof($candidates[1]) * sizeof($candidates[2]) * sizeof($candidates[3]) * sizeof($candidates[4]) * sizeof($candidates[5]) * sizeof($candidates[6]);
         if ($max_combinations == 0){
@@ -196,11 +183,12 @@
             $response = json_encode($res);
             return $response;
         }
-        /*elseif ($max_combinations > 50000000){
+        elseif ($max_combinations > 125000000){
+            // This should never happen unles query limits are changed
             http_response_code(413); // Payload too large;
             die();
             return;
-        }*/
+        }
         
         // Get the unit and its base stats
         $unit = new Unit($unit_id, true, $uid);
@@ -242,7 +230,6 @@
                 ];
                 for ($r = 1; $r <= 6; $r ++){
                     // Loop selected runes and calculate stats
-                    // TODO Consider main stat at selected level
                     $main_value = $candidates[$r][$i[$r]]->main_stat_value;
                     if ($tuning == 1){ // All +12
                         if ($candidates[$r][$i[$r]]->level < 12){
@@ -312,7 +299,6 @@
                     );
                 }
                 
-                // Calculate EHP and DMG
                 // Calculate effective_hp
                 $hp = $iteration["hp"];
                 $def = $iteration["defense"];
@@ -328,7 +314,7 @@
                 $crd = $iteration["crit_damage"];
                 $edmg = ceil(($atk * (100 - $crr) / 100) + (($atk + ($atk * $crd / 100)) * $crr / 100));
                 $iteration["dmg"] = $edmg;
-                
+
                 // Compare with filters:
                 if (
                   $iteration["attack"] >= $min["attack"] &&
@@ -342,6 +328,7 @@
                   $iteration["ehp"] >= $min["ehp"] &&
                   $iteration["dmg"] >= $min["dmg"]
                 ){
+
                     // Calculate the variation
                     $variation = 0;
                     $variation += (($iteration["attack"] - $unit->total_attack) * 1);
@@ -353,6 +340,10 @@
                     $variation += (($iteration["accuracy"] - $unit->total_accuracy) * 0.85);
                     $variation += (($iteration["resistance"] - $unit->total_resistance) * 0.85);
                     $variation = ceil($variation);
+
+                    // Calculate efficiency
+                    $efficiency = 0;
+                    
                     // Build the array
                     $option = [
                         "variation" => $variation,
@@ -446,6 +437,7 @@
         usort($options, "sortOptions");
 
         // Limit the array to the top options
+        $original_options_size = sizeof($options);
         while (sizeof($options) > $limit || sizeof($options) > $HARD_LIMIT){
             array_pop($options);
         }
@@ -453,6 +445,7 @@
         
         $res = [
             "total" => sizeof($options),
+            "skipped" => ($original_options_size - sizeof($options)),
             "options" => $options
         ];
         

+ 156 - 64
application/view/optimizer_unit.php

@@ -38,7 +38,7 @@
         <meta name='twitter:url' content='<?=$page->canonical?>'/>
         <meta name='robots' content='index follow'/>
         <script>
-        
+
             /**
              * Unit current stats.
              */
@@ -54,7 +54,7 @@
                 "ehp": <?=$page->unit->effective_hp?>,
                 "dmg": <?=$page->unit->effective_dmg?>
             }
-            
+
 <?php
             // Get current rune sets
             $sets = [];
@@ -68,7 +68,7 @@
             }
 ?>
             var current_sets = [<?=$sets[0]?>, <?=$sets[1]?>, <?=$sets[2]?>];
-            
+
             // Get current main stats in even slots
 <?php
             $mains = [0, 0, 0];
@@ -78,6 +78,12 @@
                 }
             }
 ?>
+
+            /**
+             * To calculate time.
+             */
+            var timestamp = 0;
+
             /**
              * Updates the value next to the sliders when they change.
              *
@@ -90,15 +96,33 @@
                 var min = Number(element.min);
                 if (value < min){
                     value = min;
-                    console.log("Correcting for min: " + value + "/" + min);
                 }
                 if (value > max){
-                    console.log("Correcting for max: " + value + "/" + max);
                     value = max;
                 }
                 document.getElementById('lbl_min_' + stat).value = value;
                 document.getElementById('min_' + stat).value = value;
             }
+            
+            /**
+             * Resets filter to the unit's current stat status.
+             *
+             * @param stat Name of the stat to set.
+             */
+            function resetFilter(stat){
+                document.getElementById('lbl_min_' + stat).value = current_stats[stat];
+                document.getElementById('min_' + stat).value = current_stats[stat];
+            }
+
+            /**
+             * Sets a filter to it's lowest possible value.
+             *
+             * @param stat Name of the stat to set.
+             */
+            function removeFilter(stat){
+                document.getElementById('lbl_min_' + stat).value = document.getElementById('lbl_min_' + stat).min;
+                document.getElementById('min_' + stat).value = document.getElementById('min_' + stat).min;
+            }
 
             /**
              * Starts the optimization.
@@ -111,7 +135,6 @@
              * @return false on error, true on success.
              */
             function apply(){
-                // TODO: Check for valid set combinations
 
                 var params = '';
                 var x;
@@ -208,9 +231,9 @@
                     if (this.readyState == 4){
                         document.getElementById('apply').removeAttribute('disabled');
                         document.getElementById('wait').style.display = 'none';
-                        console.log("STATUS: " + this.status);
                         if (this.status == 200) {
-                            showOptimizations(this.response);
+                            time = ((+ new Date()) - timestamp) / 1000;
+                            showOptimizations(this.response, time);
                         }
                         else if (this.status == 413) { // Payload too large
                             showMessage('Error', 'Too many combination found. Plesase narow your criteria and retry.');
@@ -220,11 +243,11 @@
                         }
                     }
                 };
-                
-                // TODO DEBUG
+
+                // DEBUG
                 //params = 'uid=8114048&unit=6441802832&limit=6&set[]=2&set[]=4&set[]=4&stat[]=4&stat[]=4&stat[]=4&source=0&tuning=2&min_defense=800';
-                
-                
+
+
                 // Clear result table, disable button and show spinner
                 var container = document.getElementById('optimizations');
                 while (container.firstChild) {
@@ -234,6 +257,9 @@
                 document.getElementById('wait').style.display = 'block';
                 document.getElementById('results').style.display = 'none';
                 
+                // Start timer
+                timestamp = + new Date();
+
                 // Make the request
                 xhttp.open('POST', '/action/optimize/', true);
                 xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
@@ -246,13 +272,16 @@
              *
              * @param content JSON received from server.
              */
-            function showOptimizations(content){
+            function showOptimizations(content, time){
                 var container = document.getElementById('optimizations');
                 var data = JSON.parse(content);
                 if (Number(data.total) == 0){
                     showMessage('No results', 'No suitable combination found. Plesase relax your criteria and retry.');
                     return;
                 }
+                document.getElementById('num_results').innerHTML = data.total;
+                document.getElementById('num_skipped').innerHTML = data.skipped;
+                document.getElementById('num_seconds').innerHTML = time;
                 var option;
                 var tr;
                 var td;
@@ -265,7 +294,7 @@
                     option = data.options[i];
                     tr = document.createElement('tr');
                     td = document.createElement('td');
-                    td.setAttribute('class', 'stats');
+                    td.setAttribute('class', 'option_stats');
                     stat_table = document.createElement('table');
                     stat_table.setAttribute('class', 'stat_table');
 
@@ -285,15 +314,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.attack) > Number(current_stats["attack"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.attack - current_stats["attack"]);
-                        
+
                     }
                     else if (Number(option.stats.attack) < Number(current_stats["attack"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["attack"] - option.stats.attack);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -303,7 +332,7 @@
                     stat_td.appendChild(span);
                     stat_tr.appendChild(stat_td);
                     stat_table.appendChild(stat_tr);
-                    
+
                     // defense
                     stat_tr = document.createElement('tr');
                     stat_td = document.createElement('td');
@@ -320,15 +349,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.defense) > Number(current_stats["defense"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.defense - current_stats["defense"]);
-                        
+
                     }
                     else if (Number(option.stats.defense) < Number(current_stats["defense"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["defense"] - option.stats.defense);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -355,15 +384,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.hp) > Number(current_stats["hp"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.hp - current_stats["hp"]);
-                        
+
                     }
                     else if (Number(option.stats.hp) < Number(current_stats["hp"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["hp"] - option.stats.hp);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -390,15 +419,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.speed) > Number(current_stats["speed"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.speed - current_stats["speed"]);
-                        
+
                     }
                     else if (Number(option.stats.speed) < Number(current_stats["speed"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["speed"] - option.stats.speed);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -425,15 +454,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.crit_rate) > Number(current_stats["crit_rate"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.crit_rate - current_stats["crit_rate"]);
-                        
+
                     }
                     else if (Number(option.stats.crit_rate) < Number(current_stats["crit_rate"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["crit_rate"] - option.stats.crit_rate);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -460,15 +489,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.crit_damage) > Number(current_stats["crit_damage"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.crit_damage - current_stats["crit_damage"]);
-                        
+
                     }
                     else if (Number(option.stats.crit_damage) < Number(current_stats["crit_damage"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["crit_damage"] - option.stats.crit_damage);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -495,15 +524,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.accuracy) > Number(current_stats["accuracy"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.accuracy - current_stats["accuracy"]);
-                        
+
                     }
                     else if (Number(option.stats.accuracy) < Number(current_stats["accuracy"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["accuracy"] - option.stats.accuracy);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -530,15 +559,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.resistance) > Number(current_stats["resistance"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.resistance - current_stats["resistance"]);
-                        
+
                     }
                     else if (Number(option.stats.resistance) < Number(current_stats["resistance"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["resistance"] - option.stats.resistance);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -565,15 +594,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.ehp) > Number(current_stats["ehp"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.ehp - current_stats["ehp"]);
-                        
+
                     }
                     else if (Number(option.stats.ehp) < Number(current_stats["ehp"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["ehp"] - option.stats.ehp);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -583,7 +612,7 @@
                     stat_td.appendChild(span);
                     stat_tr.appendChild(stat_td);
                     stat_table.appendChild(stat_tr);
-                    
+
                     // dmg
                     stat_tr = document.createElement('tr');
                     stat_td = document.createElement('td');
@@ -600,15 +629,15 @@
                     stat_td.appendChild(span);
                     span = document.createElement('span');
                     if (Number(option.stats.dmg) > Number(current_stats["dmg"])){
-                        
+
                         span.setAttribute('class', 'variation increment');
                         text = document.createTextNode(option.stats.dmg - current_stats["dmg"]);
-                        
+
                     }
                     else if (Number(option.stats.dmg) < Number(current_stats["dmg"])){
                         span.setAttribute('class', 'variation decrement');
                         text = document.createTextNode(current_stats["dmg"] - option.stats.dmg);
-                        
+
                     }
                     else{
                         span.setAttribute('class', 'variation');
@@ -622,7 +651,7 @@
                     // Add to the main table
                     td.appendChild(stat_table);
                     tr.appendChild(td);
-                    
+
                     // Runes td
                     td = document.createElement('td');
                     td.setAttribute('class', 'runes');
@@ -643,7 +672,7 @@
 
                 }
             }
-            
+
             /**
              * Displays a pop-up message.
              *
@@ -987,7 +1016,7 @@
                 Optimization parameters
             </h2>
             <article>
-                <table>
+                <table id='parameters'>
                     <tr>
                         <td class='name'>
                             Rune sets
@@ -1044,7 +1073,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_hp' type='range' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' oninput='updateMinValue("hp", this);'>
-                            <input type='number' id='lbl_min_hp' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' onChange='updateMinValue("hp", this);'></input>
+                            <input type='number' id='lbl_min_hp' value='<?=$page->unit->total_hp?>' min='<?=$page->unit->hp?>' max='50000' onChange='updateMinValue("hp", this);'></input></input><span class='slider_percent'> </span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("hp");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("hp");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1080,7 +1115,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_attack' type='range' value='<?=$page->unit->total_attack?>' min='<?=$page->unit->attack?>' max='4000' oninput='updateMinValue("attack", this);'>
-                            <input type='number' id='lbl_min_attack' value='<?=$page->unit->total_attack?>' min='<?=$page->unit->attack?>' max='4000' onChange='updateMinValue("attack", this);'></input>
+                            <input type='number' id='lbl_min_attack' value='<?=$page->unit->total_attack?>' min='<?=$page->unit->attack?>' max='4000' onChange='updateMinValue("attack", this);'></input><span class='slider_percent'> </span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("attack");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("attack");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1103,7 +1144,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_defense' type='range' value='<?=$page->unit->total_defense?>' min='<?=$page->unit->defense?>' max='4000' oninput='updateMinValue("defense", this);'>
-                            <input type='number' id='lbl_min_defense' value='<?=$page->unit->total_defense?>' min='<?=$page->unit->defense?>' max='4000' onChange='updateMinValue("defense", this);'></input>
+                            <input type='number' id='lbl_min_defense' value='<?=$page->unit->total_defense?>' min='<?=$page->unit->defense?>' max='4000' onChange='updateMinValue("defense", this);'></input><span class='slider_percent'> </span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("defense");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("defense");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1125,7 +1172,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_speed' type='range' value='<?=$page->unit->total_speed?>' min='<?=$page->unit->speed?>' max='400' oninput='updateMinValue("speed", this);'>
-                            <input type='number' id='lbl_min_speed' value='<?=$page->unit->total_speed?>' min='<?=$page->unit->speed?>' max='400' onChange='updateMinValue("speed", this);'></input>
+                            <input type='number' id='lbl_min_speed' value='<?=$page->unit->total_speed?>' min='<?=$page->unit->speed?>' max='400' onChange='updateMinValue("speed", this);'></input><span class='slider_percent'> </span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("speed");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("speed");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1142,7 +1195,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_crit_rate' type='range' value='<?=$page->unit->total_crit_rate?>' min='<?=$page->unit->crit_rate?>' max='100' oninput='updateMinValue("crit_rate", this);'>
-                            <input type='number' id='lbl_min_crit_rate' value='<?=$page->unit->total_crit_rate?>' min='<?=$page->unit->crit_rate?>' max='100' onChange='updateMinValue("crit_rate", this);'></input>%
+                            <input type='number' id='lbl_min_crit_rate' value='<?=$page->unit->total_crit_rate?>' min='<?=$page->unit->crit_rate?>' max='100' onChange='updateMinValue("crit_rate", this);'></input><span class='slider_percent'>%</span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("crit_rate");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("crit_rate");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1157,7 +1216,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_crit_damage' type='range' value='<?=$page->unit->total_crit_damage?>' min='<?=$page->unit->crit_damage?>' max='400' oninput='updateMinValue("crit_damage", this);'>
-                            <input type='number' id='lbl_min_crit_damage' value='<?=$page->unit->total_crit_damage?>' min='<?=$page->unit->crit_damage?>' max='400' onChange='updateMinValue("crit_damage", this);'></input>%
+                            <input type='number' id='lbl_min_crit_damage' value='<?=$page->unit->total_crit_damage?>' min='<?=$page->unit->crit_damage?>' max='400' onChange='updateMinValue("crit_damage", this);'></input><span class='slider_percent'>%</span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("crit_damage");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("crit_damage");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1172,7 +1237,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_accuracy' type='range' value='<?=$page->unit->total_accuracy?>' min='<?=$page->unit->accuracy?>' max='85' oninput='updateMinValue("accuracy", this);'>
-                            <input type='number' id='lbl_min_accuracy' value='<?=$page->unit->total_accuracy?>' min='<?=$page->unit->accuracy?>' max='85' onChange='updateMinValue("accuracy", this);'></input>%
+                            <input type='number' id='lbl_min_accuracy' value='<?=$page->unit->total_accuracy?>' min='<?=$page->unit->accuracy?>' max='85' onChange='updateMinValue("accuracy", this);'></input><span class='slider_percent'>%</span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("accuracy");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("accuracy");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1187,7 +1258,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_resistance' type='range' value='<?=$page->unit->total_resistance?>' min='<?=$page->unit->resistance?>' max='85' oninput='updateMinValue("resistance", this);'>
-                            <input type='number' id='lbl_min_resistance' value='<?=$page->unit->total_resistance?>' min='<?=$page->unit->resistance?>' max='85' onChange='updateMinValue("resistance", this);'></input>%
+                            <input type='number' id='lbl_min_resistance' value='<?=$page->unit->total_resistance?>' min='<?=$page->unit->resistance?>' max='85' onChange='updateMinValue("resistance", this);'></input><span class='slider_percent'>%</span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("resistance");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("resistance");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1202,7 +1279,13 @@
                         </td>
                         <td class='value'>
                             <input id='min_ehp' type='range' value='<?=$page->unit->effective_hp?>' min='0' max='200000' oninput='updateMinValue("ehp", this);'>
-                            <input type='number' id='lbl_min_ehp' value='<?=$page->unit->effective_hp?>' min='0' max='200000' onChange='updateMinValue("ehp", this);'></input>
+                            <input type='number' id='lbl_min_ehp' value='<?=$page->unit->effective_hp?>' min='0' max='200000' onChange='updateMinValue("ehp", this);'></input><span class='slider_percent'> </span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("ehp");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("ehp");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
                     <tr>
@@ -1219,13 +1302,19 @@
                         </td>
                         <td class='value'>
                             <input id='min_dmg' type='range' value='<?=$page->unit->effective_dmg?>' min='0' max='7000' oninput='updateMinValue("dmg", this);'>
-                            <input type='number' id='lbl_min_dmg' value='<?=$page->unit->effective_dmg?>' min='0' max='7000' onChange='updateMinValue("dmg", this);'></input>
+                            <input type='number' id='lbl_min_dmg' value='<?=$page->unit->effective_dmg?>' min='0' max='7000' onChange='updateMinValue("dmg", this);'></input><span class='slider_percent'> </span>
+                            <a title='Remove filter' class='filter_control a_button' onclick='removeFilter("dmg");'>
+                                <img alt='Remove filter' src='<?=URL::IMG["ICON"]?>nok.png'/>
+                            </a>
+                            <a title='Reset filter' class='filter_control a_button' onclick='resetFilter("dmg");'>
+                                <img alt='Reset filter' src='<?=URL::IMG["ICON"]?>edit.png'/>
+                            </a>
                         </td>
                     </tr>
-                    
-                    
-                    
-                    
+
+
+
+
                 </table>
             </article>
         </section>
@@ -1234,7 +1323,10 @@
                 Optimization results
             </h2>
             <article>
-                <table>
+                <div id='results_info'>
+                    <span id='num_results'></span> results (<span id='num_skipped'></span> skipped) in <span id='num_seconds'></span> seconds
+                </div>
+                <table id='table_optimizations'>
                     <tbody id='optimizations'>
                     </tbody>
                 </table>

+ 58 - 9
public/css/optimizer.css

@@ -176,12 +176,35 @@ section#parameters article{
     text-align: left;
 }
 
+section#parameters article table{
+    margin: auto;
+}
+
 section#parameters article input[type="number"]{
     width: 4em;
     text-align: right;
     -moz-appearance: textfield;
 }
 
+section#parameters span.slider_percent{
+    display: inline-block;
+    width: 1em;
+    font-size: 70%;
+}
+
+section#parameters a.filter_control{
+    width: 1em;
+    height: 1em;
+    display: inline-block;
+    vertical-align: bottom;
+}
+section#parameters a.filter_control img{
+    width: 0.8em;
+    height: 0.8em;
+    left: 0.15em;
+    position: relative;
+}
+
 section#parameters article img#wait{
     width: 2.5em;
     height: 2.5em;
@@ -192,29 +215,34 @@ section#results{
     display: none;
 }
 
+section#results div#results_info{
+    text-align: left;
+    font-weight: bold;
+    margin: 2em auto 1em 10%
+}
 
-section#results table.stat_table{
+section#results td.option_stats table.stat_table{
     border-collapse: collapse;
     border: 0.2em solid #00000088;
 }
 
-section#results table.stat_table td{
+section#results td.option_stats table.stat_table td{
     border: 0.1em solid #00000033;
 }
 
-section#results table.stat_table td.label{
+section#results td.option_stats table.stat_table td.label{
     text-align: left;
     font-family: monospace;
     font-size: 110%;
 }
 
-section#results table.stat_table td.value{
+section#results td.option_stats table.stat_table td.value{
     text-align: right;
     font-family: monospace;
     font-size: 110%;
 }
 
-section#results table.stat_table td.value span.variation{
+section#results td.option_stats table.stat_table td.value span.variation{
     font-size: 90%;
     width: 4em;
     display: inline-block;
@@ -223,21 +251,42 @@ section#results table.stat_table td.value span.variation{
     font-weight: bold
 }
 
-section#results table.stat_table td.value span.variation.increment{
+section#results td.option_stats table.stat_table td.value span.variation.increment{
     color: #00ff00;
 }
 
-section#results table.stat_table td.value span.variation.increment::before {
+section#results td.option_stats table.stat_table td.value span.variation.increment::before {
     content: "▲"; /*"&#9650;";*/
 }
 
-section#results table.stat_table td.value span.variation.decrement{
+section#results td.option_stats table.stat_table td.value span.variation.decrement{
     color: #ff0000;
 }
-section#results table.stat_table td.value span.variation.decrement::before {
+section#results td.option_stats table.stat_table td.value span.variation.decrement::before {
     content: "▼"; /*"&#9660;";*/
 }
 
+section#results td.runes table.rune{
+    font-size: 60%;
+}
+
+section#results table#table_optimizations{
+    border-collapse: collapse;
+    margin: auto;
+}
+
+section#results td.option_stats, section#results td.runes{
+    vertical-align: top;
+    padding: 1em 3em;
+    border-top: 0.1em solid #000000cc;
+    border-bottom: 0.1em solid #000000cc;
+}
+section#results td.option_stats{
+    padding-right: 0.5em;
+}
+section#results td.runes{
+    padding-left: 0.5em;
+}
 
 div#message_container{
     display: none;