FunnLearn FREE ONLINE TOOLS Explore Tools →

About Us

At funnlearn, we blend play with learning, offering tools and toys that spark curiosity and confidence in every child.
Our Mission
Learn Play Grow
Why Us
Fun Learning

Start Learning

Bring joy to learning with toys that inspire curiosity and growth every day.
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); } })();