companyRank.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { createGraph, createTable, switchPlot } from "../core";
  2. import { months, monthsPretty } from "../staticData/constants";
  3. import { addConfigField, clearChildren, getCompanyId, getData, prettyMonthName } from "../utils";
  4. import { Graph } from "./graph";
  5. export class CompanyRank implements Graph {
  6. id = "compRank";
  7. displayName = "Company Rank";
  8. configFieldIDs = ["month", "companyName"];
  9. loadedData: any;
  10. urlParams: any;
  11. constructor(loadedData: any, urlParams: any)
  12. {
  13. this.loadedData = loadedData;
  14. this.urlParams = urlParams;
  15. }
  16. setConfigs(useURLParams?: boolean)
  17. {
  18. const updateFunc = function() {switchPlot();}
  19. const configDiv = document.getElementById("selectorSubtypes");
  20. if(configDiv)
  21. {
  22. clearChildren(configDiv);
  23. }
  24. configDiv?.appendChild(addConfigField("select", "month", "Month: ", {prettyValues: monthsPretty, "values": months}, useURLParams && this.urlParams.month ? this.urlParams.month : months[months.length - 1], updateFunc));
  25. configDiv?.appendChild(addConfigField("input", "companyName", "Username: ", undefined, useURLParams ? this.urlParams.companyName : undefined, updateFunc, "-27px"));
  26. }
  27. async generatePlot(configValues: any, plotContainerID: string)
  28. {
  29. if(!configValues.companyName || configValues.companyName == ""){return;}
  30. // Get Company Data
  31. const knownCompanies = await getData(this.loadedData, "knownCompanies");
  32. // Get Company ID
  33. var companyID = await getCompanyId(configValues.companyName, this.loadedData) as string;
  34. if(!companyID){ return; }
  35. var companyName = knownCompanies[companyID]?.Username;
  36. const fullCompanyData: FullCompanyData = await getData(this.loadedData, "company", configValues.month);
  37. const fullPrevCompanyData: FullCompanyData = configValues.month == months[0] ?
  38. {individual: {}} :
  39. await getData(this.loadedData, "company", months[months.indexOf(configValues.month) - 1]);
  40. const companyData = fullCompanyData.individual[companyID]; // Company data for this company for this month
  41. const prevCompanyData = fullPrevCompanyData.individual[companyID]; // Company data for this company for last month. May be undefined.
  42. if(!companyData){return;}
  43. var tableData = [] as any[]; // Entries in the table in raw data form
  44. var tableDisplay = [] as any[]; // Entries in the table in presentable form
  45. Object.keys(companyData).forEach(ticker => {
  46. const tableRow = [companyData[ticker].rank, ticker, companyData[ticker].amount, companyData[ticker].volume, companyData[ticker].profit];
  47. const tableDisplayRow = [] as any[];
  48. // Add company rank
  49. if(prevCompanyData)
  50. {
  51. const outerRankDiv = document.createElement("div");
  52. const symbolDiv = document.createElement("div");
  53. const rankDiv = document.createElement("div");
  54. outerRankDiv.style.display = "flex";
  55. symbolDiv.style.width = "14px";
  56. symbolDiv.style.minWidth = "14px";
  57. symbolDiv.style.marginRight = "2px";
  58. const prevRank = prevCompanyData[ticker]?.rank;
  59. const increasing = prevRank < companyData[ticker].rank;
  60. if(prevRank && prevRank != companyData[ticker].rank)
  61. {
  62. symbolDiv.textContent = increasing ? "▼" : "▲";
  63. symbolDiv.style.color = increasing ? "#d9534f" : "#5cb85c";
  64. }
  65. rankDiv.textContent = companyData[ticker].rank.toLocaleString();
  66. outerRankDiv.appendChild(symbolDiv);
  67. outerRankDiv.appendChild(rankDiv);
  68. tableDisplayRow.push(outerRankDiv);
  69. }
  70. else
  71. {
  72. const rankDiv = document.createElement("div");
  73. rankDiv.textContent = companyData[ticker].rank.toLocaleString();
  74. tableDisplayRow.push(rankDiv);
  75. }
  76. // Add ticker
  77. const tickerDiv = document.createElement("div");
  78. tickerDiv.textContent = ticker;
  79. tableDisplayRow.push(tickerDiv);
  80. // Add amount
  81. const amountDiv = document.createElement("div");
  82. amountDiv.textContent = companyData[ticker].amount.toLocaleString(undefined, {maximumFractionDigits: 1});
  83. tableDisplayRow.push(amountDiv);
  84. // Add volume
  85. const volumeDiv = document.createElement("div");
  86. volumeDiv.textContent = "$" + companyData[ticker].volume.toLocaleString(undefined, {notation: "compact", maximumSignificantDigits: 3});
  87. tableDisplayRow.push(volumeDiv);
  88. // Add profit
  89. const profitDiv = document.createElement("div");
  90. const profit = companyData[ticker].profit ?? NaN;
  91. let profitText: string = "";
  92. if (profit < 0)
  93. profitText = "-$" + (-profit).toLocaleString(undefined, {notation: "compact", maximumSignificantDigits: 3});
  94. else if (profit > 0)
  95. profitText = "$" + profit.toLocaleString(undefined, {notation: "compact", maximumSignificantDigits: 3});
  96. profitDiv.textContent = profitText;
  97. tableDisplayRow.push(profitDiv);
  98. tableData.push(tableRow);
  99. tableDisplay.push(tableDisplayRow);
  100. });
  101. // Sort by rank by default
  102. const indices = tableData.map((_, i) => i)
  103. .sort((a, b) => tableData[a][0] - tableData[b][0]);
  104. tableData = indices.map(i => tableData[i]);
  105. tableDisplay = indices.map(i => tableDisplay[i]);
  106. // Get overall ranks for the title
  107. const title = "Production Ranking of " + companyName + " - " + prettyMonthName(configValues.month) + "\nVolume: #" + fullCompanyData.totals[companyID].volumeRank + ", Profit: #" + fullCompanyData.totals[companyID].profitRank;
  108. const headers = ["Rank", "Ticker", "Amount [/day]", "Volume [$/day]", "Profit [$/day]"];
  109. createTable(plotContainerID, title, headers, tableData, tableDisplay);
  110. }
  111. }
  112. interface FullCompanyData {
  113. totals: Record<string, CompanyTotals>;
  114. individual: Record<string, Record<string, CompanyTickerData>>;
  115. }
  116. interface CompanyTotals {
  117. volume: number;
  118. volumeRank: number;
  119. profitRank?: number;
  120. }
  121. interface CompanyTickerData {
  122. amount: number;
  123. volume: number;
  124. rank: number;
  125. profit?: number;
  126. }