The gap in a reciprocal graph
HTML for this example
Select the code and use your copy shortcut. Changes in this preview are temporary.
<!doctype html><html lang="en-US"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>The gap in a reciprocal graph</title><style>*{box-sizing:border-box} :root{color-scheme:light;--ink:#20303b;--muted:#536570;--line:#d3dce1;--accent:#245c76;--paper:#fff;--soft:#edf3f6}body{margin:0;background:#f3f5f5;color:var(--ink);font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{max-width:1080px;margin:auto;padding:30px 32px 64px}header{margin-bottom:20px}h1{font-size:clamp(1.5rem,3vw,2.15rem);line-height:1.18;letter-spacing:-.035em;margin:0 0 8px}h2{font-size:1.22rem;line-height:1.3;margin:0 0 16px}h3{font-size:1rem;margin:0 0 8px}p{margin:8px 0 16px}small,.muted{color:var(--muted)}.eyebrow{font-size:.76rem;letter-spacing:.13em;text-transform:uppercase;font-weight:750;color:var(--accent);margin-bottom:8px}.panel{background:var(--paper);border:1px solid var(--line);padding:24px;border-radius:16px}.grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:24px}.stack{display:grid;gap:18px}.fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}label{display:block;font-size:.9rem;font-weight:650}input,select,textarea,button{font:inherit}input,select,textarea{display:block;width:100%;min-width:0;margin-top:6px;border:1px solid #8b9ca6;border-radius:7px;padding:10px 12px;background:white;color:var(--ink)}input,select{min-height:46px}textarea{resize:vertical}button{border:1px solid var(--accent);border-radius:7px;padding:10px 16px;min-height:44px;background:var(--accent);color:white;cursor:pointer;font-weight:650}button.secondary{background:white;color:var(--accent)}button:hover{filter:brightness(.94)}:focus-visible{outline:3px solid #d06e1c;outline-offset:3px}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:18px}.answer{background:var(--ink);color:white;padding:26px;border-radius:14px}.answer .muted{color:#d9e5eb}.big{font-size:clamp(2.1rem,5vw,3.8rem);font-weight:750;line-height:1.16;letter-spacing:-.045em;margin:8px 0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.subresult{font-size:1.2rem;font-weight:650} .formula{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;overflow-wrap:anywhere}.note{border-left:3px solid #b47029;padding:10px 14px;background:#fff5e5;margin:14px 0;color:#66451b}.error{color:#a22621;font-weight:650;min-height:24px;margin:8px 0}.below{margin-top:28px}table{border-collapse:collapse;width:100%;font-size:.94rem}th{text-align:left;color:var(--muted);font-weight:650;font-size:.84rem}th,td{padding:11px 10px;border-bottom:1px solid var(--line);vertical-align:top}th:first-child,td:first-child{padding-left:0}th:last-child,td:last-child{padding-right:0}details{border-top:1px solid var(--line);padding:16px 0}summary{cursor:pointer;font-weight:650}svg{display:block;width:100%;height:auto}.tag{display:inline-block;font-size:.78rem;font-weight:650;padding:3px 8px;border-radius:30px;background:var(--soft);color:var(--accent)}.rule{height:1px;background:var(--line);margin:20px 0}.checklabel{display:flex;gap:10px;align-items:flex-start;font-weight:500}.checklabel input{width:20px;min-height:20px;flex:none;margin:2px 0}pre{white-space:pre-wrap;word-break:break-word;font: .86rem/1.6 ui-monospace,Consolas,monospace;background:#edf1f3;padding:20px;border-radius:8px}a{color:var(--accent)}[hidden]{display:none!important}@media(max-width:720px){main{padding:22px 20px 40px}.grid{grid-template-columns:1fr;gap:18px}.panel{padding:20px}.answer{padding:22px}.big{font-size:2.65rem}}@media(max-width:400px){main{padding:18px 16px 36px}.fields{gap:12px}th,td{padding:9px 6px}.panel{padding:16px}.big{font-size:2.25rem}}@media print{body{background:white}main{max-width:none;padding:0}.actions,button{display:none}.panel{break-inside:avoid}details>*{display:block}}.graph-heading{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;align-items:center;margin-bottom:10px}.graph-heading h2{margin:0}#graph svg{max-height:390px}@media(max-width:400px){#graph{margin:0 -8px}.graph-heading .tag{font-size:.75rem}}@media(max-width:400px){#graph text{font-size:24px}}</style></head><body><main><header><div class="eyebrow">f(x) = 1 / (x − a)</div><h1>The gap in a reciprocal graph</h1></header>
<p>Explore two branches without drawing a bridge across the excluded input.</p>
<section class="panel"><div class="graph-heading"><h2 id="formula">f(x) = 1 / (x − 1)</h2><span class="tag" id="excluded">x = 1 is excluded</span></div><div id="graph" aria-live="polite"></div><p class="muted" style="margin-bottom:0">Viewing window: x [−5, 5], y [−5, 5]. Full domain: all real x except a.</p></section>
<section class="below grid"><div class="panel"><div class="fields"><label for="a">Parameter a (−2 to 2)<input id="a" inputmode="decimal" value="1" ></label><label for="probe">Probe x (−5 to 5)<input id="probe" inputmode="decimal" value="0" ></label></div><div class="actions"><button type="button" id="calculate">Update graph</button><button type="button" id="shift" class="secondary">Set a = −1</button><button type="button" id="reset" class="secondary">Reset</button></div><p id="probeResult" class="subresult" aria-live="polite"></p><p id="error" class="error" role="status"></p></div><div class="panel"><h2>Exact checkpoints</h2><table><thead><tr><th>x</th><th>x − a</th><th>f(x)</th></tr></thead><tbody id="points"></tbody></table></div></section>
<details class="below"><summary>Read the guides and clipped edges</summary><p>The dashed orange line is the excluded-input asymptote, not the curve. Blue branches stay on separate sides. y = 0 is a guide; this function never equals zero. A clipped edge is not a mathematical endpoint. At a = 1, x = 1.1 is defined with f(x) = 10, above the viewing window.</p><p>Use finite decimal a in [−2, 2] and probe x in [−5, 5]. A blank probe means no probe; it does not mean x = 0. Invalid inputs clear the current view. The table is a checkpoint, not a proof of limiting behavior. No arbitrary-expression parser is included. Local entries are not saved.</p></details></main><script>
const $=id=>document.getElementById(id);const put=(id,text)=>{$(id).textContent=text};const fmt=(x,n=6)=>{if(!Number.isFinite(x))throw Error('Result exceeds the numeric range.');let v=(Math.round(Math.abs(x)*10**n)/10**n)*(x<0?-1:1);return Object.is(v,-0)?'0':v.toFixed(n).replace(/\.?0+$/,'')||'0'};const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
function decimal(s,{max=1000000,signed=false,places=6}={}){s=String(s).trim();if(!s)throw Error('Enter a value; a blank field is not zero.');const r=new RegExp('^'+(signed?'[+-]?':'')+'(?:[0-9]+(?:\\.[0-9]{1,'+places+'})?|\\.[0-9]{1,'+places+'})$');if(!r.test(s))throw Error('Use a '+(signed?'signed':'nonnegative')+' US decimal with up to '+places+' decimal places; no commas or exponents.');const v=Number(s);if(!Number.isFinite(v)||Math.abs(v)>max)throw Error('Enter a value within '+(signed?'-':'0 to ')+max+'.');return v;}
function scaled(s){decimal(s);const [a,b='']=String(s).trim().split('.');return BigInt(a||'0')*1000000n+BigInt(b.padEnd(6,'0'));}
function rational(n,d,places=6){if(d===0n)throw Error('Zero denominator');let neg=(n<0n)!=(d<0n);n=n<0n?-n:n;d=d<0n?-d:d;const scale=10n**BigInt(places),v=n*scale,q=v/d,r=v%d;let rounded=q+(r*2n>=d?1n:0n);let s=(rounded/scale).toString();const f=(rounded%scale).toString().padStart(places,'0').replace(/0+$/,'');if(f)s+='.'+f;return {text:(neg&&rounded!==0n?'-':'')+s,approx:r!==0n};}
function bind(ids,fn){ids.forEach(id=>{ $(id).addEventListener('input',fn);$(id).addEventListener('change',fn); });}
function evaluate(a,x){if(x===a)return {state:'undefined',value:null};const value=1/(x-a);return {state:Math.abs(value)>5?'offscreen':'visible',value};}
function branches(a){return [[-5,a-.2],[a+.2,5]].map(([start,end])=>Array.from({length:241},(_,i)=>{const x=start+(end-start)*i/240;return [x,1/(x-a)];}));}
function chart(a,probe){const X=x=>48+(x+5)*48,Y=y=>20+(5-y)*30;let s='<svg viewBox="0 0 576 356" role="img" aria-label="Two separate reciprocal branches with excluded input at '+a+'"><defs><clipPath id="plotclip"><rect x="48" y="20" width="480" height="300"/></clipPath></defs>';for(let k=-5;k<=5;k++){s+='<path d="M'+X(k)+' 20V320M48 '+Y(k)+'H528" stroke="'+(k===0?'#91a4b0':'#e4eaf0')+'" stroke-width="'+(k===0?1.4:1)+'"/>';if(k%2===0)s+='<text x="'+X(k)+'" y="343" text-anchor="middle" font-size="13">'+k+'</text><text x="36" y="'+(Y(k)+4)+'" text-anchor="end" font-size="13">'+k+'</text>';}s+='<path d="M'+X(a)+' 20V320" stroke="#bd6a22" stroke-dasharray="6 5" stroke-width="2"/><text x="'+(X(a)+7)+'" y="37" font-size="13" fill="#8f4910">x = '+a+' · excluded</text><g clip-path="url(#plotclip)">';for(const pts of branches(a))s+='<path class="branch" d="'+pts.map(([x,y],i)=>(i?'L':'M')+X(x).toFixed(3)+' '+Y(y).toFixed(3)).join(' ')+'" fill="none" stroke="#245c76" stroke-width="3"/>';if(probe!==null&&evaluate(a,probe).state==='visible')s+='<circle cx="'+X(probe)+'" cy="'+Y(evaluate(a,probe).value)+'" r="5" fill="#a5482c"/>';return s+'</g><text x="546" y="177" font-size="14">x</text><text x="285" y="14" font-size="14">y</text></svg>';}
function update(){try{const a=decimal($('a').value,{signed:true,max:2}),probe=$('probe').value.trim()===''?null:decimal($('probe').value,{signed:true,max:5});put('formula','f(x) = 1 / (x − ('+a+'))');put('excluded','x = '+a+' is excluded');$('graph').innerHTML=chart(a,probe);$('points').innerHTML=[-1,-.5,0,.5,1].map(o=>'<tr><td>'+fmt(a+o)+'</td><td>'+o+'</td><td>'+(o===0?'Undefined':1/o)+'</td></tr>').join('');if(probe===null)put('probeResult','No probe supplied.');else{const r=evaluate(a,probe);put('probeResult',r.state==='undefined'?'x = '+probe+': Undefined; denominator is zero.':'f('+probe+') ≈ '+fmt(r.value,9)+' · '+(r.state==='visible'?'Defined and visible':'Defined but outside the viewing window'));}put('error','');}catch(e){$('graph').innerHTML='';$('points').innerHTML='';['formula','excluded','probeResult'].forEach(id=>put(id,''));put('error',e.message);}}
bind(['a','probe'],update);$('calculate').addEventListener('click',update);$('shift').addEventListener('click',()=>{$('a').value='-1';update()});$('reset').addEventListener('click',()=>{$('a').value='1';$('probe').value='';update()});globalThis.Tool={evaluate,branches,chart,update};update();
</script></body></html>