{"id":530,"date":"2025-09-10T00:15:48","date_gmt":"2025-09-10T00:15:48","guid":{"rendered":"https:\/\/tomchan.hk\/?page_id=530"},"modified":"2025-09-10T12:55:13","modified_gmt":"2025-09-10T12:55:13","slug":"uvc-length","status":"publish","type":"page","link":"https:\/\/tomchan.hk\/?page_id=530","title":{"rendered":"UVC Length Calculator"},"content":{"rendered":"\n<div id=\"uvc-tool\" style=\"max-width:820px;margin:1rem auto;padding:1rem;border:1px solid #e5e7eb;border-radius:14px;font-family:system-ui,Segoe UI,Arial,Helvetica,sans-serif\">\n  <h2 style=\"margin:.25rem 0 1rem\">UVC Length Estimator<\/h2>\n\n  <div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px\">\n    <label>Birth weight (kg)\n      <input id=\"bw\" type=\"number\" step=\"0.01\" min=\"0\" placeholder=\"e.g., 2.8\" style=\"width:100%;padding:.6rem;border:1px solid #ddd;border-radius:10px\">\n    <\/label>\n    <label>Shoulder\u2013umbilicus (cm)\n      <input id=\"su\" type=\"number\" step=\"0.1\" min=\"0\" placeholder=\"e.g., 12.5\" style=\"width:100%;padding:.6rem;border:1px solid #ddd;border-radius:10px\">\n    <\/label>\n  <\/div>\n\n  <div style=\"position:relative\">\n    <canvas id=\"nomogram\" width=\"820\" height=\"420\" style=\"margin-top:10px;width:100%;height:auto\"><\/canvas>\n    <div id=\"mouseLabel\" style=\"position:absolute; pointer-events:none; background:rgba(255,255,255,0.95); border:1px solid #111; border-radius:8px; padding:4px 8px; font:12px system-ui,Arial; display:none;\"><\/div>\n  <\/div>\n\n  <div id=\"results\" style=\"margin-top:15px\"><\/div>\n\n  <details style=\"margin-top:12px\">\n    <summary>Methods &#038; sources<\/summary>\n    <ul style=\"margin:.5rem 1.2rem\">\n      <li><b>Shukla &amp; Ferrara:<\/b> UVC = \u00bd(3\u00d7BW + 9) + 1 cm. (BW in kg.)<\/li>\n      <li><b>Shukla (Modified):<\/b> UVC = \u00bd(3\u00d7BW + 9) cm.<\/li>\n      <li><b>Dunn (nomogram using S\u2013U length):<\/b> Atrium y = 0.79x \u2212 0.61; Diaphragm y = 0.63x \u2212 0.53 (x = S\u2013U cm). Based on Dunn\u2019s Fig. 3:contentReference[oaicite:0]{index=0}.<\/li>\n    <\/ul>\n  <\/details>\n<\/div>\n\n<script>\n(function(){\n  const $ = id => document.getElementById(id);\n  const bwEl = $(\"bw\"), suEl = $(\"su\"), res = $(\"results\");\n  const canvas = $(\"nomogram\");\n  const ctx = canvas.getContext(\"2d\");\n  const mouseLabel = $(\"mouseLabel\");\n\n  \/\/ ===== Equations =====\n  const shuklaFerrara = bw => (bw ? 0.5*(3*bw + 9) + 1 : null);  \n  const shuklaModified = bw => (bw ? 0.5*(3*bw + 9)     : null);  \n  const dunnAtrium     = su => (su ? 0.79*su - 0.61     : null);  \n  const dunnDiaphragm  = su => (su ? 0.63*su - 0.53     : null);  \n\n  \/\/ ===== Plot geometry & scales =====\n  const xMin=8, xMax=18, yMin=4, yMax=14;\n  const M = {left:70, right:20, top:20, bottom:50};\n  function plotW(){ return canvas.width - M.left - M.right; }\n  function plotH(){ return canvas.height - M.top - M.bottom; }\n  function xToPx(x){ return M.left + ( (x - xMin) \/ (xMax - xMin) ) * plotW(); }\n  function yToPx(y){ return M.top  + ( (yMax - y) \/ (yMax - yMin) ) * plotH(); }\n  function pxToX(px){ return xMin + ( (px - M.left) \/ plotW() ) * (xMax - xMin); }\n\n  \/\/ ===== Drawing helpers =====\n  function clear(){ ctx.clearRect(0,0,canvas.width,canvas.height); }\n\n  function drawGrid(){\n    ctx.save();\n    ctx.strokeStyle = \"#ccc\";\n    ctx.lineWidth = 1;\n    \/\/ vertical lines\n    for(let x = xMin; x <= xMax; x+=1){\n      const px = xToPx(x);\n      ctx.beginPath(); ctx.moveTo(px, M.top); ctx.lineTo(px, M.top+plotH()); ctx.stroke();\n    }\n    \/\/ horizontal lines\n    for(let y = yMin; y <= yMax; y+=1){\n      const py = yToPx(y);\n      ctx.beginPath(); ctx.moveTo(M.left, py); ctx.lineTo(M.left+plotW(), py); ctx.stroke();\n    }\n    ctx.restore();\n  }\n\n  function drawAxes(){\n    ctx.save();\n    ctx.strokeStyle = \"#111\"; ctx.lineWidth = 1.5;\n    ctx.strokeRect(M.left, M.top, plotW(), plotH());\n    ctx.fillStyle = \"#111\"; ctx.font = \"12px system-ui, Arial\";\n\n    for(let x = Math.ceil(xMin); x <= xMax; x+=1){\n      const px = xToPx(x);\n      ctx.beginPath(); ctx.moveTo(px, yToPx(yMin)); ctx.lineTo(px, yToPx(yMin)+6); ctx.stroke();\n      ctx.textAlign = \"center\"; ctx.fillText(String(x), px, yToPx(yMin)+20);\n    }\n    for(let y = Math.ceil(yMin); y <= yMax; y+=1){\n      const py = yToPx(y);\n      ctx.beginPath(); ctx.moveTo(xToPx(xMin), py); ctx.lineTo(xToPx(xMin)-6, py); ctx.stroke();\n      ctx.textAlign = \"right\"; ctx.fillText(String(y), xToPx(xMin)-10, py+4);\n    }\n\n    ctx.textAlign = \"center\";\n    ctx.fillText(\"Shoulder\u2013Umbilicus (cm)\", M.left + plotW()\/2, canvas.height - 10);\n\n    ctx.save();\n    ctx.translate(15, M.top + plotH()\/2);\n    ctx.rotate(-Math.PI\/2);\n    ctx.textAlign = \"center\";\n    ctx.fillText(\"UVC length (cm)\", 0, 0);\n    ctx.restore();\n    ctx.restore();\n  }\n\n  function drawDashedLine(m, b, color){\n    let x1 = xMin, y1 = m*x1 + b;\n    let x2 = xMax, y2 = m*x2 + b;\n    if(y1 < yMin){ x1 = (yMin - b)\/m; y1 = yMin; }\n    if(y1 > yMax){ x1 = (yMax - b)\/m; y1 = yMax; }\n    if(y2 < yMin){ x2 = (yMin - b)\/m; y2 = yMin; }\n    if(y2 > yMax){ x2 = (yMax - b)\/m; y2 = yMax; }\n\n    ctx.save();\n    ctx.strokeStyle = color; ctx.lineWidth = 1; ctx.setLineDash([6,6]);\n    ctx.beginPath(); ctx.moveTo(xToPx(x1), yToPx(y1)); ctx.lineTo(xToPx(x2), yToPx(y2)); ctx.stroke();\n    ctx.restore();\n  }\n\n  function drawX(px, py, size=10, width=3, color=\"#000\"){\n    ctx.save(); ctx.strokeStyle=color; ctx.lineWidth=width;\n    ctx.beginPath();\n    ctx.moveTo(px-size, py-size); ctx.lineTo(px+size, py+size);\n    ctx.moveTo(px-size, py+size); ctx.lineTo(px+size, py-size);\n    ctx.stroke(); ctx.restore();\n  }\n\n  function drawPatientMarkers(su){\n    if(!su || isNaN(su)) return;\n    const ya = dunnAtrium(su), yd = dunnDiaphragm(su);\n    if(ya!=null){ const px=xToPx(su), py=yToPx(ya); drawX(px,py); ctx.fillText(ya.toFixed(2)+\" cm\", px+12, py-8); }\n    if(yd!=null){ const px=xToPx(su), py=yToPx(yd); drawX(px,py); ctx.fillText(yd.toFixed(2)+\" cm\", px+12, py-8); }\n  }\n\n  function drawLegend(){\n    const y0 = M.top+10, x0 = M.left+10;\n    ctx.save(); ctx.setLineDash([6,6]); ctx.lineWidth=1;\n    ctx.strokeStyle=\"#2563eb\"; ctx.beginPath(); ctx.moveTo(x0,y0); ctx.lineTo(x0+30,y0); ctx.stroke();\n    ctx.setLineDash([]); ctx.fillStyle=\"#111\"; ctx.fillText(\"Dunn \u2014 Atrium\", x0+38,y0+4);\n    ctx.setLineDash([6,6]); ctx.strokeStyle=\"#16a34a\"; ctx.beginPath(); ctx.moveTo(x0+150,y0); ctx.lineTo(x0+180,y0); ctx.stroke();\n    ctx.setLineDash([]); ctx.fillStyle=\"#111\"; ctx.fillText(\"Dunn \u2014 Diaphragm\", x0+188,y0+4);\n    ctx.restore();\n  }\n\n  function drawCrosshair(mousePx){\n    if(!mousePx) return;\n    const {x,y} = mousePx;\n    if(x < M.left || x > M.left+plotW() || y < M.top || y > M.top+plotH()){ mouseLabel.style.display=\"none\"; return; }\n    let xVal = pxToX(x); xVal = Math.round(xVal*2)\/2; \n    const xPx = xToPx(xVal);\n\n    ctx.save(); ctx.strokeStyle=\"#111\"; ctx.lineWidth=1;\n    ctx.beginPath(); ctx.moveTo(xPx,M.top); ctx.lineTo(xPx,M.top+plotH()); ctx.stroke();\n    ctx.beginPath(); ctx.moveTo(M.left,y); ctx.lineTo(M.left+plotW(),y); ctx.stroke(); ctx.restore();\n\n    const yAtr=Math.max(Math.min(0.79*xVal-0.61,yMax),yMin);\n    const yDia=Math.max(Math.min(0.63*xVal-0.53,yMax),yMin);\n    const label=`x=${xVal.toFixed(2)} cm | Atrium y=${yAtr.toFixed(2)} cm \u00b7 Diaphragm y=${yDia.toFixed(2)} cm`;\n    mouseLabel.textContent=label; mouseLabel.style.display=\"block\";\n    mouseLabel.style.left=(xPx+10)+\"px\"; mouseLabel.style.top=(y-30)+\"px\";\n  }\n\n  function drawAll(mousePx=null){\n    clear(); drawGrid(); drawAxes(); drawLegend();\n    drawDashedLine(0.79,-0.61,\"#2563eb\"); drawDashedLine(0.63,-0.53,\"#16a34a\");\n    const su=parseFloat(suEl.value); drawPatientMarkers(su);\n    drawCrosshair(mousePx);\n  }\n\n  function fmt(v){ return (v==null||isNaN(v)) ? \"\u2014\" : v.toFixed(2)+\" cm\"; }\n  function updateOutputs(){\n    const bw=parseFloat(bwEl.value), su=parseFloat(suEl.value);\n    res.innerHTML=`<table style=\"width:100%;border-collapse:collapse\">\n      <thead><tr>\n        <th style=\"text-align:left;border-bottom:1px solid #e5e7eb;padding:.4rem\">Method<\/th>\n        <th style=\"text-align:left;border-bottom:1px solid #e5e7eb;padding:.4rem\">UVC length<\/th>\n        <th style=\"text-align:left;border-bottom:1px solid #e5e7eb;padding:.4rem\">Inputs used<\/th>\n      <\/tr><\/thead>\n      <tbody>\n        <tr><td>Shukla &amp; Ferrara<\/td><td>${fmt(shuklaFerrara(bw))}<\/td><td>Birth weight<\/td><\/tr>\n        <tr><td>Shukla (Modified)<\/td><td>${fmt(shuklaModified(bw))}<\/td><td>Birth weight<\/td><\/tr>\n        <tr><td>Dunn \u2014 Atrium<\/td><td>${fmt(dunnAtrium(su))}<\/td><td>S\u2013U length<\/td><\/tr>\n        <tr><td>Dunn \u2014 Diaphragm<\/td><td>${fmt(dunnDiaphragm(su))}<\/td><td>S\u2013U length<\/td><\/tr>\n      <\/tbody><\/table>`;\n  }\n\n  function onInput(){ updateOutputs(); drawAll(); }\n  bwEl.addEventListener('input', onInput); suEl.addEventListener('input', onInput);\n\n  let lastMousePx=null;\n  canvas.addEventListener('mousemove',e=>{\n    const rect=canvas.getBoundingClientRect(), scaleX=canvas.width\/rect.width, scaleY=canvas.height\/rect.height;\n    lastMousePx={x:(e.clientX-rect.left)*scaleX,y:(e.clientY-rect.top)*scaleY}; drawAll(lastMousePx);\n  });\n  canvas.addEventListener('mouseleave',()=>{ mouseLabel.style.display=\"none\"; lastMousePx=null; drawAll(); });\n\n  updateOutputs(); drawAll();\n})();\n<\/script>\n\n","protected":false},"excerpt":{"rendered":"<p>UVC Length Estimator Birth weight (kg) Shoulder\u2013umbilicus (cm) Methods &#038; sources Shukla &amp; Ferrara: UVC = \u00bd(3\u00d7BW + 9) + 1 cm. (BW in kg.) Shukla (Modified): UVC = \u00bd(3\u00d7BW + 9) cm. Dunn (nomogram using S\u2013U length): Atrium y = 0.79x \u2212 0.61; Diaphragm y = 0.63x \u2212 0.53 (x = S\u2013U cm). Based&#8230;<\/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-530","page","type-page","status-publish","article"],"_links":{"self":[{"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages\/530","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=530"}],"version-history":[{"count":13,"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages\/530\/revisions"}],"predecessor-version":[{"id":548,"href":"https:\/\/tomchan.hk\/index.php?rest_route=\/wp\/v2\/pages\/530\/revisions\/548"}],"wp:attachment":[{"href":"https:\/\/tomchan.hk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=530"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tomchan.hk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}