Compare commits
34 Commits
ef95388185
...
classic
| Author | SHA1 | Date | |
|---|---|---|---|
| ac61fe47ca | |||
| be4b84ee75 | |||
| bc44d4fe35 | |||
| b6b30df542 | |||
| 69b6409699 | |||
| 1b026d0757 | |||
| a38a118473 | |||
| 9f7ab723a9 | |||
| fa009b48b5 | |||
| 7eaedf0f9a | |||
| 5f9e3462ae | |||
| 13ed6dfdce | |||
| b8d11b3815 | |||
| 2e020633b5 | |||
| d07eec1cf0 | |||
| de6621e81c | |||
| 7a17bb8821 | |||
| f207e36ccd | |||
| 9ac97425c7 | |||
| f7a27f9350 | |||
| 4c77828d5a | |||
| 50787c1d83 | |||
| 09ec5f0d4d | |||
| 36ba83d9be | |||
| 8f6cbbc75d | |||
| 354381936d | |||
| 214910aa25 | |||
| ac12a9c55d | |||
| fa21b50b28 | |||
| ae789181f4 | |||
| a1b1dc63ff | |||
| 249f9e281f | |||
| bda9edf3df | |||
| e090a93605 |
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
These are the public assets for the [wowtoken.app](https://wowtoken.app) website, served off Amazon S3 behind CloudFront.
|
These are the public assets for the [wowtoken.app](https://wowtoken.app) website, served off Amazon S3 behind CloudFront.
|
||||||
|
|
||||||
This project gets picked up by CodePipeline, built via CodeBuild, and deployed.
|
This project gets picked up by CodePipeline, built via CodeBuild, and to S3.
|
||||||
|
|
||||||
|
Backend lambdas can be found at my private git repository [wowtoken.app-backend](https://git.emily.sh/wowtoken-app/wowtoken.app-backend)
|
||||||
|
|
||||||

|

|
||||||
@@ -3,7 +3,7 @@ version: 0.2
|
|||||||
phases:
|
phases:
|
||||||
install:
|
install:
|
||||||
runtime-versions:
|
runtime-versions:
|
||||||
nodejs: 16
|
nodejs: 18
|
||||||
commands:
|
commands:
|
||||||
- echo Installing dependencies...
|
- echo Installing dependencies...
|
||||||
- npm install
|
- npm install
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default async function fetchCurrent() {
|
export default async function fetchCurrent() {
|
||||||
const resp = await fetch("https://data.wowtoken.app/token/current.json");
|
const resp = await fetch("https://data.wowtoken.app/v2/current/classic.json");
|
||||||
return await resp.json();
|
return await resp.json();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default async function fetchData(currentRegionSelection, currentTimeSelec
|
|||||||
const resp = await fetch(urlBuilder(currentRegionSelection, currentTimeSelection, currentAggregateSelection));
|
const resp = await fetch(urlBuilder(currentRegionSelection, currentTimeSelection, currentAggregateSelection));
|
||||||
const respData = await resp.json();
|
const respData = await resp.json();
|
||||||
for (let i = 0, l = respData.length; i < l; i++) {
|
for (let i = 0, l = respData.length; i < l; i++) {
|
||||||
let datum = new Datum(Date.parse(respData[i]['time']), respData[i]['value']);
|
const datum = new Datum(new Date(respData[i][0]), respData[i][1]);
|
||||||
data.push(datum);
|
data.push(datum);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>WoW Historical Token Prices Tracker</title>
|
<title>WoW Classic Historical Token Prices Tracker</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="description" content="Track current and historical gold price trends for the World of Warcraft (WoW) in game token, including the US, EU, TW, and KR regions. Prices updated every minute. Simple, quick, and easy info, no ads or tracking, ever.">
|
<meta name="description" content="Track current and historical gold price trends for the World of Warcraft (WoW) Classic in game token, including the US, EU, TW, and KR regions. Prices updated every minute. Simple, quick, and easy info, no ads or tracking, ever.">
|
||||||
<link rel="preconnect" href="https://data.wowtoken.app">
|
<link rel="preconnect" href="https://data.wowtoken.app">
|
||||||
<link rel="dns-prefetch" href="https://data.wowtoken.app">
|
<link rel="dns-prefetch" href="https://data.wowtoken.app">
|
||||||
<link rel="preload" href="https://data.wowtoken.app/token/current.json" as="fetch" type="application/json" crossorigin="anonymous">
|
<link rel="preload" href="https://data.wowtoken.app/v2/current/classic.json" as="fetch" type="application/json" crossorigin="anonymous">
|
||||||
<link rel="preload" href="https://data.wowtoken.app/token/history/us/72h.json" as="fetch" type="application/json" crossorigin="anonymous">
|
<link rel="preload" href="https://data.wowtoken.app/v2/relative/classic/us/72h.json" as="fetch" type="application/json" crossorigin="anonymous">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div class="data-header">
|
<div class="data-header">
|
||||||
<h1>1 Token = <u id="token">0</u> Gold</h1>
|
<h1>1 Classic Token = <u id="token">0</u> Gold</h1>
|
||||||
<div class="high-low">
|
<div class="high-low">
|
||||||
<p>Lowest in last <em id="low-time">3 days</em>: <u id="low-val">0</u></p>
|
<p>Lowest in last <em id="low-time">3 days</em>: <u id="low-val">0</u></p>
|
||||||
<p>Highest in last <em id="high-time">3 days</em>: <u id="high-val">0</u></p>
|
<p>Highest in last <em id="high-time">3 days</em>: <u id="high-val">0</u></p>
|
||||||
@@ -43,8 +43,6 @@
|
|||||||
<option value="720h">1 Month</option>
|
<option value="720h">1 Month</option>
|
||||||
<option value="90d">3 Months</option>
|
<option value="90d">3 Months</option>
|
||||||
<option value="6m">6 Months</option>
|
<option value="6m">6 Months</option>
|
||||||
<option value="1y">1 Year</option>
|
|
||||||
<option value="2y">2 Years</option>
|
|
||||||
<option value="all">All Available</option>
|
<option value="all">All Available</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,9 +57,15 @@
|
|||||||
<label for="aggregate">Smoothing Function:</label>
|
<label for="aggregate">Smoothing Function:</label>
|
||||||
<select name="aggregate" id="aggregate">
|
<select name="aggregate" id="aggregate">
|
||||||
<option id='agg_none' value="none">None</option>
|
<option id='agg_none' value="none">None</option>
|
||||||
<option id='agg_davg' value="daily_mean">Daily Average</option>
|
<option id='agg_davg' value="avg">Daily Average</option>
|
||||||
</select>
|
</select>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<fieldset id="period-overlay-options">
|
||||||
|
<label for="period-overlay" id="period-overlay-label">
|
||||||
|
Overlay previous <em id="period-time">0 hours</em> on current period:
|
||||||
|
</label>
|
||||||
|
<input type="checkbox" id="period-overlay" name="period-overlay">
|
||||||
|
</fieldset>
|
||||||
<fieldset id="y-start-options">
|
<fieldset id="y-start-options">
|
||||||
<label for="y-start">Start y-axis at 0:</label>
|
<label for="y-start">Start y-axis at 0:</label>
|
||||||
<input type="checkbox" id="y-start" name="y-start"/>
|
<input type="checkbox" id="y-start" name="y-start"/>
|
||||||
@@ -74,13 +78,17 @@
|
|||||||
Copy URL to this Chart
|
Copy URL to this Chart
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="other-projects">
|
||||||
<p><em>Looking for the classic WoW Token price? Find it <a href="https://classic.wowtoken.app">here!</a></em></p>
|
<p><em>
|
||||||
|
Get alerted when the Token hits certain thresholds using GoblinBot, find out more <a href="https://blog.emily.sh/token-bot/">here!</a>
|
||||||
|
</em></p>
|
||||||
|
<hr />
|
||||||
|
<p><em>Looking for the retail WoW Token price? Find it <a href="https://wowtoken.app">here!</a></em></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<details id="about">
|
<details id="about">
|
||||||
<summary>About this Site</summary>
|
<summary>About this Site</summary>
|
||||||
This is a site developed to track the value of the World of Warcraft Token from various
|
This is a site developed to track the value of the World of Warcraft Classic Token from various
|
||||||
regions over time. I developed it because I wanted a quick and simple way to track the
|
regions over time. I developed it because I wanted a quick and simple way to track the
|
||||||
cost without being advertised to or tracked, and to play around with various "serverless"
|
cost without being advertised to or tracked, and to play around with various "serverless"
|
||||||
technologies. As such, my promise to you is never to use any tracking Javascript, and the
|
technologies. As such, my promise to you is never to use any tracking Javascript, and the
|
||||||
@@ -88,10 +96,10 @@
|
|||||||
</details>
|
</details>
|
||||||
<details id="what-is">
|
<details id="what-is">
|
||||||
<summary>What is the WoW Token</summary>
|
<summary>What is the WoW Token</summary>
|
||||||
The World of Warcraft Token is a first-party system developed by Blizzard to allow you
|
The World of Warcraft Classic Token is a first-party system developed by Blizzard to allow you
|
||||||
to either spend currency (local denomination or Blizzard Balance) and convert it to gold
|
to either spend currency (local denomination or Blizzard Balance) and convert it to gold
|
||||||
in retail World of Warcraft, or use gold to buy game time or Blizzard Balance. To find out
|
in classic World of Warcraft, or use gold to buy game time.
|
||||||
more, visit the support article on Blizzard's website
|
To find out more, visit the support article on Blizzard's website
|
||||||
<a href="https://us.battle.net/support/en/article/31218">here</a>.
|
<a href="https://us.battle.net/support/en/article/31218">here</a>.
|
||||||
</details>
|
</details>
|
||||||
<div id="source">
|
<div id="source">
|
||||||
|
|||||||
63
src/index.js
63
src/index.js
@@ -6,6 +6,7 @@ import fetchData from "./fetchData";
|
|||||||
import {updateHighTime} from "./highTime";
|
import {updateHighTime} from "./highTime";
|
||||||
import {updateLowTime} from "./lowTime";
|
import {updateLowTime} from "./lowTime";
|
||||||
import {addLoader, removeLoader} from "./loader";
|
import {addLoader, removeLoader} from "./loader";
|
||||||
|
import {allowOverlay, forceOverlayOff, forceOverlayOn, isOverlayAllowed, isOverlaySelected} from "./overlay";
|
||||||
import TokenChart from "./tokenChart";
|
import TokenChart from "./tokenChart";
|
||||||
import Datum from "./datum";
|
import Datum from "./datum";
|
||||||
|
|
||||||
@@ -44,11 +45,11 @@ async function updateTokens(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateRegionalToken(region, data) {
|
async function updateRegionalToken(region, data) {
|
||||||
if (currentPriceHash[region] !== data['price_data'][region]) {
|
if (currentPriceHash[region] !== data[region][1]) {
|
||||||
currentPriceHash[region] = data['price_data'][region];
|
currentPriceHash[region] = data[region][1];
|
||||||
if (region === currentRegionSelection) {
|
if (region === currentRegionSelection) {
|
||||||
formatToken();
|
formatToken();
|
||||||
datum = new Datum(Date.parse(data['update_times'][region]), data['price_data'][region]);
|
datum = new Datum(Date.parse(data[region][0]), data[region][1]);
|
||||||
if (currentAggregateSelection === 'none' && chart.active()) {
|
if (currentAggregateSelection === 'none' && chart.active()) {
|
||||||
await chart.addDataToChart(datum);
|
await chart.addDataToChart(datum);
|
||||||
}
|
}
|
||||||
@@ -66,7 +67,6 @@ async function updateRegionPreference(newRegion) {
|
|||||||
currentRegionSelection = newRegion;
|
currentRegionSelection = newRegion;
|
||||||
}
|
}
|
||||||
formatToken();
|
formatToken();
|
||||||
chart = new TokenChart();
|
|
||||||
await pullChartData();
|
await pullChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,12 @@ async function updateTimePreference(newTime) {
|
|||||||
addLoader();
|
addLoader();
|
||||||
currentTimeSelection = newTime;
|
currentTimeSelection = newTime;
|
||||||
}
|
}
|
||||||
chart = new TokenChart();
|
if (newTime === "all") {
|
||||||
|
forceOverlayOff();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
allowOverlay();
|
||||||
|
}
|
||||||
await pullChartData();
|
await pullChartData();
|
||||||
updateHighTime();
|
updateHighTime();
|
||||||
updateLowTime();
|
updateLowTime();
|
||||||
@@ -88,7 +93,6 @@ async function updateAggregatePreference(newAggregate) {
|
|||||||
addLoader();
|
addLoader();
|
||||||
currentAggregateSelection = newAggregate;
|
currentAggregateSelection = newAggregate;
|
||||||
}
|
}
|
||||||
chart = new TokenChart();
|
|
||||||
await pullChartData();
|
await pullChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,16 +113,28 @@ function toggleStartYAtZero(){
|
|||||||
chart.toggleYStart(startYAtZero);
|
chart.toggleYStart(startYAtZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function toggleOverlay() {
|
||||||
|
await chart.destroyChart();
|
||||||
|
addLoader();
|
||||||
|
await pullChartData();
|
||||||
|
}
|
||||||
|
|
||||||
async function pullChartData() {
|
async function pullChartData() {
|
||||||
chartData[currentRegionSelection] = await fetchData(currentRegionSelection, currentTimeSelection, currentAggregateSelection);
|
let timeSelection = currentTimeSelection;
|
||||||
|
if (isOverlaySelected()) {
|
||||||
|
let timeDigits = parseInt(timeSelection.slice(0, timeSelection.length - 1)) * 2;
|
||||||
|
let timeUnit = timeSelection.slice(timeSelection.length - 1);
|
||||||
|
timeSelection = `${timeDigits}${timeUnit}`;
|
||||||
|
}
|
||||||
|
chartData[currentRegionSelection] = await fetchData(currentRegionSelection, timeSelection, currentAggregateSelection);
|
||||||
if (!chart.active()) {
|
if (!chart.active()) {
|
||||||
await chart.createChart(currentRegionSelection, currentTimeSelection, startYAtZero, chartData[currentRegionSelection]);
|
await chart.createChart(currentRegionSelection, currentTimeSelection, startYAtZero, chartData[currentRegionSelection]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (let i = 0; i < chartData[currentRegionSelection].length; i++) {
|
for (let i = 0; i < chartData[currentRegionSelection].length; i++) {
|
||||||
await chart.addDataToChart(chartData[currentRegionSelection][i]);
|
await chart.addDataToChart(chartData[currentRegionSelection][i]);
|
||||||
console.warn("This should never hit, and should be okay to remove");
|
|
||||||
}
|
}
|
||||||
|
console.warn("This should never hit, and should be okay to remove");
|
||||||
}
|
}
|
||||||
removeLoader();
|
removeLoader();
|
||||||
}
|
}
|
||||||
@@ -151,6 +167,9 @@ function detectTimeQuery(urlSearchParams) {
|
|||||||
const validTimes = ['72h', '168h', '336h', '720h', '30d', '2190h', '90d', '1y', '2y', '6m', 'all'];
|
const validTimes = ['72h', '168h', '336h', '720h', '30d', '2190h', '90d', '1y', '2y', '6m', 'all'];
|
||||||
if (validTimes.includes(urlSearchParams.get('time').toLowerCase())) {
|
if (validTimes.includes(urlSearchParams.get('time').toLowerCase())) {
|
||||||
currentTimeSelection = urlSearchParams.get('time').toLowerCase();
|
currentTimeSelection = urlSearchParams.get('time').toLowerCase();
|
||||||
|
if (currentTimeSelection === 'all') {
|
||||||
|
forceOverlayOff();
|
||||||
|
}
|
||||||
let timeDDL = document.getElementById('time');
|
let timeDDL = document.getElementById('time');
|
||||||
for (let i = 0; i < timeDDL.options.length; i++) {
|
for (let i = 0; i < timeDDL.options.length; i++) {
|
||||||
if (timeDDL.options[i].value === currentTimeSelection) {
|
if (timeDDL.options[i].value === currentTimeSelection) {
|
||||||
@@ -165,9 +184,13 @@ function detectTimeQuery(urlSearchParams) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function detectAggregateQuery(urlSearchParams) {
|
function detectAggregateQuery(urlSearchParams) {
|
||||||
const validOperations = ['none', 'daily_mean'];
|
const validOperations = ['none', 'daily_mean', 'avg'];
|
||||||
if (validOperations.includes(urlSearchParams.get('aggregate').toLowerCase())) {
|
if (validOperations.includes(urlSearchParams.get('aggregate').toLowerCase())) {
|
||||||
currentAggregateSelection = urlSearchParams.get('aggregate').toLowerCase();
|
currentAggregateSelection = urlSearchParams.get('aggregate').toLowerCase();
|
||||||
|
// For backwards compatibility
|
||||||
|
if (currentAggregateSelection === 'daily_mean') {
|
||||||
|
currentAggregateSelection = 'avg';
|
||||||
|
}
|
||||||
let aggregateDDL = document.getElementById('aggregate');
|
let aggregateDDL = document.getElementById('aggregate');
|
||||||
for (let i = 0; i < aggregateDDL.options.length; i++) {
|
for (let i = 0; i < aggregateDDL.options.length; i++) {
|
||||||
if (aggregateDDL.options[i].value === currentAggregateSelection) {
|
if (aggregateDDL.options[i].value === currentAggregateSelection) {
|
||||||
@@ -189,6 +212,15 @@ function detectZeroQuery(urlSearchParams) {
|
|||||||
toggleStartYAtZero();
|
toggleStartYAtZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function detectOverlayQuery(urlSearchParams) {
|
||||||
|
const enableOverlay = urlSearchParams.get('overlay') === 'previous_time';
|
||||||
|
if (enableOverlay) {
|
||||||
|
forceOverlayOn();
|
||||||
|
} else {
|
||||||
|
forceOverlayOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function detectURLQuery() {
|
function detectURLQuery() {
|
||||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
if (urlSearchParams.has('region')) {
|
if (urlSearchParams.has('region')) {
|
||||||
@@ -203,10 +235,13 @@ function detectURLQuery() {
|
|||||||
if (urlSearchParams.has('startAtZero')) {
|
if (urlSearchParams.has('startAtZero')) {
|
||||||
detectZeroQuery(urlSearchParams)
|
detectZeroQuery(urlSearchParams)
|
||||||
}
|
}
|
||||||
|
if (urlSearchParams.has('overlay')) {
|
||||||
|
detectOverlayQuery(urlSearchParams);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDeepLinksURL() {
|
function buildDeepLinksURL() {
|
||||||
let url = "https://wowtoken.app/?"
|
let url = "https://classic.wowtoken.app/?"
|
||||||
if (currentTimeSelection !== '72h'){
|
if (currentTimeSelection !== '72h'){
|
||||||
url += `time=${currentTimeSelection}&`
|
url += `time=${currentTimeSelection}&`
|
||||||
}
|
}
|
||||||
@@ -219,6 +254,9 @@ function buildDeepLinksURL() {
|
|||||||
if (startYAtZero !== false){
|
if (startYAtZero !== false){
|
||||||
url += `startAtZero=${startYAtZero}&`
|
url += `startAtZero=${startYAtZero}&`
|
||||||
}
|
}
|
||||||
|
if (isOverlaySelected()){
|
||||||
|
url += `overlay=previous_time&`
|
||||||
|
}
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +283,8 @@ function registerEventHandles() {
|
|||||||
registerAdvancedHandlers();
|
registerAdvancedHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: These need to be moved out into probably tokenChart if not other files
|
||||||
|
|
||||||
function registerAdvancedHandlers() {
|
function registerAdvancedHandlers() {
|
||||||
document.getElementById('enable-advanced').addEventListener('change', () => {
|
document.getElementById('enable-advanced').addEventListener('change', () => {
|
||||||
toggleAdvancedSetting();
|
toggleAdvancedSetting();
|
||||||
@@ -252,6 +292,9 @@ function registerAdvancedHandlers() {
|
|||||||
document.getElementById('y-start').addEventListener('change', () => {
|
document.getElementById('y-start').addEventListener('change', () => {
|
||||||
toggleStartYAtZero();
|
toggleStartYAtZero();
|
||||||
})
|
})
|
||||||
|
document.getElementById('period-overlay').addEventListener('change', () => {
|
||||||
|
toggleOverlay();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerCopyHandlers() {
|
function registerCopyHandlers() {
|
||||||
|
|||||||
40
src/overlay.js
Normal file
40
src/overlay.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
function isOverlaySelected() {
|
||||||
|
return document.getElementById('period-overlay').checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOverlayTime() {
|
||||||
|
return document.getElementById("time").selectedOptions[0].innerText;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOverlayLabelTime() {
|
||||||
|
const currentTime = document.getElementById("time").selectedOptions[0].innerText;
|
||||||
|
let overlayTimeLabel = document.getElementById("period-time");
|
||||||
|
overlayTimeLabel.innerText = currentTime.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceOverlayOff(){
|
||||||
|
const overlaySetting = document.getElementById("period-overlay");
|
||||||
|
const periodOverlayField = document.getElementById("period-overlay-options");
|
||||||
|
overlaySetting.checked = false;
|
||||||
|
periodOverlayField.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceOverlayOn(){
|
||||||
|
const overlaySetting = document.getElementById("period-overlay");
|
||||||
|
const periodOverlayField = document.getElementById("period-overlay-options");
|
||||||
|
const advancedOptionsField = document.getElementById("advanced-options");
|
||||||
|
overlaySetting.checked = true;
|
||||||
|
advancedOptionsField.style.display = 'flex';
|
||||||
|
periodOverlayField.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOverlayAllowed(timeSelection) {
|
||||||
|
return !(timeSelection === "all")
|
||||||
|
}
|
||||||
|
|
||||||
|
function allowOverlay(){
|
||||||
|
const periodOverlayField = document.getElementById("period-overlay-options");
|
||||||
|
periodOverlayField.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
export {isOverlaySelected, getOverlayTime, setOverlayLabelTime, forceOverlayOff, forceOverlayOn, isOverlayAllowed, allowOverlay};
|
||||||
@@ -173,8 +173,8 @@ h6 {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
html {
|
html {
|
||||||
background-color: #073642;
|
background-color: #6b4233;
|
||||||
color: #839496;
|
color: #b7b7b7;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
/*body {
|
/*body {
|
||||||
@@ -194,7 +194,7 @@ a:hover {
|
|||||||
color: #cb4b16;
|
color: #cb4b16;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
color: #d33682;
|
color: #ffd5e9;
|
||||||
}
|
}
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
@@ -206,7 +206,7 @@ h6 {
|
|||||||
pre {
|
pre {
|
||||||
background-color: #002b36;
|
background-color: #002b36;
|
||||||
color: #839496;
|
color: #839496;
|
||||||
border: 1pt solid #586e75;
|
border: 1pt solid #000000;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
box-shadow: 5pt 5pt 8pt #073642;
|
box-shadow: 5pt 5pt 8pt #073642;
|
||||||
}
|
}
|
||||||
@@ -301,10 +301,10 @@ h6 {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background-color: #002b36;
|
background-color: #2f201e;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 85%;
|
max-width: 85%;
|
||||||
border: 1pt solid #586e75;
|
border: 1pt solid #000000;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,8 +341,8 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
details {
|
details {
|
||||||
background-color: #073642;
|
background-color: #6b4233;
|
||||||
border: 1px solid #aaa;
|
border: 1px solid #000000;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 0.5em 0.5em 0;
|
padding: 0.5em 0.5em 0;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
@@ -363,7 +363,7 @@ details[open] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
details[open] summary {
|
details[open] summary {
|
||||||
border-bottom: 1px solid #aaa;
|
border-bottom: 1px solid #000000;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,6 +420,16 @@ details[open] summary {
|
|||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.other-projects {
|
||||||
|
border: 1px solid silver;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.other-projects > p {
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.data-header h1 {
|
.data-header h1 {
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ Chart.register(
|
|||||||
|
|
||||||
import {updateHighVal} from "./highTime";
|
import {updateHighVal} from "./highTime";
|
||||||
import {updateLowVal} from "./lowTime";
|
import {updateLowVal} from "./lowTime";
|
||||||
|
import {isOverlaySelected, getOverlayTime, setOverlayLabelTime} from "./overlay";
|
||||||
|
import Datum from "./datum";
|
||||||
|
|
||||||
function lookupTimeUnit(query){
|
function lookupTimeUnit(query){
|
||||||
const lookup = {
|
const lookup = {
|
||||||
@@ -36,6 +38,24 @@ function lookupTimeUnit(query){
|
|||||||
return lookup[query.charAt(query.length - 1)]
|
return lookup[query.charAt(query.length - 1)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function timeDeltaInMilliseconds(time) {
|
||||||
|
let timeDigits = (parseInt(time.slice(0, time.length - 1))).toFixed(0);
|
||||||
|
let timeUnit = time.slice(time.length - 1);
|
||||||
|
|
||||||
|
switch (timeUnit) {
|
||||||
|
case 'h':
|
||||||
|
return timeDigits * (60 * 60) * 1000;
|
||||||
|
case 'd':
|
||||||
|
return timeDigits * (24 * 60 * 60) * 1000;
|
||||||
|
case 'm':
|
||||||
|
return (timeDigits * (30.437 * 24 * 60 * 60)).toFixed(0) * 1000;
|
||||||
|
case 'y':
|
||||||
|
return (timeDigits * (365.25 * 24 * 60 * 60)).toFixed(0) * 1000;
|
||||||
|
case 'l':
|
||||||
|
console.warn("This path should not happen, this warning is an error in logic")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class TokenChart {
|
export default class TokenChart {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._context = document.getElementById("token-chart").getContext('2d');
|
this._context = document.getElementById("token-chart").getContext('2d');
|
||||||
@@ -54,19 +74,116 @@ export default class TokenChart {
|
|||||||
return this._lowDatum;
|
return this._lowDatum;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createChart(region, time, yLevel, data) {
|
async #newChart(chartConfig) {
|
||||||
|
this._chart = new Chart(this._context, chartConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #updateHighLow(datum) {
|
||||||
|
if (this._highDatum === null) {
|
||||||
|
this._highDatum = new Datum(datum.getTime(), 0);
|
||||||
|
this._lowDatum = datum;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (datum.getPrice() > this._highDatum.getPrice()) {
|
||||||
|
this._highDatum = datum;
|
||||||
|
updateHighVal(this.highDatum);
|
||||||
|
}
|
||||||
|
else if (datum.getPrice() < this._lowDatum.getPrice()) {
|
||||||
|
this._lowDatum = datum;
|
||||||
|
updateLowVal(this.lowDatum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #createOverlayChart(region, time, yLevel, data){
|
||||||
const chartData = [];
|
const chartData = [];
|
||||||
let lateUpdateData = this._lastDatum;
|
const overlayData = [];
|
||||||
|
const overlayDelta = timeDeltaInMilliseconds(time);
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const originalDate = data[i].getX();
|
||||||
|
if (i < (data.length / 2)) {
|
||||||
|
overlayData.push({
|
||||||
|
x: new Date(originalDate.getTime() + overlayDelta),
|
||||||
|
y: data[i].getY(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await this.#updateHighLow(data[i]);
|
||||||
|
|
||||||
|
chartData.push({
|
||||||
|
x: data[i].getX(),
|
||||||
|
y: data[i].getY(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartConfig = {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
borderColor: 'gold',
|
||||||
|
label: region.toUpperCase() + " WoW Token Price",
|
||||||
|
data: chartData,
|
||||||
|
cubicInterpolationMode: 'monotone',
|
||||||
|
pointRadius: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
borderColor: 'red',
|
||||||
|
label: `Previous ${getOverlayTime()} ${region.toUpperCase()} WoW Token Price`,
|
||||||
|
data: overlayData,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.#newChart(chartConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
async #createNormalChart(region, time, yLevel, data) {
|
||||||
|
const chartData = [];
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
this._lastDatum = data[i];
|
this._lastDatum = data[i];
|
||||||
if (this._highDatum === null || this._lastDatum.getPrice() > this._highDatum.getPrice()) {
|
await this.#updateHighLow(data[i]);
|
||||||
this._highDatum = data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._lowDatum === null || this._lowDatum.getPrice() > this._lastDatum.getPrice()) {
|
|
||||||
this._lowDatum = data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
chartData.push({
|
chartData.push({
|
||||||
x: data[i].getX(),
|
x: data[i].getX(),
|
||||||
@@ -74,10 +191,7 @@ export default class TokenChart {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHighVal(this.highDatum);
|
const chartConfig = {
|
||||||
updateLowVal(this.lowDatum);
|
|
||||||
|
|
||||||
this._chart = new Chart(this._context, {
|
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
@@ -123,7 +237,25 @@ export default class TokenChart {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
await this.#newChart(chartConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createChart(region, time, yLevel, data) {
|
||||||
|
let lateUpdateData = this._lastDatum;
|
||||||
|
|
||||||
|
if (isOverlaySelected()) {
|
||||||
|
await this.#createOverlayChart(region, time, yLevel, data)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await this.#createNormalChart(region, time, yLevel, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
setOverlayLabelTime();
|
||||||
|
|
||||||
|
updateHighVal(this.highDatum);
|
||||||
|
updateLowVal(this.lowDatum);
|
||||||
|
|
||||||
if (this._lateUpdate) {
|
if (this._lateUpdate) {
|
||||||
if (this._lastDatum.getPrice() !== lateUpdateData.getPrice() &&
|
if (this._lastDatum.getPrice() !== lateUpdateData.getPrice() &&
|
||||||
@@ -160,11 +292,9 @@ export default class TokenChart {
|
|||||||
this._lowDatum = datum;
|
this._lowDatum = datum;
|
||||||
updateLowVal(this.lowDatum);
|
updateLowVal(this.lowDatum);
|
||||||
}
|
}
|
||||||
this._chart.data.datasets.forEach((dataset) => {
|
this._chart.data.datasets[0].data.push({
|
||||||
dataset.data.push({
|
x: datum.getX(),
|
||||||
x: datum.getX(),
|
y: datum.getY(),
|
||||||
y: datum.getY(),
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
this._chart.update();
|
this._chart.update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
export default function urlBuilder(currentRegionSelection, currentTimeSelection, currentAggregateSelection) {
|
export default function urlBuilder(currentRegionSelection, currentTimeSelection, currentAggregateSelection) {
|
||||||
let url = "https://data.wowtoken.app/token/history/";
|
let url = "https://data.wowtoken.app/v2/";
|
||||||
if (currentAggregateSelection !== 'none') {
|
if (currentAggregateSelection !== '' && currentAggregateSelection !== 'none'){
|
||||||
url += `${currentAggregateSelection}/`
|
url += `math/${currentAggregateSelection}/classic/`
|
||||||
}
|
}
|
||||||
url += `${currentRegionSelection}/${currentTimeSelection}.json`
|
else {
|
||||||
|
url += `relative/classic/`
|
||||||
|
}
|
||||||
|
|
||||||
|
url += `${currentRegionSelection}/${currentTimeSelection}.json`;
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user