From 76fa080364b2c479bb38f6ba6f87a9b9bb06686b Mon Sep 17 00:00:00 2001 From: Mike Shoup Date: Thu, 4 Jul 2019 14:43:13 -0600 Subject: [PATCH] Javascript to handle form changes. --- src/humulus/static/recipes.js | 185 +++++++++++++++++++-- src/humulus/templates/recipes/_macros.html | 50 ++++-- 2 files changed, 213 insertions(+), 22 deletions(-) diff --git a/src/humulus/static/recipes.js b/src/humulus/static/recipes.js index 2e057b2..c6daad4 100644 --- a/src/humulus/static/recipes.js +++ b/src/humulus/static/recipes.js @@ -13,6 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. */ + +// unbinds and re-binds the change event +function rebindChangeEvents() { + $('.ingredient-field').unbind('change'); + $('.ingredient-field').change(displayAll); +} + // Correct all the indices for forms matching item. function adjustIndices(removedIndex, item) { var $forms = $(item); @@ -51,6 +58,7 @@ function removeForm($remButton, formClass, formsId) { var $fermsDiv = $(formsId); $fermsDiv.data('length', $fermsDiv.data('length') - 1); adjustIndices(removedIndex, formClass); + displayAll(); } // Remove a fermentable @@ -75,14 +83,14 @@ function addFerm() { // Name field '
' + `` + - `` + '
' + // End name field '
' + // Type field '
' + `` + - `` + '
' + // End amount field // PPG field '
' + `` + - `` + '
' + // End PPG field // Color field '
' + `` + - `` + '
' + // End PPG field '
' + @@ -118,10 +126,13 @@ function addFerm() { ''; $fermsDiv.append(newFerm); $fermsDiv.data('length', fermsLength + 1); + // Unbind click events and re-bind them. This is needed to prevent multiple click events $('.rem-ferm').unbind('click'); $('.rem-ferm').click(removeFerm); + rebindChangeEvents(); } +// Add a hop function addHop() { var $hopsDiv = $('#hops'); var hopsLength = $hopsDiv.data('length'); @@ -134,14 +145,14 @@ function addHop() { // Name field '
' + `` + - `` + '
' + // End name field '
' + // Usage field '
' + `` + - `` + '
' + // End alpha acid % field // Duration field '
' + `` + - `` + '
' + // End duration field // Amount field '
' + `` + - `` + '
' + // End amount field '
' + @@ -176,13 +187,167 @@ function addHop() { $hopsDiv.append(newHop); $hopsDiv.data('length', hopsLength + 1); + // Unbind click events and re-bind them. This is needed to prevent multiple click events $('.rem-hop').unbind('click'); $('.rem-hop').click(removeHop); + rebindChangeEvents(); +} + +// Calculate recipe's original gravity +function calculateOG() { + var fermsLength = $('#ferms').data('length'); + if (fermsLength == 0) { + return 0; + } + var points = 0; + var grain_points = 0; + for (var i = 0; i < fermsLength; i++) { + var ppg = parseFloat($(`#fermentables-${i}-ppg`).val()) || 0.0; + var amt = parseFloat($(`#fermentables-${i}-amount`).val()) || 0.0; + + // Check if type is grain + if ($(`#fermentables-${i}-type`).val() == 'Grain') { + grain_points += ppg * amt; + } else { + points += ppg * amt; + } + } + // Add grain_points to points, adjusting for efficiency + var efficiency = parseFloat($(`#efficiency`).val()) || 0; + var volume = parseFloat($(`#volume`).val()) || 0; + points += grain_points * efficiency / 100; + return 1 + points / (1000 * volume); +} + +// display OG +function displayOG() { + $('#estimated-og').text(calculateOG().toFixed(3)); +} + +// Calculate final gravity +function calculateFG() { + var fermsLength = $('#ferms').data('length'); + if (fermsLength == 0) { + return 0; + } + + var og = parseFloat(calculateOG()) || 0.0; + var og_delta = 0.0; + var volume = parseFloat($(`#volume`).val()) || 0; + for (var i = 0; i < fermsLength; i++) { + if ($(`#fermentables-${i}-type`).val() == 'Non-fermentable') { + var ppg = parseFloat($(`#fermentables-${i}-ppg`).val()) || 0.0; + var amt = parseFloat($(`#fermentables-${i}-amount`).val()) || 0.0; + og_delta += amt * ppg / (volume * 1000) + } + } + + var low_attenuation = parseFloat($('#yeast-low_attenuation').val()) || 0.0; + var high_attenuation = parseFloat($('#yeast-high_attenuation').val()) || 0.0; + var attenuation = (low_attenuation + high_attenuation) / 200; + return 1 + (og - 1 - og_delta)*(1 - attenuation) + og_delta; +} + +// Display FG +function displayFG() { + $('#estimated-fg').text(calculateFG().toFixed(3)); +} + +// Calculate ABV +function calculate_abv() { + return (calculateOG() - calculateFG()) * 131.25; +} + +// Display ABV +function displayABV() { + var abv = calculate_abv().toFixed(1); + $('#estimated-abv').text(`${abv} %/vol.`); +} + +// Calculate IBU +function calculateIBU() { + var hopsLength = $('#hops').data('length'); + if (hopsLength == 0) { + return 0; + } + + var bigness = 1.65 * Math.pow(0.000125, calculateOG() - 1); + var ibu = 0; + var volume = parseFloat($(`#volume`).val()) || 0; + for (var i = 0; i < hopsLength; i++) { + var use = $(`#hops-${i}-use`).val(); + if (use != 'Boil' && use != 'FWH') { + continue; + } + var alpha = parseFloat($(`#hops-${i}-alpha`).val()) || 0.0; + var amt = parseFloat($(`#hops-${i}-amount`).val()) || 0.0; + var duration = parseFloat($(`#hops-${i}-duration`).val()) || 0.0; + var mgl = alpha * amt * 7490 / (volume * 100) + var btf = (1 - Math.pow(Math.E, -0.04 * duration)) / 4.15 + ibu += bigness * btf * mgl; + } + return ibu; +} + +// Display IBU +function displayIBU() { + var ibu = calculateIBU().toFixed(); + $('#estimated-ibu').text(`${ibu} IBU`); +} + +// Calculate IBU Ratio +function calculateIBURatio() { + return 0.001 * calculateIBU() / (calculateOG() - 1) +} + +// Display IBU Ratio +function displayIBURatio() { + var iburatio = calculateIBURatio().toFixed(3); + $('#estimated-iburatio').text(`${iburatio} IBU/OG`); +} + +// Calculate SRM +function calculateSRM() { + var fermsLength = $('#ferms').data('length'); + if (fermsLength == 0) { + return 0; + } + var mcu = 0; + var volume = parseFloat($(`#volume`).val()) || 0; + for (var i = 0; i < fermsLength; i++) { + var color = parseFloat($(`#fermentables-${i}-color`).val()) || 0.0; + var amt = parseFloat($(`#fermentables-${i}-amount`).val()) || 0.0; + mcu += amt * color / volume; + } + return 1.4922 * Math.pow(mcu, 0.6859) +} + +// Display SRM +function displaySRM() { + var srm = calculateSRM().toFixed(); + $('#estimated-srm').text(`${srm} SRM`); +} + +// Display all specifications +function displayAll() { + displayOG(); + displayFG(); + displayABV(); + displayIBU(); + displayIBURatio(); + displaySRM(); } $(document).ready(function() { + // Register clicks $('#add-ferm').click(addFerm); $('.rem-ferm').click(removeFerm); $('#add-hop').click(addHop); $('.rem-hop').click(removeHop); + + // Register change events + rebindChangeEvents(); + + // Update specifications + displayAll(); }); diff --git a/src/humulus/templates/recipes/_macros.html b/src/humulus/templates/recipes/_macros.html index ec2a358..ffa5f5d 100644 --- a/src/humulus/templates/recipes/_macros.html +++ b/src/humulus/templates/recipes/_macros.html @@ -26,8 +26,34 @@ -#}
{{ render_field_with_errors(form.name) }}
-
{{ render_field_with_errors(form.efficiency) }}
-
{{ render_field_with_errors(form.volume) }}
+
{{ render_field_with_errors(form.efficiency, 'ingredient-field') }}
+
{{ render_field_with_errors(form.volume, 'ingredient-field') }}
+
+ {#- + Recipe specifications + -#} +

Estimated Specifications

+
+
+
+
Original Gravity
+
+
Final Gravity
+
+
Alcohol
+
+
+
+
+
+
Bitterness
+
+
Bitterness Ratio
+
+
Color
+
+
+
{#- Fermentable Ingredients @@ -42,10 +68,10 @@
-
{{ render_field_with_errors(fermentable.form.type, 'form-control-sm') }}
-
{{ render_field_with_errors(fermentable.form.amount, 'form-control-sm') }}
-
{{ render_field_with_errors(fermentable.form.ppg, 'form-control-sm') }}
-
{{ render_field_with_errors(fermentable.form.color, 'form-control-sm') }}
+
{{ render_field_with_errors(fermentable.form.type, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(fermentable.form.amount, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(fermentable.form.ppg, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(fermentable.form.color, 'form-control-sm ingredient-field') }}
@@ -73,10 +99,10 @@
-
{{ render_field_with_errors(hop.form.use, 'form-control-sm') }}
-
{{ render_field_with_errors(hop.form.alpha, 'form-control-sm') }}
-
{{ render_field_with_errors(hop.form.duration, 'form-control-sm') }}
-
{{ render_field_with_errors(hop.form.amount, 'form-control-sm') }}
+
{{ render_field_with_errors(hop.form.use, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(hop.form.alpha, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(hop.form.duration, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(hop.form.amount, 'form-control-sm ingredient-field') }}
@@ -104,8 +130,8 @@
{{ render_field_with_errors(form.yeast.form.code, 'form-control-sm') }}
-
{{ render_field_with_errors(form.yeast.form.low_attenuation, 'form-control-sm') }}
-
{{ render_field_with_errors(form.yeast.form.high_attenuation, 'form-control-sm') }}
+
{{ render_field_with_errors(form.yeast.form.low_attenuation, 'form-control-sm ingredient-field') }}
+
{{ render_field_with_errors(form.yeast.form.high_attenuation, 'form-control-sm ingredient-field') }}
{{ render_field_with_errors(form.yeast.form.flocculation, 'form-control-sm') }}
{{ render_field_with_errors(form.yeast.form.min_temperature, 'form-control-sm') }}
{{ render_field_with_errors(form.yeast.form.max_temperature, 'form-control-sm') }}