roi.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. (async function () {
  2. const response = await fetch('roi.json');
  3. const profits: Profit[] = await response.json();
  4. const formatDecimal = new Intl.NumberFormat(undefined,
  5. {maximumFractionDigits: 2, maximumSignificantDigits: 6, roundingPriority: 'lessPrecision'}).format;
  6. const formatWhole = new Intl.NumberFormat(undefined, {maximumFractionDigits: 0}).format;
  7. const tbody = document.querySelector('tbody')!;
  8. for (const p of profits) {
  9. const tr = document.createElement('tr');
  10. tr.innerHTML = `
  11. <td>${p.output}</td>
  12. <td>${p.expertise}</td>
  13. <td style="color: ${color(p.profit_per_area, 0, 500)}">${formatDecimal(p.profit_per_area)}</td>
  14. <td style="color: ${color(p.capex, 300_000, 50_000)}">${formatWhole(p.capex)}</td>
  15. <td style="color: ${color(p.cost_per_day, 100_000, 25_000)}">${formatWhole(p.cost_per_day)}</td>
  16. <td style="color: ${color(p.logistics_per_area, 2, 0.2)}">${formatDecimal(p.logistics_per_area)}</td>
  17. <td>
  18. ${formatWhole(p.output_per_day)}<br>
  19. <span style="color: ${color(p.output_per_day/p.average_traded_7d, 0.05, 0.002)}">${formatWhole(p.average_traded_7d)}</span>
  20. </td>
  21. `;
  22. const output = tr.querySelector('td')!;
  23. output.title = p.recipe;
  24. tbody.appendChild(tr);
  25. }
  26. })();
  27. function color(n: number, low: number, high: number): string {
  28. // scale n from low..high to 0..1 clamped
  29. const scale = Math.min(Math.max((n - low) / (high - low), 0), 1);
  30. return `color-mix(in oklch, #0c8 ${scale * 100}%, #f70)`;
  31. }
  32. interface Profit {
  33. output: string
  34. recipe: string
  35. expertise: string
  36. profit_per_area: number
  37. capex: number
  38. cost_per_day: number
  39. logistics_per_area: number
  40. output_per_day: number
  41. average_traded_7d: number
  42. }