Przeglądaj źródła

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 lat temu
rodzic
commit
e73a4f1352

+ 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;