-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.min.js
1 lines (1 loc) · 11.3 KB
/
script.min.js
1
document.addEventListener("DOMContentLoaded",(()=>{BigNumber.config({DECIMAL_PLACES:20,ROUNDING_MODE:BigNumber.ROUND_HALF_UP});const e=new BigNumber(1);let t,n;const i={startTime:null,currentGems:new BigNumber(0),goalGems:null,additionalGems:null,initialTimeInDays:new BigNumber(0),dailyInterest:new BigNumber("0.0025"),hourlyInterest:null},a=(e,t=0)=>e.toFormat(t),o=t=>{if(t.lte(0))throw new Error("ln(x) is undefined for x <= 0");if(t.eq(e))return new BigNumber(0);const n=t.minus(e),i=t.plus(e),a=n.dividedBy(i),o=a.times(a);let r=a,l=a,s=new BigNumber(3);for(let e=1;e<=20;e++)l=l.times(o),r=r.plus(l.dividedBy(s)),s=s.plus(2);return r.times(2)},r=(e,t)=>o(e).dividedBy(o(t)),l=(e,t)=>t.isInteger()?e.exponentiatedBy(t):(e=>{let t=new BigNumber(1),n=new BigNumber(1),i=new BigNumber(1);for(let a=1;a<50;a++)n=n.times(e).dividedBy(i),t=t.plus(n),i=i.plus(1);return t})(t.times(o(e))),s=()=>{const t=document.getElementById("targetDate"),n=document.getElementById("targetTime"),o=document.getElementById("futureAmount"),r=o.nextElementSibling;if(!t.value)return o.textContent="",o.parentElement.style.display="none",void(r.style.display="none");const s=new Date(`${t.value}T${n.value||"00:00"}`);if(isNaN(s.getTime()))return void alert("Please enter a valid target date.");if(!i.startTime)return void alert("Calculation has not been started. Please click 'Calculate!'");const u=new BigNumber(s.getTime()-i.startTime).dividedBy(864e5),d=i.initialTimeInDays.plus(u);if(d.lte(0))return o.textContent="The target date is in the past. Please select a future date.",o.parentElement.style.display="block",void(r.style.display="inline-block");const m=i.currentGems.times(l(e.plus(i.hourlyInterest),d.times(24))),c=formatDateUS(s);o.textContent=`On ${c}, you will have: ${a(m)} gems`,o.parentElement.style.display="block",r.style.display="inline-block"},u=(e,t,n,o,r)=>{const l=r.times(n);document.getElementById(e).textContent=`Profit per ${o}: ${a(l)}`;const s=i.currentGems.plus(l);document.getElementById(t).textContent=`Total gems after ${o}: ${a(s)}`};document.getElementById("calculateBtn").addEventListener("click",(()=>{(()=>{clearInterval(t),clearInterval(n);const o=document.getElementById("currentGems").value,d=document.getElementById("goalGems").value,m=document.getElementById("additionalGems").value,c=parseInt(document.getElementById("years").value)||0,g=parseInt(document.getElementById("days").value)||0,p=parseInt(document.getElementById("hours").value)||0,y=parseInt(document.getElementById("minutes").value)||0,h=parseInt(document.getElementById("seconds").value)||0,f=parseInt(document.getElementById("months").value)||0;if(isNaN(o)||Number(o)<=0)return void alert("Please enter a valid number for Current Gems.");i.currentGems=new BigNumber(o),i.goalGems=d?new BigNumber(d):null,i.additionalGems=m?new BigNumber(m):null,i.hourlyInterest=l(e.plus(i.dailyInterest),new BigNumber(1).dividedBy(24)).minus(e),i.initialTimeInDays=new BigNumber(g).plus(new BigNumber(f).times(30)).plus(new BigNumber(c).times(365)).plus(new BigNumber(p).dividedBy(24)).plus(new BigNumber(y).dividedBy(1440)).plus(new BigNumber(h).dividedBy(86400)),i.startTime=Date.now();const B=()=>{const t=new BigNumber(Date.now()-i.startTime).dividedBy(1e3).dividedBy(86400),n=i.initialTimeInDays.plus(t),o=i.currentGems.times(l(e.plus(i.hourlyInterest),n.times(24))),s=o.minus(i.currentGems),d=s.dividedBy(i.currentGems).times(100);document.getElementById("gemsAfterTime").textContent=`Gems after ${n.integerValue(BigNumber.ROUND_FLOOR).toString()} day(s): ${a(o)}`,document.getElementById("profit").textContent=`Profit: ${a(s)}`;const m=document.getElementById("timeToReach");if(i.goalGems&&!i.goalGems.isZero())if(i.goalGems.lte(i.currentGems))m.textContent="Your current gems already meet or exceed the goal.",m.parentElement.style.display="block";else{const t=r(i.goalGems.dividedBy(i.currentGems),e.plus(i.hourlyInterest)).dividedBy(24),n=new Date(i.startTime+t.times(864e5).toNumber());m.textContent=`You will reach your goal on ${formatDateUS(n)} (in ${t.integerValue(BigNumber.ROUND_FLOOR).toString()} day(s)).`,m.parentElement.style.display="block"}else if(i.additionalGems&&!i.additionalGems.isZero()){const t=i.currentGems.plus(i.additionalGems),n=r(t.dividedBy(i.currentGems),e.plus(i.hourlyInterest)).dividedBy(24),o=new Date(i.startTime+n.times(864e5).toNumber());m.textContent=`You will get ${a(i.additionalGems)} additional gems on ${formatDateUS(o)} (in ${n.integerValue(BigNumber.ROUND_FLOOR).toString()} day(s)).`,m.parentElement.style.display="block"}else m.textContent="",m.parentElement.style.display="none";const c=s.dividedBy(n.times(86400));document.getElementById("profitPerSecond").textContent=`Profit per second: ${a(c)}`,u("profitPerSecond","totalGemsPerSecond",1,"second",c),u("profitPerMinute","totalGemsPerMinute",60,"minute",c),u("profitPerHour","totalGemsPerHour",3600,"hour",c),u("profitPerDay","totalGemsPerDay",86400,"day",c),u("profitPerWeek","totalGemsPerWeek",604800,"week",c),u("profitPerMonth","totalGemsPerMonth",2592e3,"month",c),document.getElementById("profitGrowth").textContent=`Profit Growth (%): ${d.toFixed(6)}%`};B(),s(),n=setInterval(B,100),t=setInterval(s,1e3)})(),s()})),document.getElementById("clearBtn").addEventListener("click",(function(){document.getElementById("targetDate").value="",document.getElementById("targetTime").value="",document.getElementById("futureAmount").textContent="",document.getElementById("futureAmount").parentElement.style.display="none"})),["currentGems","goalGems","additionalGems","years","months","days","hours","minutes","seconds","targetDate","targetTime"].forEach((e=>{document.getElementById(e).addEventListener("input",(function(){clearInterval(t),clearInterval(n)}))})),["targetDate","targetTime"].forEach((e=>{document.getElementById(e).addEventListener("input",(function(){document.getElementById("futureAmount").textContent="",document.getElementById("futureAmount").parentElement.style.display="none"}))}));const d=document.getElementById("technicalInfoBtn"),m=document.getElementById("technicalInfoModal"),c=document.getElementById("technicalInfoContent"),g=m.querySelector(".close"),p=e=>{m.style.display=e?"block":"none",e&&(c.innerHTML="\n <h3>Technical Details</h3>\n <h4>BigNumber.js Configuration</h4>\n <p>The calculator uses the BigNumber.js library configured with 20 decimal places and ROUND_HALF_UP rounding mode for high precision calculations. This configuration is crucial to ensure accuracy in complex financial calculations where rounding errors can accumulate significantly.</p>\n \n <h4>Custom Mathematical Functions</h4>\n <ul>\n <li><strong>Natural Logarithm (ln):</strong> Implemented using a series expansion method known for its high precision. This function is essential for performing inverse exponential growth calculations, such as determining the time required to reach a financial goal.</li>\n <li><strong>Logarithm in Any Base (logBase):</strong> Calculated using the change of base formula, this method allows determining logarithms in any desired base. Internally, the logBase function utilizes our custom ln implementation, providing significant flexibility in analyzing logarithmic growth.</li>\n <li><strong>Exponentiation (customExponentiation):</strong> Handles both integer and non-integer exponents. For integer exponents, BigNumber.js's built-in method is used, while for non-integer exponents, a custom implementation combining Taylor series and natural logarithm calculation is employed. This duality enables the calculator to handle a wide range of mathematical scenarios with precision.</li>\n <li><strong>Exponential Function (exp):</strong> Implemented using a Taylor series expansion, this function allows the calculation of exponents for any real number. It is particularly useful in scenarios where the exponent is not an integer, providing accurate results without relying solely on BigNumber.js's built-in functions.</li>\n </ul>\n \n <h4>Calculation Process</h4>\n <ol>\n <li><strong>User Input Conversion:</strong> All user inputs are converted to BigNumber objects, ensuring that subsequent calculations are performed with the necessary precision. This is especially critical in financial calculations where decimal precision is paramount.</li>\n <li><strong>Daily Interest Rate Application:</strong> The daily interest rate is applied to the current gem balance using the compound interest formula. This operation accounts for time variations, including seconds and fractional seconds, to provide a precise calculation of balance growth.</li>\n <li><strong>Time to Reach Goal Calculation:</strong> The time needed to reach the gem goal is calculated using the logarithmic property of exponential growth. This calculation relies on the custom logBase function, allowing precise determination of when the balance will reach the desired goal under the influence of interest.</li>\n <li><strong>Profit and Growth Rate Calculations:</strong> Profits and growth rates are calculated for various time intervals (second, minute, hour, day, week, month). These calculations are performed in real-time, allowing users to visualize the impact of interest rates on their gem balance continuously and accurately.</li>\n <li><strong>Real-Time Results Update:</strong> Results are updated in real-time using JavaScript's setInterval function. This allows the calculator to respond immediately to user input and adjust calculations as needed, while maintaining a balance between precision and performance.</li>\n </ol>\n \n <h4>Performance Considerations</h4>\n <p>To optimize the user experience, the calculator employs separate intervals for result updates and future amount calculations. Results are updated every 100 ms to ensure high responsiveness, while future amount calculations are performed every 1000 ms, helping to balance computational load without sacrificing accuracy. Additionally, the code is designed to minimize redundant calculations and maximize efficient use of resources, ensuring optimal performance even on devices with limited resources.</p>\n \n <h4>Error Handling</h4>\n <p>The calculator includes a robust input validation and error handling system. User inputs are validated before any mathematical operation to prevent invalid calculations that could lead to incorrect results or execution failures. In case of errors, feedback is provided to the user, guiding them to correct the inputs and ensuring that the calculation can be successfully completed. This attention to detail in error handling and validation contributes to a smooth and reliable user experience, ensuring the calculator can be effectively used by a wide range of users.</p>\n ")};d.addEventListener("click",(()=>p(!0))),g.addEventListener("click",(()=>p(!1))),window.addEventListener("click",(e=>{e.target===m&&p(!1)})),window.addEventListener("keydown",(e=>{"Escape"===e.key&&p(!1)})),document.getElementById("goalGems").addEventListener("input",(function(){clearInterval(t),clearInterval(n),""===this.value&&(document.getElementById("timeToReach").textContent="",document.getElementById("timeToReach").parentElement.style.display="none")}))}));const formatDateUS=e=>e.toLocaleString("en-US",{year:"numeric",month:"2-digit",day:"2-digit",hour:"numeric",minute:"2-digit",hour12:!0,timeZone:"UTC"});