| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- import {cachedFetchJSON} from './cache';
- const renderTarget = document.querySelector('#gov')!;
- const planetInput = document.querySelector('#planet') as HTMLInputElement;
- const popSelect = document.querySelector('#pop') as HTMLSelectElement;
- function serializeToHash(planet: string, pop: Pop): void {
- const params = new URLSearchParams({'planet': planet, 'pop': pop});
- document.location.hash = params.toString();
- }
- function deserializeFromHash(): {planet: string, pop: Pop} | null {
- const params = new URLSearchParams(document.location.hash.substring(1));
- const planet = params.get('planet');
- const pop = params.get('pop');
- if (planet && pop && ['pio', 'set', 'tec', 'eng', 'sci'].includes(pop)) {
- planetInput.value = planet;
- popSelect.value = pop;
- return {planet, pop: pop as Pop};
- } else
- return null;
- }
- document.querySelector('form')!.addEventListener('submit', async (event) => {
- event.preventDefault();
- const planet = planetInput.value;
- const pop = popSelect.value as Pop;
- if (planet && pop) {
- await render(planet, pop);
- serializeToHash(planet, pop);
- }
- });
- {
- const deserialized = deserializeFromHash();
- if (deserialized)
- void render(deserialized.planet, deserialized.pop);
- }
- async function render(planetName: string, pop: Pop) {
- const loader = document.querySelector('#loader') as HTMLElement;
- loader.style.display = 'block';
- renderTarget.innerHTML = '';
- const planet: Planet = await cachedFetchJSON(
- `https://api.fnar.net/planet/${encodeURIComponent(planetName)}?include_population_reports=true`);
- let lastPOPR = null;
- for (const report of planet.PopulationReports) {
- if (!lastPOPR || report.SimulationPeriod > lastPOPR.SimulationPeriod)
- lastPOPR = report;
- }
- if (lastPOPR === null) {
- renderTarget.textContent = `no POPR for ${planetName}`;
- return;
- }
- const lastPOPRts = Math.floor(new Date(lastPOPR.ReportTimestamp).getTime() / 1000);
- const nextPOPRts = lastPOPRts + 7 * 24 * 60 * 60;
- renderTarget.innerHTML = `last POPR: ${lastPOPR.ReportTimestamp} (${lastPOPRts})
- <br>next POPR: ${new Date(nextPOPRts * 1000).toISOString()} (${nextPOPRts})
- <table>
- <tr>
- <th></th>
- <th>pio</th>
- <th>set</th>
- <th>tec</th>
- <th>eng</th>
- <th>sci</th>
- </tr>
- <tr>
- <th>population</th>
- <td>${lastPOPR.NextPopulationPioneer}<br>${formatDelta(lastPOPR.PopulationDifferencePioneer)}</td>
- <td>${lastPOPR.NextPopulationSettler}<br>${formatDelta(lastPOPR.PopulationDifferenceSettler)}</td>
- <td>${lastPOPR.NextPopulationTechnician}<br>${formatDelta(lastPOPR.PopulationDifferenceTechnician)}</td>
- <td>${lastPOPR.NextPopulationEngineer}<br>${formatDelta(lastPOPR.PopulationDifferenceEngineer)}</td>
- <td>${lastPOPR.NextPopulationScientist}<br>${formatDelta(lastPOPR.PopulationDifferenceScientist)}</td>
- </tr>
- <tr>
- <th>unemployed</th>
- <td>${unemployed(lastPOPR.NextPopulationPioneer, lastPOPR.PopulationDifferencePioneer, lastPOPR.OpenJobsPioneer, lastPOPR.UnemploymentRatePioneer)}</td>
- <td>${unemployed(lastPOPR.NextPopulationSettler, lastPOPR.PopulationDifferenceSettler, lastPOPR.OpenJobsSettler, lastPOPR.UnemploymentRateSettler)}</td>
- <td>${unemployed(lastPOPR.NextPopulationTechnician, lastPOPR.PopulationDifferenceTechnician, lastPOPR.OpenJobsTechnician, lastPOPR.UnemploymentRateTechnician)}</td>
- <td>${unemployed(lastPOPR.NextPopulationEngineer, lastPOPR.PopulationDifferenceEngineer, lastPOPR.OpenJobsEngineer, lastPOPR.UnemploymentRateEngineer)}</td>
- <td>${unemployed(lastPOPR.NextPopulationScientist, lastPOPR.PopulationDifferenceScientist, lastPOPR.OpenJobsScientist, lastPOPR.UnemploymentRateScientist)}</td>
- </tr>
- </table>`;
- loader.style.display = 'none';
- }
- function formatDelta(n: number, withPlus: boolean = true): string {
- if (n > 0)
- return `<span class="positive">${withPlus ? '+' : ''}${n}</span>`;
- else if (n < 0)
- return `<span class="negative">${n}</span>`;
- else
- return n.toString();
- }
- function unemployed(people: number, change: number, openJobs: number, unemploymentRate: number): string {
- let nextUnemployed;
- if (openJobs <= people + change) {
- let prevUnemploymentRate = unemploymentRate;
- if (openJobs > 0)
- if (people - change > 0)
- prevUnemploymentRate = -openJobs / (people - change);
- else
- prevUnemploymentRate = -1
- const prevUnemployed = prevUnemploymentRate * (people - change);
- nextUnemployed = prevUnemployed + change;
- } else
- nextUnemployed = -openJobs + change;
- return formatDelta(Math.round(nextUnemployed), false);
- }
- type Pop = 'pio' | 'set' | 'tec' | 'eng' | 'sci';
- interface Planet {
- PopulationReports: POPR[]
- }
- interface POPR {
- SimulationPeriod: number;
- ReportTimestamp: string;
- NextPopulationPioneer: number;
- NextPopulationSettler: number;
- NextPopulationTechnician: number;
- NextPopulationEngineer: number;
- NextPopulationScientist: number;
- PopulationDifferencePioneer: number;
- PopulationDifferenceSettler: number;
- PopulationDifferenceTechnician: number;
- PopulationDifferenceEngineer: number;
- PopulationDifferenceScientist: number;
- OpenJobsPioneer: number;
- OpenJobsSettler: number;
- OpenJobsTechnician: number;
- OpenJobsEngineer: number;
- OpenJobsScientist: number;
- UnemploymentRatePioneer: number;
- UnemploymentRateSettler: number;
- UnemploymentRateTechnician: number;
- UnemploymentRateEngineer: number;
- UnemploymentRateScientist: number;
- }
|