Thu, 12 Oct 2023 14:19:46 +0200
Version 0.3.44. Moved iSpindel Plato calculation from the php script to bmsd. This uses calibration data in the mon_ispindels table. Setup of this data will be done by the bmsapp applications. Default settings are stored in MySQL. From now on you don't need to store calibration data in the iSpindel.
/***************************************************************************** * Copyright (C) 2018-2022 * * Michiel Broek <mbroek at mbse dot eu> * * This file is part of BMS * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * BrewCloud is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ThermFerm; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ var psugar = 0, // Percentage real sugars pcara = 0, // Percentage cara/crystal malts svg = 77, // Default attenuation mashkg = 0, // Malt in mash weight mash_infuse = 0, dataRecord = {}, // Main recipe record hop_flavour = 0, hop_aroma = 0, preboil_sg = 0, last_base = '', last_acid = '', Ka1 = 0.0000004445, Ka2 = 0.0000000000468, error_count = 0, MMCa = 40.048, MMMg = 24.305, MMNa = 22.98976928, MMCl = 35.453, MMSO4 = 96.0626, MMCO3 = 60.01684, MMHCO3 = 61.01684, MMCaSO4 = 172.171, MMCaCl2 = 147.015, MMCaCO3 = 100.087, MMMgCl2 = 95.211, /* Since 27-06-2021 */ MMMgSO4 = 246.475, MMNaHCO3 = 84.007, MMNa2CO3 = 105.996, MMNaCl = 58.443, MMCaOH2 = 74.06268, SpecificHeatWater = 1.0, SpecificHeatMalt = 0.399, //cal/g.°C SlakingHeat = 10.318, //cal/g.°C eq_tun_weight = 2.0, // 2 Kg pot eq_tun_specific_heat = 0.110, // Stainless Steel data_loaded = 0; function hopFlavourContribution(bt, vol, use, amount) { var result; if (use == 4 || use == 5) // Whirlpool or Dry-hop return 0; if (use == 1) { // First wort result = 0.15; // assume 15% flavourcontribution for fwh } else if (bt > 50) { result = 0.10; // assume 10% flavourcontribution as a minimum } else { result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) / 6, 2)); if (result < 0.10) result = 0.10; // assume 10% flavourcontribution as a minimum } return (result * amount * 1000) / vol; } function hopAromaContribution(bt, vol, use, amount) { var result = 0; if (use == 5) { // Dry hop result = 1.33; } else if (use == 4) { // Whirlpool if (bt > 30) bt = 30; // Max 30 minutes result = 0.62 * bt / 30; } else if (bt > 20) { result = 0; } else if (bt > 7.5) { result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) / 4, 2)); } else if (use == 2) { // Boil result = 1; } else if (use == 3) { // Aroma result = 1.2; } return (result * amount * 1000) / vol; } function calcFermentables() { console.log('calcFermentables()'); var i, row, rows, org, s = 0, d, x, sug, alc, cw, color, scolor, fig, sugarsf = 0, // fermentable sugars mash + boil sugarsm = 0; // fermentable sugars in mash vol = 0, // Volume sugars after boil addedS = 0, // Added sugars after boil addedmass = 0, // Added mass after boil mvol = 0, // mash volume colort = 0, // Colors srm * vol totals colorh = 0, // Colors ebc * vol * kt colorn = 0, // Colors ebc * pt * pct my_100 = false, mashtime = 0, // Total mash time mashtemp = 0, // Average mash temperature bv = 0.925, // Bierverlies rendement sr = 0.95, // Mash en spoel rendement lintner = 0; // Total recipe lintner /* Init global variables */ psugar = 0; pcara = 0; mashkg = 0; if ((rows = $('#mashGrid').jqxGrid('getrows'))) { for (i = 0; i < rows.length; i++) { row = rows[i]; if (row.step_type == 0) // Infusion mvol += parseFloat(row.step_infuse_amount); if (row.step_temp <= 75) { // Ignore mashout mashtime += row.step_time; mashtemp += row.step_time * row.step_temp; } } mashtemp = mashtemp / mashtime; } if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { return; // grid not yet loaded. } for (i = 0; i < rows.length; i++) { row = rows[i]; if (row.f_adjust_to_total_100) my_100 = true; if (row.f_type == 1 && row.f_added < 4) // Sugar psugar += row.f_percentage; if (row.f_graintype == 2 && row.f_added < 4) // Crystal pcara += row.f_percentage; d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); if (row.f_added == 0) { // Mash if (mvol > 0) { // Only if mash already known mvol += row.f_amount * row.f_moisture / 100; s += d; } d = parseFloat(dataRecord.efficiency) / 100 * d; sugarsm += d; mashkg += row.f_amount; } if (row.f_added == 0 || row.f_added == 1) // Mash or Boil sugarsf += d; if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering x = (row.f_yield / 100) * (1 - row.f_moisture / 100); addedS += row.f_amount * x; addedmass += row.f_amount; vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; } if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 lintner += row.f_diastatic_power * row.f_amount; } if (row.f_added < 4) { colort += row.f_amount * ebc_to_srm(row.f_color); colorh += row.f_amount * row.f_color * get_kt(row.f_color); colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. } } $('#ferm_lintner').val(Math.round(parseFloat(lintner / mashkg))); to_100 = my_100; // Estimate total recipe OG. dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); $('#est_og').val(dataRecord.est_og); $('#est_og2').val(dataRecord.est_og); org = dataRecord.est_og; // Estimate SG in kettle before boil preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); // Color of the wort if (dataRecord.color_method == 4) { color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); } else if (dataRecord.color_method == 3) { // Hans Halberstadt color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); } else { cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; color = kw_to_ebc(dataRecord.color_method, cw); } dataRecord.est_color = color; $('#est_color').val(color); $('#est_color2').val(color); scolor = ebc_to_color(color); document.getElementById('bcolor').style.background = scolor; document.getElementById('bcolor2').style.background = scolor; // Progress bars pmalts = mashkg / (dataRecord.boil_size / 3) * 100; $('#perc_malts').jqxProgressBar('val', pmalts); $('#perc_sugars').jqxProgressBar('val', psugar); $('#perc_cara').jqxProgressBar('val', pcara); // Calculate estimated svg. svg = 0; // default. rows = $('#yeastGrid').jqxGrid('getrows'); for (i = 0; i < rows.length; i++) { row = rows[i]; if (row.y_use == 0) { // Primary if (parseFloat(row.y_attenuation) > svg) svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. } // TODO: brett in secondary ?? } if (svg == 0) svg = 77; if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); } else { dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); } $('#est_fg').val(dataRecord.est_fg); $('#est_fg2').val(dataRecord.est_fg); fig = dataRecord.est_fg; dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); $('#est_abv').val(dataRecord.est_abv); $('#est_abv2').val(dataRecord.est_abv); // Calculate the calories in kcal/l (from brouwhulp) alc = 1881.22 * fig * (org - fig) / (1.775 - org); sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); $('#kcal').val(Math.round((alc + sug) / (12 * 0.0295735296))); } function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) { var a = last_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); var b = step_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2); console.log('infusionVol(' + step_infused + ', ' + step_mashkg + ', ' + infuse_temp + ', ' + step_temp + ', ' + last_temp + '): ' + vol); return vol; } function decoctionVol(step_volume, step_temp, prev_temp) { var a = (eq_tun_weight * eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); var b = SpecificHeatWater * (99 - step_temp); var vol = 0; if (b > 0) vol = Round(a / b, 6); console.log('decoctionVol(' + step_volume + ', ' + step_temp + ', ' + prev_temp + '): ' + vol); return vol; } function calcMash() { var infused = 0, vol, i, j, n, a, b, row, rows, temp; var lasttemp = 18.0; var graintemp = 18.0; var tuntemp = 18.0; if ((rows = $('#mashGrid').jqxGrid('getrows')) && (mashkg > 0)) { console.log('calcMash()'); for (i = 0; i < rows.length; i++) { row = $('#mashGrid').jqxGrid('getrowdata', i); if (row.step_type == 0) { // Infusion if (i == 0) { // First mash step, temperature from the mashtun and malt. n = 20; // tun is preheated. tuntemp = row.step_temp; for (j = 0; j < n; j++) { a = mashkg * graintemp * SpecificHeatMalt + eq_tun_weight * tuntemp * eq_tun_specific_heat; b = row.step_temp * (eq_tun_weight * eq_tun_specific_heat + row.step_infuse_amount * SpecificHeatWater + mashkg * SpecificHeatMalt) - SlakingHeat * mashkg; if (row.step_infuse_amount > 0) { temp = (b - a) / (row.step_infuse_amount * SpecificHeatWater); } else { temp = 99; } tuntemp += (temp - tuntemp) / 2; row.step_infuse_temp = Round(temp, 6); } console.log('init infuse temp: ' + row.step_infuse_temp); } else { // Calculate amount of infusion water. row.step_infuse_amount = infusionVol(infused, mashkg, row.step_infuse_temp, row.step_temp, lasttemp); //console.log('vol: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); } infused += row.step_infuse_amount; } else if (row.step_type == 1) { // Temperature if (i > 0) row.step_infuse_amount = 0; row.step_infuse_temp = 0; } else if (row.step_type == 2) { // Decoction row.step_infuse_amount = decoctionVol(infused, row.step_temp, lasttemp); row.step_infuse_temp = 99; } row.step_volume = infused; //console.log(i + ' type: ' + row.step_type + ' volume: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); lasttemp = row.step_temp; mashtime += row.step_time + row.ramp_time; row.step_wg_ratio = Round(infused / mashkg, 6); $('#mashGrid').jqxGrid('updaterow', i, row); } } } function GetBUGU() { var gu = (dataRecord.est_og - 1) * 1000; if (gu > 0) return dataRecord.est_ibu / gu; else return 0.5; } function GetOptSO4Clratio() { var BUGU = GetBUGU(); return (-1.2 * BUGU + 1.4); } function setRangeIndicator(ion, rangeCode) { if ((rangeCode == 'laag') || (rangeCode == 'hoog')) $('#wr_' + ion).html('<img src="images/dialog-error.png"><span style="vertical-align: top; font-size: 10px; font-style: italic;">' + rangeCode + '</span>'); else $('#wr_' + ion).html('<img src="images/dialog-ok-apply.png">'); } function mix(v1, v2, c1, c2) { if ((v1 + v2) > 0) { return ((v1 * c1) + (v2 * c2)) / (v1 + v2); } return 0; } // mg/l as CaCO3 function ResidualAlkalinity(total_alkalinity, calcium, magnesium) { return total_alkalinity - (calcium / 1.4 + magnesium / 1.7); } function PartCO3(pH) { var H = Math.pow(10, -pH); return 100 * Ka1 * Ka2 / (H * H + H * Ka1 + Ka1 * Ka2); } function PartHCO3(pH) { var H = Math.pow(10, -pH); return 100 * Ka1 * H / (H * H + H * Ka1 + Ka1 * Ka2); } function Charge(pH) { return (-2 * PartCO3(pH) - PartHCO3(pH)); } //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) function ZAlkalinity(pHZ) { var C43 = Charge(4.3), Cw = Charge(parseFloat($('#wg_ph').jqxNumberInput('decimal'))), Cz = Charge(pHZ), DeltaCNaught = -C43 + Cw, CT = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) / 50 / DeltaCNaught, DeltaCZ = -Cz + Cw; return CT * DeltaCZ; } //Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) function ZRA(pHZ) { var Calc = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) / (MMCa / 2), Magn = parseFloat($('#wg_magnesium').jqxNumberInput('decimal')) / (MMMg / 2), Z = ZAlkalinity(pHZ); return Z - (Calc / 3.5 + Magn / 7); } function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) { C1 = 0; if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) { C1 = acid_to_ph_57 / (di_ph - 5.7); } else { // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. switch (graintype) { case 0: // Base, Special, Kilned case 3: case 5: C1 = 0.014 * ebc - 34.192; break; case 2: C1 = -0.0597 * ebc - 32.457; // Crystal break; case 1: C1 = 0.0107 * ebc - 54.768; // Roast break; case 4: C1 = -149; // Sour malt break; } } return C1; } function ProtonDeficit(pHZ) { var C1, i, rows, row, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal')); // proton deficit for the grist if ((rows = $('#fermentableGrid').jqxGrid('getrows'))) { for (i = 0; i < rows.length; i++) { row = rows[i]; if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype); x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) Result += x * row.f_amount; } } } else { error_count++; if (error_count < 5) console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result); } return Result; } function MashpH() { var n = 0, pH = 5.4, deltapH = 0.001, deltapd = 0.1, pd = ProtonDeficit(pH); while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { n++; if (pd < -deltapd) pH -= deltapH; else if (pd > deltapd) pH += deltapH; pd = ProtonDeficit(pH); } pH = Round(pH, 6); //console.log('MashpH() n: ' + n + ' pH: ' + pH); return pH; } $(document).ready(function() { var to_100 = false, // Fermentables adjust to 100% fermentableRow = 0, fermentableData = {}, hopRow = 0, hopData = {}, miscRow = 0, miscData = {}, yeastRow = 0, yeastData = {}, mashRow = 0, mashData = {}, url = 'includes/db_recipes.php', // prepare the data source = { datatype: 'json', cache: false, datafields: [ { name: 'record', type: 'number' }, { name: 'uuid', type: 'string' }, { name: 'locked', type: 'int' }, { name: 'st_name', type: 'string' }, { name: 'st_letter', type: 'string' }, { name: 'st_guide', type: 'string' }, { name: 'st_type', type: 'int' }, { name: 'st_category', type: 'string' }, { name: 'st_category_number', type: 'int' }, { name: 'st_og_min', type: 'float' }, { name: 'st_og_max', type: 'float' }, { name: 'st_fg_min', type: 'float' }, { name: 'st_fg_max', type: 'float' }, { name: 'st_ibu_min', type: 'float' }, { name: 'st_ibu_max', type: 'float' }, { name: 'st_color_min', type: 'float' }, { name: 'st_color_max', type: 'float' }, { name: 'st_carb_min', type: 'float' }, { name: 'st_carb_max', type: 'float' }, { name: 'st_abv_min', type: 'float' }, { name: 'st_abv_max', type: 'float' }, { name: 'name', type: 'string' }, { name: 'notes', type: 'string' }, { name: 'type', type: 'int' }, { name: 'batch_size', type: 'float' }, { name: 'boil_size', type: 'float' }, { name: 'boil_time', type: 'float' }, { name: 'efficiency', type: 'float' }, { name: 'est_og', type: 'float' }, { name: 'est_fg', type: 'float' }, { name: 'est_abv', type: 'float' }, { name: 'est_color', type: 'float' }, { name: 'color_method', type: 'int' }, { name: 'est_ibu', type: 'float' }, { name: 'ibu_method', type: 'int' }, { name: 'est_carb', type: 'float' }, { name: 'sparge_temp', type: 'float' }, { name: 'sparge_ph', type: 'float' }, { name: 'sparge_volume', type: 'float' }, { name: 'sparge_source', type: 'int' }, { name: 'sparge_acid_type', type: 'int' }, { name: 'sparge_acid_perc', type: 'float' }, { name: 'sparge_acid_amount', type: 'float' }, { name: 'mash_ph', type: 'float' }, { name: 'mash_name', type: 'string' }, { name: 'calc_acid', type: 'int' }, { name: 'w1_name', type: 'string' }, { name: 'w1_amount', type: 'float' }, { name: 'w1_calcium', type: 'float' }, { name: 'w1_sulfate', type: 'float' }, { name: 'w1_chloride', type: 'float' }, { name: 'w1_sodium', type: 'float' }, { name: 'w1_magnesium', type: 'float' }, { name: 'w1_total_alkalinity', type: 'float' }, { name: 'w1_ph', type: 'float' }, { name: 'w1_cost', type: 'float' }, { name: 'w2_name', type: 'string' }, { name: 'w2_amount', type: 'float' }, { name: 'w2_calcium', type: 'float' }, { name: 'w2_sulfate', type: 'float' }, { name: 'w2_chloride', type: 'float' }, { name: 'w2_sodium', type: 'float' }, { name: 'w2_magnesium', type: 'float' }, { name: 'w2_total_alkalinity', type: 'float' }, { name: 'w2_ph', type: 'float' }, { name: 'w2_cost', type: 'float' }, { name: 'wg_amount', type: 'float' }, { name: 'wg_calcium', type: 'float' }, { name: 'wg_sulfate', type: 'float' }, { name: 'wg_chloride', type: 'float' }, { name: 'wg_sodium', type: 'float' }, { name: 'wg_magnesium', type: 'float' }, { name: 'wg_total_alkalinity', type: 'float' }, { name: 'wg_ph', type: 'float' }, { name: 'wb_calcium', type: 'float' }, { name: 'wb_sulfate', type: 'float' }, { name: 'wb_chloride', type: 'float' }, { name: 'wb_sodium', type: 'float' }, { name: 'wb_magnesium', type: 'float' }, { name: 'wb_total_alkalinity', type: 'float' }, { name: 'wb_ph', type: 'float' }, { name: 'wa_acid_name', type: 'int' }, { name: 'wa_acid_perc', type: 'int' }, { name: 'wa_base_name', type: 'int' }, { name: 'fermentables', type: 'string' }, { name: 'hops', type: 'string' }, { name: 'miscs', type: 'string' }, { name: 'yeasts', type: 'string' }, { name: 'mashs', type: 'string' } ], id: 'record', url: url + '?record=' + my_record }, // Load data and select one record. dataAdapter = new $.jqx.dataAdapter(source, { loadComplete: function() { var records = dataAdapter.records; dataRecord = records[0]; // Hidden record uuid $('#name').val(dataRecord.name); $('#notes').val(dataRecord.notes); // Hidden record locked $('#st_name').val(dataRecord.st_name); $('#st_letter').val(dataRecord.st_letter); $('#st_guide').val(dataRecord.st_guide); $('#st_category').val(dataRecord.st_category); $('#st_category_number').val(dataRecord.st_category_number); $('#st_type').val(StyleTypeData[dataRecord.st_type].nl); $('#type').val(RecipeTypeData[dataRecord.type].nl); $('#batch_size').val(dataRecord.batch_size); $('#boil_size').val(dataRecord.boil_size); $('#boil_time').val(dataRecord.boil_time); $('#efficiency').val(dataRecord.efficiency); $('#est_og').val(dataRecord.est_og); $('#est_og2').val(dataRecord.est_og); $('#st_og_min').val(dataRecord.st_og_min); $('#st_og_max').val(dataRecord.st_og_max); $('#est_fg').val(dataRecord.est_fg); $('#est_fg2').val(dataRecord.est_fg); $('#st_fg_min').val(dataRecord.st_fg_min); $('#st_fg_max').val(dataRecord.st_fg_max); $('#est_fg').val(dataRecord.est_fg); $('#est_fg2').val(dataRecord.est_fg); $('#st_fg_min').val(dataRecord.st_fg_min); $('#st_fg_max').val(dataRecord.st_fg_max); $('#est_color').val(dataRecord.est_color); $('#est_color2').val(dataRecord.est_color); $('#est_abv').val(dataRecord.est_abv); $('#est_abv2').val(dataRecord.est_abv); $('#st_abv_min').val(dataRecord.st_abv_min); $('#st_abv_max').val(dataRecord.st_abv_max); $('#st_color_min').val(dataRecord.st_color_min); $('#st_color_max').val(dataRecord.st_color_max); $('#color_method').val(ColorMethodData[dataRecord.color_method].nl); $('#est_ibu').val(dataRecord.est_ibu); $('#est_ibu2').val(dataRecord.est_ibu); $('#st_ibu_min').val(dataRecord.st_ibu_min); $('#st_ibu_max').val(dataRecord.st_ibu_max); $('#ibu_method').val(IBUmethodData[dataRecord.ibu_method].nl); $('#est_carb').val(dataRecord.est_carb); $('#st_carb_min').val(dataRecord.st_carb_min); $('#st_carb_max').val(dataRecord.st_carb_max); $('#mash_name').val(dataRecord.mash_name); $('#mash_ph').val(dataRecord.mash_ph); // Hidden record sparge_temp $('#sparge_ph').val(dataRecord.sparge_ph); $('#sw_amount').val(dataRecord.sparge_volume); // Hidden record sparge_source $('#sparge_acid_type').val(AcidTypeData[dataRecord.sparge_acid_type].nl); $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); $('#sparge_acid_amount').val(dataRecord.sparge_acid_amount * 1000); $('#calc_acid').val(dataRecord.calc_acid); $('#w1_name').val(dataRecord.w1_name); $('#w1_amount').val(dataRecord.w1_amount); $('#w1_calcium').val(dataRecord.w1_calcium); $('#w1_sulfate').val(dataRecord.w1_sulfate); $('#w1_chloride').val(dataRecord.w1_chloride); $('#w1_sodium').val(dataRecord.w1_sodium); $('#w1_magnesium').val(dataRecord.w1_magnesium); $('#w1_total_alkalinity').val(dataRecord.w1_total_alkalinity); $('#w1_ph').val(dataRecord.w1_ph); $('#w1_bicarbonate').val(Bicarbonate(dataRecord.w1_total_alkalinity, dataRecord.w1_ph)); $('#w1_cost').val(dataRecord.w1_cost); $('#w2_name').val(dataRecord.w2_name); $('#w2_amount').val(dataRecord.w2_amount); $('#w2_calcium').val(dataRecord.w2_calcium); $('#w2_sulfate').val(dataRecord.w2_sulfate); $('#w2_chloride').val(dataRecord.w2_chloride); $('#w2_sodium').val(dataRecord.w2_sodium); $('#w2_magnesium').val(dataRecord.w2_magnesium); $('#w2_total_alkalinity').val(dataRecord.w2_total_alkalinity); $('#w2_ph').val(dataRecord.w2_ph); $('#w2_bicarbonate').val(Bicarbonate(dataRecord.w2_total_alkalinity, dataRecord.w2_ph)); $('#w2_cost').val(dataRecord.w2_cost); $('#wg_amount').val(dataRecord.wg_amount); $('#wg_calcium').val(dataRecord.wg_calcium); $('#wg_sulfate').val(dataRecord.wg_sulfate); $('#wg_chloride').val(dataRecord.wg_chloride); $('#wg_sodium').val(dataRecord.wg_sodium); $('#wg_magnesium').val(dataRecord.wg_magnesium); $('#wg_total_alkalinity').val(dataRecord.wg_total_alkalinity); $('#wg_ph').val(dataRecord.wg_ph); $('#wb_calcium').val(dataRecord.wb_calcium); $('#wb_sulfate').val(dataRecord.wb_sulfate); $('#wb_chloride').val(dataRecord.wb_chloride); $('#wb_sodium').val(dataRecord.wb_sodium); $('#wb_magnesium').val(dataRecord.wb_magnesium); $('#wb_total_alkalinity').val(dataRecord.wb_total_alkalinity); $('#wb_ph').val(dataRecord.wb_ph); $('#wa_acid_name').val(AcidTypeData[dataRecord.wa_acid_name].nl); $('#wa_acid_perc').val(dataRecord.wa_acid_perc); editFermentable(dataRecord); editHop(dataRecord); editMisc(dataRecord); editYeast(dataRecord); editMash(dataRecord); $('#jqxTabs').jqxTabs('next'); data_loaded = 1; }, loadError: function(jqXHR, status, error) {}, beforeLoadComplete: function(records) { $('#jqxLoader').jqxLoader('open'); } }), // Inline fermentables editor editFermentable = function(data) { var fermentableSource = { localdata: data.fermentables, datafields: [ { name: 'f_name', type: 'string' }, { name: 'f_origin', type: 'string' }, { name: 'f_supplier', type: 'string' }, { name: 'f_amount', type: 'float' }, { name: 'f_cost', type: 'float' }, { name: 'f_type', type: 'int' }, { name: 'f_yield', type: 'float' }, { name: 'f_color', type: 'float' }, { name: 'f_coarse_fine_diff', type: 'float' }, { name: 'f_moisture', type: 'float' }, { name: 'f_diastatic_power', type: 'float' }, { name: 'f_protein', type: 'float' }, { name: 'f_max_in_batch', type: 'float' }, { name: 'f_graintype', type: 'int' }, { name: 'f_added', type: 'int' }, { name: 'f_dissolved_protein', type: 'float' }, { name: 'f_recommend_mash', type: 'int' }, { name: 'f_add_after_boil', type: 'int' }, { name: 'f_adjust_to_total_100', type: 'int' }, { name: 'f_percentage', type: 'float' }, { name: 'f_di_ph', type: 'float' }, { name: 'f_acid_to_ph_57', type: 'float' }, { name: 'f_inventory', type: 'float' }, { name: 'f_avail', type: 'int' } ], }, fermentableAdapter = new $.jqx.dataAdapter(fermentableSource); $('#fermentableGrid').jqxGrid({ width: 1240, height: 470, source: fermentableAdapter, theme: theme, editable: false, ready: function() { calcFermentables(); $('#jqxTabs').jqxTabs('next'); }, columns: [ { text: 'Vergistbaar ingrediënt', datafield: 'f_name' }, { text: 'Leverancier', datafield: 'f_supplier', width: 180 }, { text: 'Kleur', datafield: 'f_color', width: 90, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f0') + ' EBC</span>'; } }, { text: 'Type', width: 100, datafield: 'f_type', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 3px; margin-top: 6px; float: left;">' + FermentableTypeData[value].nl + '</span>'; } }, { text: 'Moment', width: 110, datafield: 'f_added', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 3px; margin-top: 6px; float: left;">' + AddedData[value].nl + '</span>'; } }, { text: 'Maxinbatch', datafield: 'f_max_in_batch', hidden: true }, { text: 'Opbrengst', editable: false, datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, { text: 'Gewicht Kg', datafield: 'f_amount', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f3' }, { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right', cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { var color = '#ffffff'; if (value > rowdata.f_max_in_batch) color = '#ff4040'; return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + fermentableAdapter.formatNumber(value, 'p1') + '</span>'; } }, { text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 70 } ] }); }; // Inline hops editor var editHop = function(data) { var hopSource = { localdata: data.hops, datafields: [ { name: 'h_name', type: 'string' }, { name: 'h_origin', type: 'string' }, { name: 'h_amount', type: 'float' }, { name: 'h_cost', type: 'float' }, { name: 'h_type', type: 'int' }, { name: 'h_form', type: 'int' }, { name: 'h_useat', type: 'int' }, { name: 'h_time', type: 'float' }, { name: 'h_alpha', type: 'float' }, { name: 'h_beta', type: 'float' }, { name: 'h_hsi', type: 'float' }, { name: 'h_humulene', type: 'float' }, { name: 'h_caryophyllene', type: 'float' }, { name: 'h_cohumulone', type: 'float' }, { name: 'h_myrcene', type: 'float' }, { name: 'h_total_oil', type: 'float' }, { name: 'h_inventory', type: 'float' }, { name: 'h_avail', type: 'int' } ], }, hopAdapter = new $.jqx.dataAdapter(hopSource); $('#hopGrid').jqxGrid({ width: 1240, height: 560, source: hopAdapter, theme: theme, editable: false, ready: function() { $('#jqxTabs').jqxTabs('next'); }, columns: [ { text: 'Hop', datafield: 'h_name' }, { text: 'Origin', width: 180, datafield: 'h_origin' }, { text: 'Type', width: 90, datafield: 'h_type', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopTypeData[value].nl + '</span>'; } }, { text: 'Vorm', width: 110, datafield: 'h_form', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopFormData[value].nl + '</span>'; } }, { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, { text: 'Gebruik', width: 110, datafield: 'h_useat', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopUseData[value].nl + '</span>'; } }, { text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var duration = ''; if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4)) // Boil, Whirlpool duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; else if (rowdata.h_useat == 5) // Dry hop duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>'; } }, { text: 'IBU', datafield: 'ibu', width: 80, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat(dataRecord.batch_size), parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), dataRecord.ibu_method, 0, parseFloat(rowdata.h_time), 0); return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(ibu, 'f1') + '</span>'; } }, { text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var amount = dataAdapter.formatNumber(value, 'f1') + ' kg'; if (value < 1) amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>'; } } ] }); }; // Inline miscs editor var editMisc = function(data) { var miscSource = { localdata: data.miscs, datafields: [ { name: 'm_name', type: 'string' }, { name: 'm_amount', type: 'float' }, { name: 'm_cost', type: 'float' }, { name: 'm_type', type: 'int' }, { name: 'm_use_use', type: 'int' }, { name: 'm_time', type: 'float' }, { name: 'm_amount_is_weight', type: 'int' }, { name: 'm_inventory', type: 'float' }, { name: 'm_avail', type: 'int' } ], }, miscAdapter = new $.jqx.dataAdapter(miscSource, { beforeLoadComplete: function(records) { var i, row, data = new Array(); for (i = 0; i < records.length; i++) { row = records[i]; data.push(row); // Initial set water agent values. if (row.m_use_use == 1) { // Mash switch (row.m_name) { case 'CaCl2': $('#wa_cacl2').val(row.m_amount * 1000); break; case 'CaSO4': $('#wa_caso4').val(row.m_amount * 1000); break; case 'MgSO4': $('#wa_mgso4').val(row.m_amount * 1000); break; case 'NaCl': $('#wa_nacl').val(row.m_amount * 1000); break; case 'MgCl2': $('#wa_mgcl2').val(row.m_amount * 1000); break; case 'NaHCO3': $('#wa_nahco3').val(row.m_amount * 1000); break; case 'CaCO3': $('#wa_caco3').val(row.m_amount * 1000); break; case 'Melkzuur': $('#wa_acid_name').val(AcidTypeData[0].nl); $('#wa_acid').val(row.m_amount * 1000); $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); last_acid = 'Melkzuur'; break; case 'Zoutzuur': $('#wa_acid_name').val(AcidTypeData[1].nl); $('#wa_acid').val(row.m_amount * 1000); $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); last_acid = 'Zoutzuur'; break; case 'Fosforzuur': $('#wa_acid_name').val(AcidTypeData[2].nl); $('#wa_acid').val(row.m_amount * 1000); $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); last_acid = 'Fosforzuur'; break; case 'Zwavelzuur': $('#wa_acid_name').val(AcidTypeData[3].nl); $('#wa_acid').val(row.m_amount * 1000); $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); last_acid = 'Zwavelzuur'; break; } } if (row.m_use_use == 6) { // Sparge switch (row.m_name) { case 'CaCl2': $('#ss_cacl2').val(row.m_amount * 1000); break; case 'CaSO4': $('#ss_caso4').val(row.m_amount * 1000); break; case 'MgSO4': $('#ss_mgso4').val(row.m_amount * 1000); break; case 'NaCl': $('#ss_nacl').val(row.m_amount * 1000); break; case 'MgCl2': $('#ss_mgcl2').val(row.m_amount * 1000); break; case 'Melkzuur': // $('#wa_acid_name').val(0); // $('#wa_acid').val(row.m_amount * 1000); // $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); // TODO: this ignores changed percentages. // last_acid = 'Melkzuur'; break; case 'Zoutzuur': // $('#wa_acid_name').val(1); // $('#wa_acid').val(row.m_amount * 1000); // $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); // last_acid = 'Zoutzuur'; break; case 'Fosforzuur': // $('#wa_acid_name').val(2); // $('#wa_acid').val(row.m_amount * 1000); // $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); // last_acid = 'Fosforzuur'; break; case 'Zwavelzuur': // $('#wa_acid_name').val(3); // $('#wa_acid').val(row.m_amount * 1000); // $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); // last_acid = 'Zwavelzuur'; break; } } } return data; }, loadError: function(jqXHR, status, error) {} }); $('#miscGrid').jqxGrid({ width: 1240, height: 575, source: miscAdapter, theme: theme, editable: false, ready: function() { $('#jqxTabs').jqxTabs('next'); }, columns: [ { text: 'Ingredient', datafield: 'm_name' }, { text: 'Type', width: 140, datafield: 'm_type', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 3px; margin-top: 6px; float: left;">' + MiscTypeData[value].nl + '</span>'; } }, { text: 'Gebruik', width: 140, datafield: 'm_use_use', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 3px; margin-top: 6px; float: left;">' + MiscUseData[value].nl + '</span>'; } }, { text: 'Tijd', datafield: 'm_time', width: 140, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var duration = ''; if (rowdata.m_use_use == 2) // Boil duration = dataAdapter.formatNumber(value, 'f0') + ' minuten'; else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) // Primary or Secondary duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>'; } }, { text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr + '</span>'; } } ] }); }; // Inline yeasts editor var editYeast = function(data) { var yeastSource = { localdata: data.yeasts, datafields: [ { name: 'y_name', type: 'string' }, { name: 'y_laboratory', type: 'string' }, { name: 'y_product_id', type: 'string' }, { name: 'y_amount', type: 'float' }, { name: 'y_cost', type: 'float' }, { name: 'y_type', type: 'int' }, { name: 'y_form', type: 'int' }, { name: 'y_flocculation', type: 'int' }, { name: 'y_min_temperature', type: 'float' }, { name: 'y_max_temperature', type: 'float' }, { name: 'y_attenuation', type: 'float' }, { name: 'y_use', type: 'int' }, { name: 'y_cells', type: 'float' }, { name: 'y_tolerance', type: 'float' }, { name: 'y_inventory', type: 'float' }, { name: 'y_sta1', type: 'int' }, { name: 'y_bacteria', type: 'int' }, { name: 'y_harvest_top', type: 'int' }, { name: 'y_harvest_time', type: 'int' }, { name: 'y_pitch_temperature', type: 'float' }, { name: 'y_pofpos', type: 'int' }, { name: 'y_zymocide', type: 'int' }, { name: 'y_gr_hl_lo', type: 'int' }, { name: 'y_sg_lo', type: 'float' }, { name: 'y_gr_hl_hi', type: 'int' }, { name: 'y_sg_hi', type: 'float' }, { name: 'y_avail', type: 'int' } ], }, yeastAdapter = new $.jqx.dataAdapter(yeastSource); $('#yeastGrid').jqxGrid({ width: 1240, height: 350, source: yeastAdapter, theme: theme, editable: false, ready: function() { calcFermentables(); $('#jqxTabs').jqxTabs('next'); }, columns: [ { text: 'Gist', datafield: 'y_name' }, { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' }, { text: 'Code', width: 90, datafield: 'y_product_id' }, { text: 'Soort', width: 100, datafield: 'y_form', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastFormData[value].nl + '</span>'; } }, { text: 'Min. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' }, { text: 'Max. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' }, { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var amount = '', color = '#ffffff'; if (value > 0) { amount = dataAdapter.formatNumber(value, 'f1'); if (dataRecord.est_abv > value) color = '#ff4040'; } return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>'; } }, { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' }, { text: 'Voor', width: 120, datafield: 'y_use', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastUseData[value].nl + '</span>'; } }, { text: 'Hoeveel', datafield: 'y_amount', width: 90, align: 'right', cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { var amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; if (rowdata.y_form == 0) // Liquid amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; else if (rowdata.y_form == 1) // Dry amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>'; } } ] }); }; // inline mash editor var editMash = function(data) { var mashSource = { localdata: data.mashs, datafields: [ { name: 'step_name', type: 'string' }, { name: 'step_type', type: 'int' }, { name: 'step_volume', type: 'float' }, { name: 'step_infuse_amount', type: 'float' }, { name: 'step_infuse_temp', type: 'float' }, { name: 'step_temp', type: 'float' }, { name: 'step_time', type: 'float' }, { name: 'step_wg_ratio', type: 'float' }, { name: 'ramp_time', type: 'float' }, { name: 'end_temp', type: 'float' } ], }, mashAdapter = new $.jqx.dataAdapter(mashSource, { beforeLoadComplete: function(records) { mash_infuse = 0; var row, i, data = new Array(); for (i = 0; i < records.length; i++) { row = records[i]; if (row.step_type == 0) // Infusion mash_infuse += parseFloat(row.step_infuse_amount); row.step_wg_ratio = 0; // Init this field. data.push(row); } }, }); $('#mashGrid').jqxGrid({ width: 1240, height: 400, source: mashAdapter, theme: theme, editable: false, ready: function() { calcFermentables(); calcInit(); calcMash(); $('#jqxLoader').jqxLoader('close'); $('#jqxTabs').jqxTabs('first'); }, columns: [ { text: 'Stap naam', datafield: 'step_name' }, { text: 'Stap type', datafield: 'step_type', width: 175, cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { return '<div style="margin: 4px;">' + MashStepTypeData[value].nl + '</div>'; } }, { text: 'Start °C', datafield: 'step_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, { text: 'Eind °C', datafield: 'end_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, { text: 'Rust min.', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' }, { text: 'Stap min.', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' }, { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 90, align: 'right', cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { if (rowdata.step_type == 1) return '<span></span>'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f1') + '</span>'; } }, { text: 'Inf/dec °C', datafield: 'step_infuse_temp', width: 90, align: 'right', cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { if (rowdata.step_type == 1) return '<span></span>'; return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f2') + '</span>'; } }, { text: 'L/Kg.', datafield: 'step_wg_ratio', width: 90, align: 'right', cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { var color = '#ffffff'; if (value < 2.0 || value > 6.0) color = '#ff4040'; return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + dataAdapter.formatNumber(value, 'f2') + '</span>'; } } ] }); }; /* * Remove the top menu so that we MUST use the buttons to leave the editor. */ $('#jqxMenu').jqxMenu('destroy'); console.log('record:' + my_record + ' return:' + my_return + ' theme:' + theme); $('#jqxLoader').jqxLoader({ width: 250, height: 150, isModal: true, text: 'Laden recept ...', theme: theme }); function setWaterAgent(name, amount) { var record, records, miscs, i, id, row, found = false, rows = $('#miscGrid').jqxGrid('getrows'); if (amount == 0) { for (i = 0; i < rows.length; i++) { row = rows[i]; if (row.m_name == name) { id = $('#miscGrid').jqxGrid('getrowid', i); $('#miscGrid').jqxGrid('deleterow', id); } } } else { for (i = 0; i < rows.length; i++) { row = rows[i]; if (row.m_name == name) { found = true; $('#miscGrid').jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); break; } } if (! found) { miscs = new $.jqx.dataAdapter(miscInvSource, { loadComplete: function() { records = miscs.records; for (i = 0; i < records.length; i++) { record = records[i]; if (record.name == name) { row = {}; row['m_name'] = record.name; row['m_amount'] = amount / 1000; row['m_cost'] = record.cost; row['m_type'] = record.type; row['m_use_use'] = record.use_use; row['m_time'] = 0; row['m_amount_is_weight'] = record.amount_is_weight; row['m_inventory'] = record.inventory; row['m_avail'] = 1; $('#miscGrid').jqxGrid('addrow', null, row); } } } }); miscs.dataBind(); return; } } } // Procedure TFrmWaterAdjustment.CalcWater2; function calcWater() { if (! data_loaded) { console.log('calcWater(): failsave'); return; } var liters = 0, calcium = 0, magnesium = 0, sodium = 0, total_alkalinity = 0, bicarbonate = 0, chloride = 0, sulfate = 0, ph = 0, RA = 0, frac = 0, TpH = 0, protonDeficit = 0, AT, BT, r1d, r2d, f1d, f2d, f3d, deltapH, deltapd, pd, n, Res; if (dataRecord.w1_name == '') { return; } $('#w1_hardness').val(Hardness(dataRecord.w1_calcium, dataRecord.w1_magnesium)); $('#w1_ra').val(ResidualAlkalinity(dataRecord.w1_total_alkalinity, dataRecord.w1_calcium, dataRecord.w1_magnesium)); // If there is a dillute water source, mix the waters. if (dataRecord.w2_name != '') { liters = dataRecord.w1_amount + dataRecord.w2_amount; calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); $('#w2_hardness').val(Hardness(dataRecord.w2_calcium, dataRecord.w2_magnesium)); $('#w2_ra').val(ResidualAlkalinity(dataRecord.w2_total_alkalinity, dataRecord.w2_calcium, dataRecord.w2_magnesium)); } else { liters = dataRecord.w1_amount; calcium = dataRecord.w1_calcium; magnesium = dataRecord.w1_magnesium; sodium = dataRecord.w1_sodium; chloride = dataRecord.w1_chloride; sulfate = dataRecord.w1_sulfate; total_alkalinity = dataRecord.w1_total_alkalinity; ph = dataRecord.w1_ph; } var bicarbonate = Bicarbonate(total_alkalinity, ph); /* Save mixed water ions for later */ var wg_calcium = calcium; var wg_sodium = sodium; var wg_total_alkalinity = total_alkalinity; var wg_chloride = chloride; var wg_sulfate = sulfate; var wg_bicarbonate = bicarbonate; dataRecord.wg_amount = liters; dataRecord.wg_ph = ph; $('#wg_amount').val(liters); $('#wg_calcium').val(Round(calcium, 1)); $('#wg_magnesium').val(Round(magnesium, 1)); $('#wg_sodium').val(Round(sodium, 1)); $('#wg_bicarbonate').val(Round(bicarbonate, 1)); $('#wg_total_alkalinity').val(Round(total_alkalinity, 1)); $('#wg_chloride').val(Round(chloride, 1)); $('#wg_sulfate').val(Round(sulfate, 1)); $('#wg_ph').val(Round(ph, 2)); $('#wg_hardness').val(Round(Hardness(calcium, magnesium), 1)); $('#wg_ra').val(Round(ResidualAlkalinity(total_alkalinity, calcium, magnesium), 1)); var mash_ph = Round(MashpH(), 3); console.log('Distilled water mash pH: ' + mash_ph); /* Calculate Salt additions */ if (liters > 0) { calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 + parseFloat($('#wa_caco3').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters; magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / liters; sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 + parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters; sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters; chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / liters; bicarbonate += (parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000 + parseFloat($('#wa_caco3').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / liters; } if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) { $('#wa_acid_name').val(0); dataRecord.wa_acid_name = 0; dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc; $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); } if (last_acid == '') last_acid = AcidTypeData[dataRecord.wa_acid_name].nl; if (parseFloat(dataRecord.wa_acid_perc) == 0) { dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc; $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc); } AT = dataRecord.wa_acid_name; /* Note that the next calculations do not correct the pH change by the added salts. This pH change is at most 0.1 pH and is a minor difference in Acid amount. */ if (dataRecord.calc_acid) { $('.c_mashph').show(); /* Auto calculate pH */ TpH = parseFloat(dataRecord.mash_ph); protonDeficit = ProtonDeficit(TpH); console.log('calc_acid tgt: ' + TpH + ' protonDeficit: ' + protonDeficit); if (protonDeficit > 0) { // Add acid frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); Acid = protonDeficit / frac; Acid *= AcidTypeData[AT].MolWt; // mg Acidmg = Acid; var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (parseFloat(dataRecord.wa_acid_perc) / 100)) + 1000, 2); Acid /= RealSG; Acid /= AcidTypeData[AT].AcidPrc / 100; Acid = Round(Acid, 2); console.log('Mash auto Acid final ml: ' + Acid); $('#wa_acid').val(Acid); setWaterAgent(AcidTypeData[AT].nl, Acid); bicarbonate = bicarbonate - protonDeficit * frac / liters; total_alkalinity = bicarbonate * 50 / 61; } ph = TpH; dataRecord.wb_ph = ph; $('#wb_ph').val(Round(ph, 2)); $('#est_mash_ph').val(Round(ph, 2)); } else { // Manual /* Manual calculate pH */ $('.c_mashph').hide(); console.log('calc_acid no'); pHa = Round(ph, 3); // Adjusted water pH // Then calculate the new pH with added acids and malts console.log('Mash pH: ' + pHa); Acid = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal')); Acid /= AcidTypeData[AT].MolWt; // mg Acidmg = Acid; //find the pH where the protondeficit = protondeficit by the acid frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); protonDeficit = Round(Acid * frac, 3); //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa); deltapH = 0.001; deltapd = 0.1; pd = Round(ProtonDeficit(pHa), 6); n = 0; while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) { n++; if (pd < (protonDeficit - deltapd)) pHa -= deltapH; else if (pd > (protonDeficit + deltapd)) pHa += deltapH; frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); protonDeficit = Acid * frac; pd = ProtonDeficit(pHa); } //console.log('n: ' + n + ' pd: ' + pd + ' protonDeficit: ' + protonDeficit + ' frac: ' + frac + ' pHa: ' + pHa); bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; total_alkalinity = bicarbonate * 50 / 61; ph = pHa; $('#wb_ph').val(Round(ph, 2)); $('#est_mash_ph').val(Round(ph, 2)); } if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + Acidmg / 1000 * MMSO4 / (MMSO4 + 2); RA = 1000 * RA / liters; sulfate = wg_sulfate + RA; // Not add to sulfate?? } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur RA = parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 + parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl + Acidmg / 1000 * MMCl / (MMCl + 1); RA = 1000 * RA / liters; chloride = wg_chloride + RA; } var BUGU = GetBUGU(); $('#tgt_bu').val(Round(BUGU, 2)); // From brouwhulp. if (BUGU < 0.32) $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>"); else if (BUGU < 0.43) $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>"); else if (BUGU < 0.52) $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>"); else if (BUGU < 0.63) $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>"); else $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>"); // Sulfate to Chloride ratio (Palmer). var OptSO4Clratio = GetOptSO4Clratio(); $('#tgt_so4_cl').val(Round(OptSO4Clratio, 1)); if (OptSO4Clratio < 0.4) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Te moutig</span>"); else if (OptSO4Clratio < 0.6) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig</span>"); else if (OptSO4Clratio < 0.8) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig</span>"); else if (OptSO4Clratio < 1.5) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Gebalanceerd</span>"); else if (OptSO4Clratio < 2.0) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht bitter</span>"); else if (OptSO4Clratio < 4.0) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Bitter</span>"); else if (OptSO4Clratio < 9.0) $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer bitter</span>"); else $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Te bitter</span>"); if (chloride > 0) RA = sulfate / chloride; else RA = 10; $('#got_so4_cl').val(Round(RA, 1)); Res = 'normaal'; if (RA < (0.8 * OptSO4Clratio)) Res = 'laag'; else if (RA > (1.2 * OptSO4Clratio)) Res = 'hoog'; setRangeIndicator('so4_cl', Res); $('#wb_calcium').val(Round(calcium, 1)); $('#wb_magnesium').val(Round(magnesium, 1)); $('#wb_sodium').val(Round(sodium, 1)); $('#wb_sulfate').val(Round(sulfate, 1)); $('#wb_chloride').val(Round(chloride, 1)); $('#wb_bicarbonate').val(Round(bicarbonate, 1)); $('#wb_total_alkalinity').val(Round(total_alkalinity, 1)); $('#wb_hardness').val(Hardness(calcium, magnesium)); $('#wb_ra').val(ResidualAlkalinity(total_alkalinity, calcium, magnesium)); if (calcium < 40) { setRangeIndicator('calcium', 'laag'); } else if (calcium > 150) { setRangeIndicator('calcium', 'hoog'); } else { setRangeIndicator('calcium', 'normaal'); } if (magnesium < 5) { setRangeIndicator('magnesium', 'laag'); } else if (magnesium > 40) { setRangeIndicator('magnesium', 'hoog'); } else { setRangeIndicator('magnesium', 'normaal'); } if (sodium <= 150) { setRangeIndicator('sodium', 'normaal'); } else { setRangeIndicator('sodium', 'hoog'); } // Both chloride and sulfate should be above 50 according to // John Palmer. So the Cl/SO4 ratio calculation will work. if (chloride <= 50) { setRangeIndicator('chloride', 'laag'); } else if (chloride <= 150) { setRangeIndicator('chloride', 'normaal'); } else { setRangeIndicator('chloride', 'hoog'); } if (sulfate <= 50) { setRangeIndicator('sulfate', 'laag'); } else if (sulfate <= 400) { setRangeIndicator('sulfate', 'normaal'); } else { setRangeIndicator('sulfate', 'hoog'); } // (cloride + sulfate) > 500 is too high if ((chloride + sulfate) > 500) { setRangeIndicator('chloride', 'hoog'); setRangeIndicator('sulfate', 'hoog'); } if (ph < 5.2) { setRangeIndicator('ph', 'laag'); } else if (ph > 5.6) { setRangeIndicator('ph', 'hoog'); } else { setRangeIndicator('ph', 'normaal'); } if (bicarbonate > 250) { setRangeIndicator('bicarbonate', 'hoog'); } else { setRangeIndicator('bicarbonate', 'normaal'); } calcSparge(); } function calcSparge() { /* Based on the work of ajDeLange. */ var ws_calcium, ws_magnesium, ws_total_alkalinity, ws_sodium, ws_chloride; var ws_sulfate, ws_ph, ws_hardness, ws_ra; var TargetpH = dataRecord.sparge_ph; var Source_pH = 7.0; // Select watersource or fallback to the first source. if ((dataRecord.sparge_source == 1) && (dataRecord.w2_ph > 0.0)) { // Source 2 ws_calcium = dataRecord.w2_calcium; ws_magnesium = dataRecord.w2_magnesium; ws_total_alkalinity = dataRecord.w2_total_alkalinity; ws_sodium = dataRecord.w2_sodium; ws_chloride = dataRecord.w2_chloride; ws_sulfate = dataRecord.w2_sulfate; Source_pH = dataRecord.w2_ph; $('#w2_button').jqxRadioButton({ checked: true }); } else if ((dataRecord.sparge_source == 2) && (dataRecord.w2_ph > 0.0)) { // Mixed ws_calcium = dataRecord.wg_calcium; ws_magnesium = dataRecord.wg_magnesium; ws_total_alkalinity = dataRecord.wg_total_alkalinity; ws_sodium = dataRecord.wg_sodium; ws_chloride = dataRecord.wg_chloride; ws_sulfate = dataRecord.wg_sulfate; Source_pH = dataRecord.wg_ph; $('#wg_button').jqxRadioButton({ checked: true }); } else { ws_calcium = dataRecord.w1_calcium; ws_magnesium = dataRecord.w1_magnesium; ws_total_alkalinity = dataRecord.w1_total_alkalinity; ws_sodium = dataRecord.w1_sodium; ws_chloride = dataRecord.w1_chloride; ws_sulfate = dataRecord.w1_sulfate; Source_pH = dataRecord.w1_ph; $('#w1_button').jqxRadioButton({ checked: true }); } if (dataRecord.sparge_volume > 0) { ws_calcium += (parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / dataRecord.sparge_volume; ws_magnesium += (parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / dataRecord.sparge_volume; ws_sodium += (parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000) / dataRecord.sparge_volume; ws_sulfate += (parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / dataRecord.sparge_volume; ws_chloride += (2 * parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / dataRecord.sparge_volume; } /* Show the spargewate with salt additions */ $('#sw_calcium').val(Round(ws_calcium, 1)); $('#sw_magnesium').val(Round(ws_magnesium, 1)); $('#sw_sodium').val(Round(ws_sodium, 1)); $('#sw_sulfate').val(Round(ws_sulfate, 1)); $('#sw_chloride').val(Round(ws_chloride, 1)); $('#sw_bicarbonate').val(Round(Bicarbonate(ws_total_alkalinity, Source_pH), 1)); $('#sw_total_alkalinity').val(Round(ws_total_alkalinity, 1)); $('#sw_ph').val(dataRecord.sparge_ph); $('#sw_hardness').val(Hardness(ws_calcium, ws_magnesium)); $('#sw_ra').val(ResidualAlkalinity(ws_total_alkalinity, ws_calcium, ws_magnesium)); AT = dataRecord.sparge_acid_type; if (AT < 0 || AT >= AcidTypeData.length) { AT = 0; dataRecord.sparge_acid_type = 0; $('#sparge_acid_type').val(AcidTypeData[0].nl); dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc; $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); } /* * Auto calculate the required acid */ if (dataRecord.calc_acid) { // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH var r1 = Math.pow(10, Source_pH - 6.35); var r2 = Math.pow(10, Source_pH - 10.33); var d = 1 + r1 + r1 * r2; var f1 = 1 / d; var f3 = r1 * r2 / d; //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) var r143 = Math.pow(10, 4.3 - 6.35); var r243 = Math.pow(10, 4.3 - 10.33); var d43 = 1 + r143 + r143 * r243; var f143 = 1 / d43; var f343 = r143 * r243 / d43; //Step 4. Solve var Ct = ws_total_alkalinity / 50 / ((f143 - f1) + (f3 - f343)); //Step 5. Compute mole fractions at desired pH var r1g = Math.pow(10, TargetpH - 6.35); var r2g = Math.pow(10, TargetpH - 10.33); var dg = 1 + r1g + r1g * r2g; var f1g = 1 / dg; var f3g = r1g * r2g / dg; //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l Acid += 0.01; // Add acid that would be required for distilled water. //Step 8. Get the acid data. var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. Acid /= fract; //Step 10. Multiply by molecular weight of the acid Acid *= AcidTypeData[AT].MolWt; //mg //Step 11. Divide by Specific Gravity and Percentage to get the final ml. var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (dataRecord.sparge_acid_perc / 100)) + 1000, 2); Acid = Acid / RealSG; //ml Acid *= dataRecord.sparge_volume; //ml acid total at 100% Acid /= AcidTypeData[AT].AcidPrc / 100; //ml acid at supplied strength Acid = Round(Acid, 2); dataRecord.sparge_acid_amount = Acid / 1000; $('#sparge_acid_amount').val(Acid); } // Finally calculate the estimate preboil pH var ph = -Math.log10(((Math.pow(10, -dataRecord.wb_ph) * dataRecord.wg_amount) + (Math.pow(10, -dataRecord.sparge_ph) * dataRecord.sparge_volume)) / (dataRecord.wg_amount + dataRecord.sparge_volume)); $('#preboil_ph').val(ph); } function calcInit() { console.log('calc.init()'); calcWater(); $('#w1_name').jqxDropDownList('selectItem', dataRecord.w1_name); $('#w2_name').jqxDropDownList('selectItem', dataRecord.w2_name); // Fix tap water if zero using mash infuse amount. if (parseFloat($('#w1_amount').jqxNumberInput('decimal')) == 0 && mash_infuse > 0) { $('#w1_amount').val(mash_infuse); dataRecord.w1_amount = mash_infuse; $('#wg_amount').val(mash_infuse); $('#w2_amount').val(0); dataRecord.w2_amount = 0; } calcWater(); }; function saveRecord(goback) { window.location.href = my_return; }; dataAdapter.dataBind(); // initialize the input fields. // Tab 1, Algemeen $('#name').jqxTooltip({ content: 'De naam voor dit recept.' }); $('#name').jqxInput({ theme: theme, width: 640, height: 23 }); $('#notes').jqxTooltip({ content: 'De uitgebreide opmerkingen over dit recept.' }); $('#notes').jqxInput({ theme: theme, width: 960, height: 200 }); $('#type').jqxTooltip({ content: 'Het brouw type van dit recept.' }); $('#type').jqxInput({ theme: theme, width: 180, height: 23 }); $('#efficiency').jqxTooltip({ content: 'Het rendement van maischen en koken.' }); $('#efficiency').jqxNumberInput(Show1dec); $('#batch_size').jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' }); $('#batch_size').jqxNumberInput(Show1dec); $('#batch_size').jqxNumberInput({ min: 4 }); $('#boil_size').jqxTooltip({ content: 'Het volume van het wort voor het koken.' }); $('#boil_size').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 2, readOnly: true }); $('#boil_time').jqxTooltip({ content: 'De kooktijd in minuten.' }); $('#boil_time').jqxNumberInput(Show0dec); $('#boil_time').jqxNumberInput({ min: 4, max: 360 }); $('#st_name').jqxTooltip({ content: 'De bierstijl naam voor dit recept.'}); $('#st_name').jqxInput({ theme: theme, width: 250, height: 23 }); $('#st_letter').jqxTooltip({ content: 'De bierstijl letter voor dit recept.'}); $('#st_letter').jqxInput({ theme: theme, width: 90, height: 23 }); $('#st_guide').jqxTooltip({ content: 'De bierstijl gids voor dit recept.'}); $('#st_guide').jqxInput({ theme: theme, width: 250, height: 23 }); $('#st_category').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'}); $('#st_category').jqxInput({ theme: theme, width: 250, height: 23 }); $('#st_category_number').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'}); $('#st_category_number').jqxNumberInput(Smal0dec); $('#st_type').jqxTooltip({ content: 'Het bierstijl type.'}); $('#st_type').jqxInput({ theme: theme, width: 250, height: 23 }); $('#est_og').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); $('#est_og').jqxNumberInput(Show3dec); $('#st_og_min').jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'}); $('#st_og_min').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); $('#st_og_max').jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'}); $('#st_og_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); $('#est_fg').jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' }); $('#est_fg').jqxNumberInput(Show3dec); $('#st_fg_min').jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'}); $('#st_fg_min').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); $('#st_fg_max').jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'}); $('#st_fg_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); $('#est_abv').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); $('#est_abv').jqxNumberInput(Smal1dec); $('#st_abv_min').jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'}); $('#st_abv_min').jqxNumberInput(Smal1dec); $('#st_abv_max').jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'}); $('#st_abv_max').jqxNumberInput(Smal1dec); $('#est_color').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); $('#est_color').jqxNumberInput(Show0dec); $('#st_color_min').jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'}); $('#st_color_min').jqxNumberInput(Smal0dec); $('#st_color_max').jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'}); $('#st_color_max').jqxNumberInput(Smal0dec); $('#color_method').jqxInput({ theme: theme, width: 180, height: 23 }); $('#est_ibu').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); $('#est_ibu').jqxNumberInput(Show0dec); $('#st_ibu_min').jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'}); $('#st_ibu_min').jqxNumberInput(Smal0dec); $('#st_ibu_max').jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'}); $('#st_ibu_max').jqxNumberInput(Smal0dec); $('#ibu_method').jqxInput({ theme: theme, width: 180, height: 23 }); $('#kcal').jqxTooltip({ content: 'Energie-inhoud in kcal/liter.' }); $('#kcal').jqxNumberInput(Smal0dec); $('#est_carb').jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' }); $('#est_carb').jqxNumberInput(Smal1dec); $('#st_carb_min').jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'}); $('#st_carb_min').jqxNumberInput(Smal1dec); $('#st_carb_max').jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'}); $('#st_carb_max').jqxNumberInput(Smal1dec); // Tab 2, Vergistbaar $('#est_color2').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); $('#est_color2').jqxNumberInput(Show0dec); $('#est_og2').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); $('#est_og2').jqxNumberInput(Show3dec); $('#perc_malts').jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true, max: 120, animationDuration: 0, colorRanges: [ { stop: 90, color: '#008C00' }, { stop: 100, color: '#EB7331' }, { stop: 120, color: '#FF0000' } ], renderText: function(text) { return (Math.round(parseInt(text) * 1.2)) + '%'; } }); $('#perc_sugars').jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, colorRanges: [ { stop: 20, color: '#008C00' }, { stop: 50, color: '#FF0000' } ], renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } }); $('#perc_cara').jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true, max: 50, animationDuration: 0, colorRanges: [ { stop: 25, color: '#008C00' }, { stop: 50, color: '#FF0000' } ], renderText: function(text) { return (Math.round(parseInt(text) * 5) / 10) + '%'; } }); $('#ferm_lintner').jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true, max: 200, animationDuration: 0, colorRanges: [ { stop: 30, color: '#FF0000' }, { stop: 40, color: '#EB7331' }, { stop: 200, color: '#008C00' } ], renderText: function(text) { return (parseInt(text) * 2) + ' lintner'; } }); // Tab 3, Hoppen $('#est_ibu2').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); $('#est_ibu2').jqxNumberInput(Smal0dec); $('#hop_flavour').jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, colorRanges: [ { stop: 20, color: '#004D00' }, { stop: 40, color: '#008C00' }, { stop: 60, color: '#00BF00' }, { stop: 80, color: '#00FF00' }, { stop: 100, color: '#80FF80' } ], renderText: function(text) { var val = parseInt(text); if (val < 20) return 'Weinig'; else if (val < 40) return 'Matig'; else if (val < 60) return 'Redelijk'; else if (val < 80) return 'Veel'; else return 'Zeer veel'; } }); $('#hop_aroma').jqxProgressBar({ width: 300, height: 23, theme: theme, showText: true, animationDuration: 0, colorRanges: [ { stop: 20, color: '#004D00' }, { stop: 40, color: '#008C00' }, { stop: 60, color: '#00BF00' }, { stop: 80, color: '#00FF00' }, { stop: 100, color: '#80FF80' } ], renderText: function(text) { var val = parseInt(text); if (val < 20) return 'Weinig'; else if (val < 40) return 'Matig'; else if (val < 60) return 'Redelijk'; else if (val < 80) return 'Veel'; else return 'Zeer veel'; } }); // Tab 4, Diversen // Tab 5, Gist $('#est_fg2').jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' }); $('#est_fg2').jqxNumberInput(Show3dec); $('#est_abv2').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); $('#est_abv2').jqxNumberInput(Smal1dec); // Tab 6, Maischen $('#mash_name').jqxInput({ theme: theme, width: 320, height: 23 }); // Tab 7, Water $('#tgt_bu').jqxNumberInput(Show2wat); $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat); $('#preboil_ph').jqxNumberInput(Show2wat); // Water source 1 $('#w1_name').jqxInput({ theme: theme, width: 200, height: 23 }); $('#w1_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); $('#w1_amount').jqxNumberInput(Show1wat); $('#w1_calcium').jqxNumberInput(Show1wat); $('#w1_magnesium').jqxNumberInput(Show1wat); $('#w1_sodium').jqxNumberInput(Show1wat); $('#w1_bicarbonate').jqxNumberInput(Show1wat); $('#w1_total_alkalinity').jqxNumberInput(Show1wat); $('#w1_chloride').jqxNumberInput(Show1wat); $('#w1_sulfate').jqxNumberInput(Show1wat); $('#w1_ph').jqxNumberInput(Show2wat); $('#w1_hardness').jqxNumberInput(Show1wat); $('#w1_ra').jqxNumberInput(Show1wat); // Water source 2 $('#w2_name').jqxInput({ theme: theme, width: 200, height: 23 }); $('#w2_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); $('#w2_amount').jqxNumberInput(Show1wat); $('#w2_calcium').jqxNumberInput(Show1wat); $('#w2_magnesium').jqxNumberInput(Show1wat); $('#w2_sodium').jqxNumberInput(Show1wat); $('#w2_bicarbonate').jqxNumberInput(Show1wat); $('#w2_total_alkalinity').jqxNumberInput(Show1wat); $('#w2_chloride').jqxNumberInput(Show1wat); $('#w2_sulfate').jqxNumberInput(Show1wat); $('#w2_ph').jqxNumberInput(Show2wat); $('#w2_hardness').jqxNumberInput(Show1wat); $('#w2_ra').jqxNumberInput(Show1wat); // Water mixed $('#wg_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); $('#wg_amount').jqxNumberInput(Show1wat); $('#wg_calcium').jqxNumberInput(Show1wat); $('#wg_magnesium').jqxNumberInput(Show1wat); $('#wg_sodium').jqxNumberInput(Show1wat); $('#wg_bicarbonate').jqxNumberInput(Show1wat); $('#wg_total_alkalinity').jqxNumberInput(Show1wat); $('#wg_chloride').jqxNumberInput(Show1wat); $('#wg_sulfate').jqxNumberInput(Show1wat); $('#wg_ph').jqxNumberInput(Show2wat); $('#wg_hardness').jqxNumberInput(Show1wat); $('#wg_ra').jqxNumberInput(Show1wat); // Water treated $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'}); $('#wb_calcium').jqxNumberInput(Show1wat); $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tussen 5 en 40.'}); $('#wb_magnesium').jqxNumberInput(Show1wat); $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'}); $('#wb_sodium').jqxNumberInput(Show1wat); $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 150. Samen met Sulfaat minder dan 500.'}); $('#wb_chloride').jqxNumberInput(Show1wat); $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 400. Samen met Sulfaat minder dan 500.'}); $('#wb_sulfate').jqxNumberInput(Show1wat); $('#wb_bicarbonate').jqxTooltip({ content: '0 tot 50 lichte bieren, 50 tot 150 amber bieren, 150 tot 250 donkere bieren.'}); $('#wb_bicarbonate').jqxNumberInput(Show1wat); $('#wb_total_alkalinity').jqxNumberInput(Show1wat); $('#wb_ph').jqxNumberInput(Show2wat); $('#wb_hardness').jqxNumberInput(Show1wat); $('#wb_ra').jqxNumberInput(Show1wat); // Sparge water $('#sw_amount').jqxNumberInput(Show1wat); $('#sw_calcium').jqxNumberInput(Show1wat); $('#sw_magnesium').jqxNumberInput(Show1wat); $('#sw_sodium').jqxNumberInput(Show1wat); $('#sw_bicarbonate').jqxNumberInput(Show1wat); $('#sw_total_alkalinity').jqxNumberInput(Show1wat); $('#sw_chloride').jqxNumberInput(Show1wat); $('#sw_sulfate').jqxNumberInput(Show1wat); $('#sw_ph').jqxNumberInput(Show2wat); $('#sw_hardness').jqxNumberInput(Show1wat); $('#sw_ra').jqxNumberInput(Show1wat); // Water agents $('#wa_cacl2').jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'}); $('#wa_cacl2').jqxNumberInput(Show2wat); $('#ss_cacl2').jqxNumberInput(Show2wat); $('#wa_caso4').jqxTooltip({ content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.' }); $('#wa_caso4').jqxNumberInput(Show2wat); $('#ss_caso4').jqxNumberInput(Show2wat); $('#wa_mgso4').jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'}); $('#wa_mgso4').jqxNumberInput(Show2wat); $('#ss_mgso4').jqxNumberInput(Show2wat); $('#wa_nacl').jqxTooltip({ content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. ' + 'Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.' }); $('#wa_nacl').jqxNumberInput(Show2wat); $('#ss_nacl').jqxNumberInput(Show2wat); $('#wa_mgcl2').jqxTooltip({ content: 'Magnesiumchloride'}); $('#wa_mgcl2').jqxNumberInput(Show2wat); $('#ss_mgcl2').jqxNumberInput(Show2wat); $('#wa_nahco3').jqxTooltip({ content: 'Baksoda'}); $('#wa_caco3').jqxTooltip({ content: 'Kalk'}); $('#wa_nahco3,#wa_caco3').jqxNumberInput(Show2wat); $('#mash_ph').jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'}); $('#mash_ph').jqxNumberInput(Show2dec); $('#calc_acid').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); $('#wa_acid_name').jqxInput({ theme: theme, width: 130, height: 23 }); $('#wa_acid').jqxNumberInput(Show2dec); $('#wa_acid').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); $('#wa_acid_perc').jqxNumberInput(Show0dec); $('#wa_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); // Sparge water $('#sparge_ph').jqxNumberInput(Show2dec); $('#sparge_acid_amount').jqxNumberInput(Show2dec); $('#sparge_acid_amount').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); $('#sparge_acid_type').jqxInput({ theme: theme, width: 130, height: 23 }); $('#sparge_acid_perc').jqxNumberInput(Show0dec); $('#sparge_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); // Tabs inside the popup window. $('#jqxTabs').jqxTabs({ theme: theme, width: 1280, height: 660, autoHeight: false, position: 'top' }); // Button below $('#Terug').jqxButton({ template: 'primary', width: '80px', theme: theme }); $('#Terug').bind('click', function() { window.location.href = my_return; }); });