{"id":671,"date":"2026-01-18T17:25:05","date_gmt":"2026-01-18T09:25:05","guid":{"rendered":"https:\/\/tomchan.hk\/?page_id=671"},"modified":"2026-01-18T17:35:41","modified_gmt":"2026-01-18T09:35:41","slug":"fluid-calculator","status":"publish","type":"page","link":"https:\/\/tomchan.hk\/?page_id=671","title":{"rendered":"Fluid Calculator"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Fluid Calculator<\/h2>\n\n\n<style>\r\n\/* Scoped CSS for GIR Calculator *\/\r\n#gir-tfi-app {\r\n  width: 100%;\r\n  max-width: 100%;\r\n  margin: 1.5rem auto;\r\n  color: #111827;\r\n  font-family: system-ui, -apple-system, sans-serif;\r\n  line-height: 1.5;\r\n  font-size: 16px;\r\n}\r\n#gir-tfi-app * {\r\n  box-sizing: border-box;\r\n}\r\n#gir-tfi-app .card {\r\n  background: #fff;\r\n  border: 1px solid #e5e7eb;\r\n  border-radius: 14px;\r\n  box-shadow: 0 2px 8px rgba(0, 0, 0, .04);\r\n  margin-bottom: 1rem;\r\n}\r\n#gir-tfi-app .stack:after {\r\n  content: \"\";\r\n  display: table;\r\n  clear: both;\r\n}\r\n#gir-tfi-app .row {\r\n  border: 1px solid #d1d5db;\r\n  border-radius: 12px;\r\n  background: #fff;\r\n  display: block;\r\n  width: 100%;\r\n  margin-bottom: .9rem;\r\n}\r\n#gir-tfi-app .row-inner {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  width: 100%;\r\n  padding: .75rem;\r\n  align-items: flex-end;\r\n}\r\n#gir-tfi-app .cell {\r\n  padding-right: .5rem;\r\n  margin-bottom: 0.5rem;\r\n}\r\n#gir-tfi-app .cell:last-child {\r\n  padding-right: 0;\r\n  width: auto;\r\n}\r\n#gir-tfi-app .row-stats {\r\n  background-color: #f9fafb;\r\n  border-top: 1px solid #e5e7eb;\r\n  padding: 0.4rem 0.75rem;\r\n  border-bottom-left-radius: 12px;\r\n  border-bottom-right-radius: 12px;\r\n  color: #4b5563;\r\n  font-size: 0.85rem;\r\n  display: flex;\r\n  gap: 1.5rem;\r\n  align-items: center;\r\n  flex-wrap: wrap;\r\n}\r\n#gir-tfi-app .row-stats strong {\r\n  font-weight: 600;\r\n  color: #111827;\r\n}\r\n\/* Flex widths for desktop *\/\r\n#gir-tfi-app .w-type { width: 20%; }\r\n#gir-tfi-app .w-mid { width: 14%; }\r\n#gir-tfi-app .w-del { width: 50px; }\r\n#gir-tfi-app label {\r\n  font-size: .8rem;\r\n  color: #374151;\r\n  margin-bottom: .25rem;\r\n  display: block;\r\n  line-height: 1.2;\r\n}\r\n#gir-tfi-app input, #gir-tfi-app select {\r\n  width: 100%;\r\n  height: 40px;\r\n  padding: 0 .5rem;\r\n  border: 1px solid #d1d5db;\r\n  border-radius: 8px;\r\n  font-size: .9rem;\r\n  background: #fff;\r\n  color: #111827;\r\n  margin: 0;\r\n}\r\n#gir-tfi-app .btn {\r\n  display: inline-block;\r\n  border: 1px solid #d1d5db;\r\n  border-radius: 12px;\r\n  padding: .55rem .8rem;\r\n  background: #fff;\r\n  cursor: pointer;\r\n  font-size: .95rem;\r\n  color: #111827;\r\n  line-height: 1;\r\n}\r\n#gir-tfi-app .btn.primary { background: #111827; color: #fff; border-color: #111827; }\r\n#gir-tfi-app .btn.danger {\r\n  color: #b91c1c;\r\n  border-color: #fecaca;\r\n  background: #fff5f5;\r\n  padding: 0;\r\n  height: 40px;\r\n  width: 40px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n}\r\n#gir-tfi-app .muted { color: #6b7280; font-size: .9rem; }\r\n\/* Output KPIs *\/\r\n#gir-tfi-app .out {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 2%;\r\n}\r\n#gir-tfi-app .kpi {\r\n  flex: 1;\r\n  min-width: 120px;\r\n  padding: 1rem;\r\n  border: 1px dashed #d1d5db;\r\n  border-radius: 12px;\r\n  background: #fafafa;\r\n  text-align: center;\r\n  margin-bottom: 0.5rem;\r\n}\r\n#gir-tfi-app .kpi h3 { margin: .2rem 0 .4rem 0; font-size: 1.05rem; }\r\n#gir-tfi-app .kpi .val { font-size: 1.4rem; font-weight: 700; }\r\n#gir-tfi-app .top-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }\r\n\/* Mobile Responsive *\/\r\n@media (max-width: 768px) {\r\n  #gir-tfi-app .row-inner { display: block; padding-bottom: 0; }\r\n  #gir-tfi-app .cell { width: 100% !important; padding-right: 0; margin-bottom: .75rem; }\r\n  #gir-tfi-app .btn.danger { width: 100%; border-radius: 8px; }\r\n  #gir-tfi-app .kpi { width: 100%; flex: 100%; }\r\n}\r\n#notesBox { display: none; margin-top: .6rem; line-height: 1.45; }\r\n#notesBox ul { padding-left: 1.5rem; margin: 0; }\r\n#notesBox li { margin-bottom: 0.5rem; }\r\n#notesToggle { margin-top: 1rem; }\r\n<\/style>\r\n\r\n<div id=\"gir-tfi-app\">\r\n  <div class=\"card\" style=\"padding:1rem;\">\r\n    <div class=\"top-header\">\r\n      <div><\/div>\r\n      <div style=\"text-align:right;\">\r\n        <label for=\"wt\" style=\"display:inline-block; margin-right:5px;\">Weight (kg)<\/label>\r\n        <input id=\"wt\" type=\"number\" min=\"0\" step=\"0.001\" placeholder=\"e.g. 2.8\" style=\"max-width:100px; display:inline-block;\">\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div id=\"rows\"><\/div>\r\n\r\n    <div class=\"stack\" style=\"padding-top: 1rem;\">\r\n      <div style=\"float:left\">\r\n        <button id=\"addRow\" class=\"btn\">\u2795 Add row<\/button>\r\n      <\/div>\r\n      <div style=\"float:right\">\r\n        <button id=\"resetAll\" class=\"btn\">\u21ba Reset<\/button>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"card\" style=\"padding:1rem;\">\r\n    <div class=\"out\">\r\n      <div class=\"kpi\">\r\n        <h3>TFI<\/h3>\r\n        <div class=\"val\"><span id=\"totMlKgDay\">\u2014<\/span><\/div>\r\n        <div class=\"muted\"><span id=\"totMlDay\">0<\/span> mL\/day<\/div>\r\n      <\/div>\r\n      <div class=\"kpi\">\r\n        <h3>GIR<\/h3>\r\n        <div class=\"val\"><span id=\"girOverall\">\u2014<\/span><\/div>\r\n        <div class=\"muted\">mg\/kg\/min<\/div>\r\n      <\/div>\r\n      <div class=\"kpi\">\r\n        <h3>Calories<\/h3>\r\n        <div class=\"val\"><span id=\"kcalKgDay\">\u2014<\/span><\/div>\r\n        <div class=\"muted\"><span id=\"kcalDay\">0<\/span> kcal\/day<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div id=\"notesToggle\">\r\n    <button class=\"btn\" id=\"toggleNotesBtn\">Notes & formulas<\/button>\r\n    <div id=\"notesBox\" class=\"muted\">\r\n      <ul>\r\n        <li><b>Default sugar:<\/b> D10 = 10g\/100mL. Formulas ~7.1g to 8.5g.<\/li>\r\n        <li><b>Default energy:<\/b> Dextrose = g \u00d7 3.4. Formulas = 67-80 kcal\/100mL.<\/li>\r\n        <li><b>GIR (mg\/kg\/min)<\/b> = Total Glucose mg\/hr \u00f7 (Wt \u00d7 60).<\/li>\r\n        <li><b>TFI (mL\/kg\/day)<\/b> = Total mL\/day \u00f7 Wt.<\/li>\r\n      <\/ul>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<script type=\"text\/javascript\">\r\n(function (){\r\n  var presets = {\r\n    \"D10 (IV dextrose)\":{glu: 10, kcal: null},\r\n    \"D12.5 (IV dextrose)\":{glu: 12.5, kcal: null},\r\n    \"D20 (IV dextrose)\":{glu: 20, kcal: null},\r\n    \"Normal formula\":{glu: 7.1, kcal: 67},\r\n    \"Preterm formula\":{glu: 8.5, kcal: 80},\r\n    \"Custom\":{glu: \"\", kcal: \"\"}\r\n  };\r\n\r\n  var modes = [\r\n    {val: \"continuous\", label: \"Continuous (mL\/hr)\"},\r\n    {val: \"q2\", label: \"q2h (mL\/feed)\"},\r\n    {val: \"q3\", label: \"q3h (mL\/feed)\"},\r\n    {val: \"q4\", label: \"q4h (mL\/feed)\"}\r\n  ];\r\n\r\n  var rowsEl = document.getElementById(\"rows\");\r\n  var addBtn = document.getElementById(\"addRow\");\r\n  var resetBtn = document.getElementById(\"resetAll\");\r\n  var wtEl = document.getElementById(\"wt\");\r\n\r\n  var outMlDay = document.getElementById(\"totMlDay\");\r\n  var outMlKgDay = document.getElementById(\"totMlKgDay\");\r\n  var outGIR = document.getElementById(\"girOverall\");\r\n  var outKcalDay = document.getElementById(\"kcalDay\");\r\n  var outKcalKgDay = document.getElementById(\"kcalKgDay\");\r\n  var notesBox = document.getElementById(\"notesBox\");\r\n  var toggleBtn = document.getElementById(\"toggleNotesBtn\");\r\n\r\n  function buildPresetOptions(){\r\n    var html = \"\";\r\n    for (var k in presets){\r\n      if (presets.hasOwnProperty(k)){ html += '<option value=\"' + k + '\">' + k + \"<\/option>\"; }\r\n    }\r\n    return html;\r\n  }\r\n\r\n  function buildModeOptions(){\r\n    var html = \"\";\r\n    for (var i = 0; i < modes.length; i++){\r\n      html += '<option value=\"' + modes[i].val + '\">' + modes[i].label + \"<\/option>\";\r\n    }\r\n    return html;\r\n  }\r\n\r\n  function makeRow(){\r\n    var row = document.createElement(\"div\");\r\n    row.className = \"row\";\r\n    \r\n    var innerHTML = \r\n      '<div class=\"row-inner\">' +\r\n        '<div class=\"cell w-type\">' +\r\n          \"<label>Type<\/label>\" +\r\n          '<select class=\"type\">' + buildPresetOptions() + \"<\/select>\" +\r\n        \"<\/div>\" +\r\n        '<div class=\"cell w-mid\">' +\r\n          \"<label>Glu (g%)<\/label>\" +\r\n          '<input class=\"glu\" type=\"number\" min=\"0\" step=\"0.1\" placeholder=\"10\">' +\r\n        \"<\/div>\" +\r\n        '<div class=\"cell w-mid\">' +\r\n          \"<label>Kcal\/dL<\/label>\" +\r\n          '<input class=\"kcal\" type=\"number\" min=\"0\" step=\"0.1\" placeholder=\"auto\">' +\r\n        \"<\/div>\" +\r\n        '<div class=\"cell w-mid\">' +\r\n          \"<label>Mode<\/label>\" +\r\n          '<select class=\"mode\">' + buildModeOptions() + \"<\/select>\" +\r\n        \"<\/div>\" +\r\n        '<div class=\"cell w-mid\">' +\r\n          '<label class=\"amt-label\">Amount<\/label>' +\r\n          '<input class=\"amt\" type=\"number\" min=\"0\" step=\"0.1\" placeholder=\"e.g. 6\">' +\r\n        \"<\/div>\" +\r\n        '<div class=\"cell w-mid\">' +\r\n          \"<label>Flow (mL\/hr)<\/label>\" +\r\n          '<input class=\"avg\" type=\"number\" step=\"0.01\" disabled=\"disabled\">' +\r\n        \"<\/div>\" +\r\n        '<div class=\"cell w-del\">' +\r\n          '<label>&nbsp;<\/label>' +\r\n          '<button class=\"btn danger del\" title=\"Remove\">\u2716<\/button>' +\r\n        \"<\/div>\" +\r\n      '<\/div>' + \r\n      '<div class=\"row-stats\">' +\r\n        '<span><strong>Fluid:<\/strong> <span class=\"stat-fluid\">\u2014<\/span><\/span>' +\r\n        '<span><strong>GIR:<\/strong> <span class=\"stat-gir\">\u2014<\/span><\/span>' +\r\n      '<\/div>';\r\n\r\n    row.innerHTML = innerHTML;\r\n\r\n    var typeSel = row.getElementsByClassName(\"type\")[0];\r\n    var gluIn = row.getElementsByClassName(\"glu\")[0];\r\n    var kcalIn = row.getElementsByClassName(\"kcal\")[0];\r\n    var modeSel = row.getElementsByClassName(\"mode\")[0];\r\n    var amtLabel = row.getElementsByClassName(\"amt-label\")[0];\r\n    var amtIn = row.getElementsByClassName(\"amt\")[0];\r\n    var avgIn = row.getElementsByClassName(\"avg\")[0];\r\n    var delBtn = row.getElementsByClassName(\"del\")[0];\r\n    var statFluid = row.getElementsByClassName(\"stat-fluid\")[0];\r\n    var statGir = row.getElementsByClassName(\"stat-gir\")[0];\r\n\r\n    function setPreset(){\r\n      var key = typeSel.value;\r\n      var preset = presets[key];\r\n      if (preset.glu === \"\"){ gluIn.value = \"\"; gluIn.placeholder = \"g%\"; }\r\n      else { gluIn.value = preset.glu; }\r\n      \r\n      if (key.indexOf(\"IV dextrose\") !== -1){\r\n        var g = parseFloat(gluIn.value || 0);\r\n        kcalIn.value = g ? (g * 3.4).toFixed(1) : \"\";\r\n        kcalIn.placeholder = \"auto\";\r\n      } else if (preset.kcal === \"\"){\r\n        kcalIn.value = \"\"; kcalIn.placeholder = \"kcal\";\r\n      } else {\r\n        kcalIn.value = preset.kcal;\r\n      }\r\n      recalc();\r\n    }\r\n\r\n    function applyModeUI(){\r\n      var m = modeSel.value;\r\n      if (m === \"continuous\"){ amtLabel.innerHTML = \"mL\/hr\"; amtIn.placeholder = \"e.g. 6\"; }\r\n      else { amtLabel.innerHTML = \"mL\/feed\"; amtIn.placeholder = \"e.g. 18\"; }\r\n      recalc();\r\n    }\r\n\r\n    function avgMlHr(){\r\n      var m = modeSel.value;\r\n      var amt = parseFloat(amtIn.value || 0);\r\n      if (!amt || amt < 0) return 0;\r\n      if (m === \"continuous\") return amt;\r\n      if (m === \"q2\") return amt \/ 2;\r\n      if (m === \"q3\") return amt \/ 3;\r\n      if (m === \"q4\") return amt \/ 4;\r\n      return 0;\r\n    }\r\n\r\n    function recalc(){\r\n      var key = typeSel.value;\r\n      if (key.indexOf(\"IV dextrose\") !== -1){\r\n        var g = parseFloat(gluIn.value || 0);\r\n        kcalIn.value = g ? (g * 3.4).toFixed(1) : \"\";\r\n      }\r\n      var avg = avgMlHr();\r\n      avgIn.value = avg ? avg.toFixed(2) : \"\";\r\n      \r\n      var wt = parseFloat(wtEl.value);\r\n      var glu = parseFloat(gluIn.value || 0);\r\n      \r\n      if (wt && wt > 0 && avg > 0){\r\n        var dailyVol = avg * 24;\r\n        statFluid.innerHTML = (dailyVol \/ wt).toFixed(1) + \" mL\/kg\";\r\n        var mgHr = avg * (glu * 10);\r\n        var gir = mgHr \/ (wt * 60);\r\n        statGir.innerHTML = gir.toFixed(2);\r\n      } else {\r\n        statFluid.innerHTML = \"\u2014\";\r\n        statGir.innerHTML = \"\u2014\";\r\n      }\r\n      computeTotals();\r\n    }\r\n\r\n    typeSel.onchange = setPreset;\r\n    modeSel.onchange = applyModeUI;\r\n    gluIn.oninput = recalc;\r\n    kcalIn.oninput = recalc;\r\n    amtIn.oninput = recalc;\r\n\r\n    delBtn.onclick = function (){\r\n      if (row.parentNode) row.parentNode.removeChild(row);\r\n      computeTotals();\r\n    };\r\n\r\n    setPreset();\r\n    applyModeUI();\r\n    row.recalc = recalc;\r\n    return row;\r\n  }\r\n\r\n  function computeTotals(){\r\n    var wt = parseFloat(wtEl.value);\r\n    var totalMlHr = 0;\r\n    var totalMgHr = 0;\r\n    var totalKcalDay = 0;\r\n\r\n    var rows = rowsEl.getElementsByClassName(\"row\");\r\n    for (var i = 0; i < rows.length; i++){\r\n      var r = rows[i];\r\n      var glu = parseFloat(r.getElementsByClassName(\"glu\")[0].value || 0);\r\n      var kcal100 = parseFloat(r.getElementsByClassName(\"kcal\")[0].value || 0);\r\n      var avg = parseFloat(r.getElementsByClassName(\"avg\")[0].value || 0);\r\n\r\n      var mgPerMl = glu * 10;\r\n      var mgHr = avg * mgPerMl;\r\n      totalMgHr += mgHr;\r\n\r\n      var kcalPerMl = kcal100 \/ 100;\r\n      var kcalDay = avg * kcalPerMl * 24;\r\n      totalKcalDay += kcalDay;\r\n      totalMlHr += avg;\r\n    }\r\n\r\n    var mlDay = totalMlHr * 24;\r\n    outMlDay.innerHTML = mlDay.toFixed(1);\r\n\r\n    if (wt && wt > 0){\r\n      var mlKgDay = mlDay \/ wt;\r\n      outMlKgDay.innerHTML = mlKgDay.toFixed(1) + \" mL\/kg\/day\";\r\n      var gir = totalMgHr \/ (wt * 60);\r\n      outGIR.innerHTML = isFinite(gir) ? gir.toFixed(2) : \"\u2014\";\r\n      var kcalKgDay = totalKcalDay \/ wt;\r\n      outKcalKgDay.innerHTML = isFinite(kcalKgDay) ? kcalKgDay.toFixed(1) + \" kcal\/kg\/day\" : \"\u2014\";\r\n    } else {\r\n      outMlKgDay.innerHTML = \"\u2014\";\r\n      outGIR.innerHTML = \"\u2014\";\r\n      outKcalKgDay.innerHTML = \"\u2014\";\r\n    }\r\n    outKcalDay.innerHTML = totalKcalDay.toFixed(0);\r\n  }\r\n\r\n  function addDefaultRows(){\r\n    var r1 = makeRow();\r\n    r1.getElementsByClassName(\"type\")[0].value = \"D10 (IV dextrose)\";\r\n    r1.getElementsByClassName(\"type\")[0].onchange(); \r\n    rowsEl.appendChild(r1);\r\n\r\n    var r2 = makeRow();\r\n    r2.getElementsByClassName(\"type\")[0].value = \"Normal formula\";\r\n    r2.getElementsByClassName(\"type\")[0].onchange();\r\n    r2.getElementsByClassName(\"mode\")[0].value = \"q3\";\r\n    r2.getElementsByClassName(\"mode\")[0].onchange();\r\n    rowsEl.appendChild(r2);\r\n  }\r\n\r\n  addBtn.onclick = function (){ rowsEl.appendChild(makeRow()); computeTotals(); };\r\n\r\n  resetBtn.onclick = function (){\r\n    rowsEl.innerHTML = \"\";\r\n    wtEl.value = \"\";\r\n    addDefaultRows();\r\n    computeTotals();\r\n  };\r\n\r\n  wtEl.oninput = function(){\r\n    var rows = rowsEl.getElementsByClassName(\"row\");\r\n    for(var i=0; i<rows.length; i++){ if(rows[i].recalc) rows[i].recalc(); }\r\n    computeTotals();\r\n  };\r\n\r\n  toggleBtn.onclick = function (){\r\n    notesBox.style.display = (notesBox.style.display === \"none\" || notesBox.style.display === \"\") ? \"block\" : \"none\";\r\n  };\r\n\r\n  addDefaultRows();\r\n  computeTotals();\r\n})();\r\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Fluid Calculator<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-full.php","meta":{"footnotes":""},"tags":[],"class_list":["post-671","page","type-page","status-publish","article"],"_links":{"self":[{"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages\/671","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tomchan.hk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=671"}],"version-history":[{"count":3,"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages\/671\/revisions"}],"predecessor-version":[{"id":676,"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages\/671\/revisions\/676"}],"wp:attachment":[{"href":"https:\/\/tomchan.hk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=671"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tomchan.hk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=671"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}