FunnLearn FREE ONLINE TOOLS Explore Tools →

Latest Insights

About Us

At funnlearn, we blend play with education to help kids grow confidently through creative resources and supportive tools.

Join Us

Dive into fun learning—get tips, resources, and tools all in one spot.
if(n!==0&&Math.abs(n)<0.000001){return n.toExponential(3);} return FMT?FMT.format(n):String(n); } function parseNum(raw){ var s=String(raw).replace(/[\s\u00a0]/g,''); if(s.charAt(s.length-1)==='%'){s=s.slice(0,-1);} if(s===''){return {empty:true};} var hasComma=s.indexOf(',')!==-1,hasDot=s.indexOf('.')!==-1; if(hasComma&&hasDot){ if(s.lastIndexOf(',')>s.lastIndexOf('.')){s=s.replace(/\./g,'').replace(',','.');} else{s=s.replace(/,/g,'');} }else if(hasComma){ if(/^[+-]?\d{1,3}(,\d{3})+$/.test(s)){s=s.replace(/,/g,'');} else{s=s.replace(',','.');} } if(!/^[+-]?(\d+\.?\d*|\.\d+)$/.test(s)){return {invalid:true};} var n=Number(s); if(!isFinite(n)){return {invalid:true};} return {value:n}; } var MINUS=' \u2212 ',TIMES=' \u00d7 ',DIV=' \u00f7 '; var CALCS={ percentOf:function(x,y){ var r=x/100*y; return {num:r,main:fmt(r),detail:fmt(x)+'% of '+fmt(y)+' = '+fmt(x)+DIV+'100'+TIMES+fmt(y)+' = '+fmt(r)}; }, whatPercent:function(x,y){ if(y===0){return {error:'Y cannot be zero, because dividing by zero is not possible.'};} var r=x/y*100; return {num:r,main:fmt(r)+'%',detail:fmt(x)+' is '+fmt(r)+'% of '+fmt(y)+'. Formula: '+fmt(x)+DIV+fmt(y)+TIMES+'100 = '+fmt(r)+'%'}; }, change:function(x,y){ if(x===0){return {error:'X (the starting value) cannot be zero, because a percentage change from zero is undefined.'};} var r=(y-x)/Math.abs(x)*100; var rc=clean(r); var word=rc>0?'an increase of ':'a decrease of '; var formula='Formula: ('+fmt(y)+MINUS+fmt(x)+')'+DIV+fmt(Math.abs(x))+TIMES+'100 = '+fmt(r)+'%'; if(rc===0){return {num:r,main:'0%',detail:'No change from '+fmt(x)+' to '+fmt(y)+'. '+formula};} return {num:r,main:(rc>0?'+':'')+fmt(r)+'%',detail:'From '+fmt(x)+' to '+fmt(y)+' is '+word+fmt(Math.abs(r))+'%. '+formula}; }, addSub:function(x,y,mode){ var amount=x*y/100; var sub=(mode==='subtract'); var r=sub?x-amount:x+amount; return {num:r,main:fmt(r),detail:fmt(x)+(sub?MINUS:' + ')+fmt(y)+'% = '+fmt(x)+(sub?MINUS:' + ')+fmt(amount)+' = '+fmt(r)}; }, ofWhat:function(x,y){ if(y===0){return {error:'Y (the percentage) cannot be zero, because dividing by zero is not possible.'};} var r=x/(y/100); return {num:r,main:fmt(r),detail:fmt(x)+' is '+fmt(y)+'% of '+fmt(r)+'. Formula: '+fmt(x)+DIV+'('+fmt(y)+DIV+'100) = '+fmt(r)} } }; function fallbackCopy(str,done){ var ta=document.createElement('textarea'); ta.value=str;ta.setAttribute('readonly',''); ta.style.position='fixed';ta.style.top='-1000px';ta.style.opacity='0'; root.appendChild(ta);ta.select(); try{ta.setSelectionRange(0,str.length);}catch(e){} var ok=false; try{ok=document.execCommand('copy');}catch(e){ok=false;} root.removeChild(ta); done(ok); } function copyText(str,done){ if(navigator.clipboard){ if(window.isSecureContext){ navigator.clipboard.writeText(str).then(function(){done(true);},function(){fallbackCopy(str,done);}); return; } } fallbackCopy(str,done); } function setupCard(card){ var name=card.getAttribute('data-calc'); var inputs=Array.prototype.slice.call(card.querySelectorAll('input[data-field]')); var sel=card.querySelector('select[data-field]'); var out=card.querySelector('.fl-pc__out'); var mainEl=card.querySelector('[data-main]'); var detailEl=card.querySelector('[data-detail]'); var btnCopy=card.querySelector('[data-act="copy"]'); var btnClear=card.querySelector('[data-act="clear"]'); var msgEl=card.querySelector('[data-msg]'); if(!CALCS[name]||!out||!mainEl||!detailEl||!btnCopy||!btnClear||inputs.length<2){throw new Error('a calculator card is incomplete');} var copyValue='',timer,msgTimer; function show(state,main,detail,copy){ out.className='fl-pc__out'+(state?' is-'+state:''); mainEl.textContent=main; detailEl.textContent=detail; copyValue=copy; btnCopy.disabled=!copy; } function update(){ var vals={},anyEmpty=false,bad=null; inputs.forEach(function(inp){ inp.removeAttribute('aria-invalid'); var p=parseNum(inp.value); if(p.empty){anyEmpty=true;return;} if(p.invalid){ inp.setAttribute('aria-invalid','true'); if(!bad){bad=inp;} return; } vals[inp.getAttribute('data-field')]=p.value; }); if(bad){ show('error','','Please enter a valid number in the "'+bad.getAttribute('data-name')+'" box. Use digits with an optional minus sign and decimal point.',''); return; } if(anyEmpty){ show('','','Enter both numbers to see the result.',''); return; } var r; try{r=CALCS[name](vals.x,vals.y,sel?sel.value:'');}catch(e){r={error:'Sorry, this could not be calculated.'};} if(r.error){show('error','',r.error,'');return;} if(!isFinite(r.num)){show('error','','The result is too large to display.','');return;} show('ok',r.main,r.detail,r.main); } inputs.forEach(function(inp){ inp.addEventListener('input',function(){clearTimeout(timer);timer=setTimeout(update,250);}); }); if(sel){sel.addEventListener('change',update);} btnCopy.addEventListener('click',function(){ if(!copyValue){return;} copyText(copyValue,function(ok){ msgEl.textContent=ok?'Copied.':'Copy failed. Please copy it manually.'; msgEl.style.color=ok?'':'#b91c1c'; clearTimeout(msgTimer); msgTimer=setTimeout(function(){msgEl.textContent='';},2500); }); }); btnClear.addEventListener('click',function(){ clearTimeout(timer); inputs.forEach(function(inp){inp.value='';}); update(); inputs[0].focus(); }); update(); } cardEls.forEach(setupCard); if(loadingEl){loadingEl.hidden=true;} } function init(root){ if(root.getAttribute('data-init')==='1'){return;} root.setAttribute('data-init','1'); var loadingEl=root.querySelector('#fl-pc-loading'); try{ build(root,loadingEl); }catch(err){ if(loadingEl){ loadingEl.hidden=false; loadingEl.textContent='Sorry, this calculator could not start ('+(err&&err.message?err.message:'unknown error')+'). Please reload the page.'; } } } function start(){ var root=document.getElementById('fl-pc'); if(!root){return false;} init(root); return true; } if(!start()){ var tries=0; var tmr=setInterval(function(){ tries=tries+1; if(start()||tries>=50){clearInterval(tmr);} },200); document.addEventListener('DOMContentLoaded',start); } })();