Start the process of splitting JS files

I am a JS noob so this is probably poorly thought out. But it is a wip and I dont really care about the quality, just more the learning experience.
This commit is contained in:
Emily Doherty 2024-10-13 23:23:31 -07:00
parent 27eb2ccb45
commit a51d3f8d7b
7 changed files with 252 additions and 79 deletions

22
src/datum.js Normal file
View File

@ -0,0 +1,22 @@
export default class Datum {
constructor(time, price) {
this._time = time;
this._price = price;
}
getTime() {
return this._time;
}
getPrice() {
return this._price;
}
getX() {
return this.getTime();
}
getY() {
return this.getPrice();
}
}

4
src/fetchCurrent.js Normal file
View File

@ -0,0 +1,4 @@
export default async function fetchCurrent() {
const resp = await fetch("https://data.wowtoken.app/token/current.json");
return await resp.json();
}

13
src/fetchData.js Normal file
View File

@ -0,0 +1,13 @@
import Datum from "./datum";
import urlBuilder from "./urlBuilder";
export default async function fetchData(currentRegionSelection, currentTimeSelection, currentAggregateSelection) {
const data = [];
const resp = await fetch(urlBuilder(currentRegionSelection, currentTimeSelection, currentAggregateSelection));
const respData = await resp.json();
for (let i = 0, l = respData.length; i < l; i++) {
let datum = new Datum(Date.parse(respData[i]['time']), respData[i]['value']);
data.push(datum);
}
return data;
}

View File

@ -12,6 +12,12 @@ import {
import 'chartjs-adapter-dayjs-3'; import 'chartjs-adapter-dayjs-3';
import "./style.css" import "./style.css"
import fetchCurrent from "./fetchCurrent";
import fetchData from "./fetchData";
import {addLoader, removeLoader} from "./loader";
import TokenChart from "./tokenChart";
import Datum from "./datum";
// TODO: This file should be seperated into multiple with better ownership // TODO: This file should be seperated into multiple with better ownership
Chart.register( Chart.register(
@ -29,13 +35,14 @@ let currentRegionSelection = '';
let currentTimeSelection = ''; let currentTimeSelection = '';
let currentAggregateSelection = ''; let currentAggregateSelection = '';
let startYAtZero = false; let startYAtZero = false;
let chart;
const currentPriceHash = { const currentPriceHash = {
us: 0, us: 0,
eu: 0, eu: 0,
kr: 0, kr: 0,
tw: 0 tw: 0
}; };
let chartData = { const chartData = {
us: [], us: [],
eu: [], eu: [],
kr: [], kr: [],
@ -68,7 +75,7 @@ function populateChart() {
datasets: [{ datasets: [{
borderColor: 'gold', borderColor: 'gold',
label: currentRegionSelection.toUpperCase() + " WoW Token Price", label: currentRegionSelection.toUpperCase() + " WoW Token Price",
data: chartJsData, data: [],
cubicInterpolationMode: 'monotone', cubicInterpolationMode: 'monotone',
pointRadius: 0 pointRadius: 0
}] }]
@ -122,42 +129,35 @@ function lookupTimeUnit(query){
return lookup[query.charAt(query.length - 1)] return lookup[query.charAt(query.length - 1)]
} }
async function callUpdateURL() { async function callUpdateURL() {
let resp = await fetch("https://data.wowtoken.app/token/current.json"); await updateTokens(await fetchCurrent());
let data = await resp.json();
updateTokens(data);
} }
function updateTokens(data) { async function updateTokens(data) {
updateRegionalToken('us', data); await Promise.all([
updateRegionalToken('eu', data); updateRegionalToken('us', data),
updateRegionalToken('kr', data); updateRegionalToken('eu', data),
updateRegionalToken('tw', data); updateRegionalToken('kr', data),
updateRegionalToken('tw', data)
]);
} }
function updateRegionalToken(region, data) { async function updateRegionalToken(region, data) {
if (currentPriceHash[region] !== data['price_data'][region]) { if (currentPriceHash[region] !== data['price_data'][region]) {
currentPriceHash[region] = data['price_data'][region]; currentPriceHash[region] = data['price_data'][region];
if (region === currentRegionSelection) { if (region === currentRegionSelection) {
formatToken(); formatToken();
if (currentAggregateSelection === 'none') { const datum = new Datum(data['current_time'], data['price']);
addDataToChart(region, data); if (currentAggregateSelection === 'none' && chart.active()) {
await chart.addDataToChart(datum);
}
else if (currentAggregateSelection === 'none' && !chart.active()) {
await chart.lateUpdate(datum);
} }
} }
} }
} }
function addDataToChart(region, data) {
if (tokenChart) {
const datum = {x: data['current_time'], y: data['price_data'][region]}
tokenChart.data.datasets.forEach((dataset) => {
dataset.data.push(datum);
})
tokenChart.update();
}
}
async function aggregateFunctionToggle() { async function aggregateFunctionToggle() {
// TODO: We should probably make these global or something // TODO: We should probably make these global or something
// so if the need to be updated in the future we can do so easily // so if the need to be updated in the future we can do so easily
@ -177,54 +177,33 @@ async function aggregateFunctionToggle() {
} }
} }
function addLoader() { async function updateRegionPreference(newRegion) {
let loader = document.getElementById('loader');
if (!loader) {
const blank_div = document.createElement('div');
let loaderNode = blank_div.cloneNode();
loaderNode.id = 'loader';
loaderNode.className = 'lds-ripple';
loaderNode.appendChild(blank_div.cloneNode());
loaderNode.appendChild(blank_div.cloneNode());
let chartNode = document.getElementById('token-chart');
chartNode.before(loaderNode);
}
}
function removeLoader () {
let loader = document.getElementById('loader');
if (loader) {
loader.remove();
}
}
function updateRegionPreference(newRegion) {
if (newRegion !== currentRegionSelection) { if (newRegion !== currentRegionSelection) {
tokenChart.destroy(); await chart.destroyChart();
addLoader(); addLoader();
currentRegionSelection = newRegion; currentRegionSelection = newRegion;
} }
formatToken(); formatToken();
pullChartData().then(populateChart); await pullChartData();
} }
function updateTimePreference(newTime) { async function updateTimePreference(newTime) {
if (newTime !== currentTimeSelection) { if (newTime !== currentTimeSelection) {
tokenChart.destroy(); await chart.destroyChart();
addLoader(); addLoader();
currentTimeSelection = newTime; currentTimeSelection = newTime;
aggregateFunctionToggle(); await aggregateFunctionToggle();
} }
pullChartData().then(populateChart); await pullChartData();
} }
function updateAggregatePreference(newAggregate) { async function updateAggregatePreference(newAggregate) {
if (newAggregate !== currentAggregateSelection) { if (newAggregate !== currentAggregateSelection) {
tokenChart.destroy(); await chart.destroyChart();
addLoader(); addLoader();
currentAggregateSelection = newAggregate; currentAggregateSelection = newAggregate;
} }
pullChartData().then(populateChart); await pullChartData();
} }
function toggleAdvancedSetting() { function toggleAdvancedSetting() {
@ -241,33 +220,19 @@ function toggleAdvancedSetting() {
function toggleStartYAtZero(){ function toggleStartYAtZero(){
startYAtZero = document.getElementById('y-start').checked; startYAtZero = document.getElementById('y-start').checked;
if (tokenChart){ chart.toggleYStart(startYAtZero);
tokenChart.options.scales.y.beginAtZero = startYAtZero;
tokenChart.update();
}
}
function urlBuilder() {
let url = "https://data.wowtoken.app/token/history/";
if (currentAggregateSelection !== 'none') {
url += `${currentAggregateSelection}/`
}
url += `${currentRegionSelection}/${currentTimeSelection}.json`
return url;
} }
async function pullChartData() { async function pullChartData() {
let resp = await fetch(urlBuilder()); chartData[currentRegionSelection] = await fetchData(currentRegionSelection, currentTimeSelection, currentAggregateSelection);
let chartData = await resp.json(); if (!chart.active()) {
let newChartJSData = []; await chart.createChart(currentRegionSelection, currentTimeSelection, startYAtZero, chartData[currentRegionSelection]);
for (let i = 0; i < chartData.length; i++) { }
let datum = { else {
x: chartData[i]['time'], for (let i = 0; i < chartData[currentRegionSelection].length; i++) {
y: chartData[i]['value'] await chart.addDataToChart(chartData[currentRegionSelection][i]);
}; }
newChartJSData.push(datum);
} }
chartJsData = newChartJSData;
removeLoader(); removeLoader();
} }
@ -428,7 +393,11 @@ function registerOptionHandlers() {
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
registerEventHandles(); registerEventHandles();
detectURLQuery(); detectURLQuery();
Promise.all([callUpdateURL(), pullChartData()]).then(populateChart) chart = new TokenChart();
Promise.all([
callUpdateURL(),
]).then(pullChartData);
setInterval(callUpdateURL, 60*1000); setInterval(callUpdateURL, 60*1000);
}, false); }, false);

22
src/loader.js Normal file
View File

@ -0,0 +1,22 @@
function addLoader() {
let loader = document.getElementById('loader');
if (!loader) {
const blank_div = document.createElement('div');
let loaderNode = blank_div.cloneNode();
loaderNode.id = 'loader';
loaderNode.className = 'lds-ripple';
loaderNode.appendChild(blank_div.cloneNode());
loaderNode.appendChild(blank_div.cloneNode());
let chartNode = document.getElementById('token-chart');
chartNode.before(loaderNode);
}
}
function removeLoader () {
let loader = document.getElementById('loader');
if (loader) {
loader.remove();
}
}
export {addLoader, removeLoader};

135
src/tokenChart.js Normal file
View File

@ -0,0 +1,135 @@
import {
Chart,
Legend,
LinearScale,
LineController,
LineElement,
PointElement,
TimeSeriesScale,
Title,
Tooltip
} from 'chart.js';
import 'chartjs-adapter-dayjs-3';
function lookupTimeUnit(query){
const lookup = {
'h': 'day',
'd': 'week',
'm': 'month',
'y': 'month',
'l': 'year'
}
return lookup[query.charAt(query.length - 1)]
}
export default class TokenChart {
constructor() {
this._context = document.getElementById("token-chart").getContext('2d');
this._chartActive = false;
this._lastDatum = null;
this._lateUpdate = true
}
async createChart(region, time, yLevel, data = []) {
const chartData = [];
let lateUpdateData = this._lastDatum;
for (let i = 0; i < data.length; i++) {
this._lastDatum = data[i];
chartData.push({
x: data[i].getX(),
y: data[i].getY(),
})
}
if (this._lateUpdate) {
if (this._lastDatum.getPrice() !== lateUpdateData.getPrice() &&
this._lastDatum.getTime() < lateUpdateData.getTime()) {
chartData.push({
x: lateUpdateData.getX(),
y: lateUpdateData.getY(),
})
}
this._lateUpdate = false
}
this._chart = new Chart(this._context, {
type: 'line',
data: {
datasets: [{
borderColor: 'gold',
label: region.toUpperCase() + " WoW Token Price",
data: chartData,
cubicInterpolationMode: 'monotone',
pointRadius: 0
}]
},
options: {
interaction: {
intersect: false,
mode: "index"
},
scales: {
x: {
type: 'time',
grid: {
color: '#625f62',
},
ticks: {
color: '#a7a4ab',
font: {
size: 18,
}
},
time: {
unit: lookupTimeUnit(time)
}
},
y: {
beginAtZero: yLevel,
grid: {
color: '#2f2c2f',
},
ticks: {
color: '#a7a4ab',
font: {
size: 18,
}
}
}
},
}
});
this._chartActive = true;
}
async destroyChart() {
await this._chart.destroy();
this._chartActive = false;
}
async lateUpdate(datum){
this._lastDatum = datum;
this._lateUpdate = true;
}
async addDataToChart(datum) {
this._chart.data.datasets.forEach((dataset) => {
dataset.data.push({
x: datum.getX(),
y: datum.getY(),
})
});
this._chart.update();
}
active() {
return this._chartActive;
}
toggleYStart(startYAtZero) {
this._chart.options.scales.y.beginAtZero = startYAtZero;
this._chart.update();
}
}

8
src/urlBuilder.js Normal file
View File

@ -0,0 +1,8 @@
export default function urlBuilder(currentRegionSelection, currentTimeSelection, currentAggregateSelection) {
let url = "https://data.wowtoken.app/token/history/";
if (currentAggregateSelection !== 'none') {
url += `${currentAggregateSelection}/`
}
url += `${currentRegionSelection}/${currentTimeSelection}.json`
return url;
}