| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- (async function () {
- const response = await fetch('roi.json');
- const profits: Profit[] = await response.json();
- const formatDecimal = new Intl.NumberFormat(undefined,
- {maximumFractionDigits: 2, maximumSignificantDigits: 6, roundingPriority: 'lessPrecision'}).format;
- const formatWhole = new Intl.NumberFormat(undefined, {maximumFractionDigits: 0}).format;
- const tbody = document.querySelector('tbody')!;
- for (const p of profits) {
- const tr = document.createElement('tr');
- const profit_per_area = p.profit_per_day / p.area;
- const break_even = p.profit_per_day > 0 ? p.capex / p.profit_per_day : Infinity;
- tr.innerHTML = `
- <td>${p.output}</td>
- <td>${p.expertise}</td>
- <td style="color: ${color(profit_per_area, 0, 500)}">${formatDecimal(profit_per_area)}</td>
- <td><span style="color: ${color(break_even, 30, 2)}">${formatDecimal(break_even)}</span>d</td>
- <td style="color: ${color(p.capex, 300_000, 50_000)}">${formatWhole(p.capex)}</td>
- <td style="color: ${color(p.cost_per_day, 100_000, 25_000)}">${formatWhole(p.cost_per_day)}</td>
- <td style="color: ${color(p.logistics_per_area, 2, 0.2)}">${formatDecimal(p.logistics_per_area)}</td>
- <td>
- ${formatWhole(p.output_per_day)}<br>
- <span style="color: ${color(p.output_per_day/p.average_traded_7d, 0.05, 0.002)}">${formatWhole(p.average_traded_7d)}</span>
- </td>
- `;
- const output = tr.querySelector('td')!;
- output.title = p.recipe;
- tbody.appendChild(tr);
- }
- })();
- function color(n: number, low: number, high: number): string {
- // scale n from low..high to 0..1 clamped
- const scale = Math.min(Math.max((n - low) / (high - low), 0), 1);
- return `color-mix(in oklch, #0c8 ${scale * 100}%, #f70)`;
- }
- interface Profit {
- output: string
- recipe: string
- expertise: string
- profit_per_day: number
- area: number
- capex: number
- cost_per_day: number
- logistics_per_area: number
- output_per_day: number
- average_traded_7d: number
- }
|