Compare commits

24 Commits

Author SHA1 Message Date
1e0b4a0a1f Make time and cost delineation more apparent 2024-04-25 00:17:09 -07:00
17ffbc3db1 Enabled the option to start Y at zero 2024-04-24 23:54:03 -07:00
0c9e7ed183 Change the timescale legend to be more readable instead of dense 2024-04-12 05:27:41 -07:00
4a7c03307d Change logs to warnings, since that's what they really are 2024-04-12 05:06:41 -07:00
0e40f403e4 Increase font size and brightness for better contrast 2024-04-12 05:04:33 -07:00
66ab042995 Changes to advanced options and styling in prep for future work 2023-10-15 01:16:38 -07:00
8cd9a2ddeb Remove Cash dependency, refactor event registration 2023-09-10 13:00:47 -07:00
702ca8c4d3 Update dependencies 2023-09-10 12:53:12 -07:00
c1b05851a4 Add link to classic token 2023-05-23 19:33:41 -07:00
86555f5983 Fix non-minimized JS 2023-05-21 06:54:25 -07:00
aab8a9cd12 Move to using hashed CSS files too 2023-05-20 03:02:08 -07:00
7df594f22a Add ability to generate deeplinks URL for chart 2023-05-06 16:50:55 -07:00
be4678eab1 Use hashed bundle name for better caching and invalidation 2023-05-06 15:43:36 -07:00
5c80316d89 Version bump packages 2023-05-06 14:43:31 -07:00
69cd58e487 Bump node build version to match new AWS Builder 2023-03-04 15:50:48 -08:00
4ce5481fd0 Correct build rule to include production mode
Not that it wasn't building in production before, but this means it no longer warns it's using the default values
2023-03-04 15:48:02 -08:00
25e9353f22 Add aggregate to URL params and bug fixes 2023-03-04 15:47:06 -08:00
543b9ba9d2 Added new aggregate functions feature 2023-02-19 17:44:59 -08:00
71b38778f1 Added 'details' sections to provide more information about the site 2023-02-12 03:01:03 -08:00
6379803a45 Made the external data requests parallel 2023-02-09 00:17:35 -08:00
11a3fd7fff Adjusted selection dropdowns to be more compact 2023-02-09 00:17:13 -08:00
e0b6ea9f8e Added devel webpack build job 2023-02-09 00:16:27 -08:00
b92f24739b Update About and Source to point at new landing page 2022-12-11 17:06:51 -08:00
23ca3cbcef Syles loader to no take mess with content-paint 2022-12-11 16:01:38 -08:00
8 changed files with 2404 additions and 1595 deletions

View File

@@ -2,6 +2,6 @@
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 CodePipline, built via CodeBuild, and deployed. This project gets picked up by CodePipeline, built via CodeBuild, and deployed.
![Build Status](https://codebuild.us-east-1.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiblpRUnlNUzVmNU9sK1VBRVl1bVI1U1ZrWHJFSDVPYjFpTC9WVzZuSk1hd0lsUU5NekdDZTl4M2t4Uy9EWFdaY3JSNU1mYTFtaVI0VXN6ZGQvNE9BUWpvPSIsIml2UGFyYW1ldGVyU3BlYyI6InZNcHhHanNTODQ0b2lwbkkiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=main) ![Build Status](https://codebuild.us-east-1.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiblpRUnlNUzVmNU9sK1VBRVl1bVI1U1ZrWHJFSDVPYjFpTC9WVzZuSk1hd0lsUU5NekdDZTl4M2t4Uy9EWFdaY3JSNU1mYTFtaVI0VXN6ZGQvNE9BUWpvPSIsIml2UGFyYW1ldGVyU3BlYyI6InZNcHhHanNTODQ0b2lwbkkiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=main)

View File

@@ -3,7 +3,7 @@ version: 0.2
phases: phases:
install: install:
runtime-versions: runtime-versions:
nodejs: 14 nodejs: 16
commands: commands:
- echo Installing dependencies... - echo Installing dependencies...
- npm install - npm install

3353
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,16 +4,20 @@
"private": true, "private": true,
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack && mkdir -p dist && cp src/robots.txt src/index.html src/style.css src/favicon.ico dist/" "build": "webpack --mode production && mkdir -p dist && cp src/robots.txt src/style.css src/favicon.ico dist/",
"build-dev": "webpack --mode development && mkdir -p dist && cp src/robots.txt src/style.css src/favicon.ico dist/"
}, },
"devDependencies": { "devDependencies": {
"css-loader": "^6.7.4",
"html-webpack-plugin": "^5.5.1",
"mini-css-extract-plugin": "^2.7.6",
"webpack": "^5.73.0", "webpack": "^5.73.0",
"webpack-cli": "^4.7.2" "webpack-cli": "^4.7.2"
}, },
"dependencies": { "dependencies": {
"cash-dom": "^8.1.2", "chart.js": "^4.4.0",
"chart.js": "^4.0.1",
"chartjs-adapter-dayjs-3": "^1.2.3", "chartjs-adapter-dayjs-3": "^1.2.3",
"dayjs": "^1.11.6" "css-minimizer-webpack-plugin": "^5.0.0",
"dayjs": "^1.11.7"
} }
} }

View File

@@ -5,12 +5,10 @@
<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) 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="stylesheet" href="style.css">
<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/token/current.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/token/history/us/72h.json" as="fetch" type="application/json" crossorigin="anonymous">
<script src="bundle.js"></script>
</head> </head>
<body> <body>
<div class="flex-container"> <div class="flex-container">
@@ -19,32 +17,92 @@
<div class="lds-ripple" id="loader"><div></div><div></div></div> <div class="lds-ripple" id="loader"><div></div><div></div></div>
<canvas id="token-chart"></canvas> <canvas id="token-chart"></canvas>
<div id="option_select"> <div id="option_select">
<label for="region">Region:</label> <fieldset id="basic-options">
<select name="region" id="region"> <legend>Basic chart options</legend>
<option value="us">US</option> <div>
<option value="eu">EU</option> <label for="region">Region:</label>
<option value="kr">KR</option> <select name="region" id="region">
<option value="tw">TW</option> <option value="us">US</option>
</select> <option value="eu">EU</option>
<br /> <option value="kr">KR</option>
<label for="time">Time Selection:</label> <option value="tw">TW</option>
<select name="time" id="time"> </select>
<option value="72h">3 Days</option> </div>
<option value="168h">7 Days</option> <div>
<option value="336h">14 Days</option> <label for="time">Time Selection:</label>
<option value="720h">1 Month</option> <select name="time" id="time">
<option value="90d">3 Months</option> <option value="72h">3 Days</option>
<option value="6m">6 Months</option> <option value="168h">7 Days</option>
<option value="1y">1 Year</option> <option value="336h">14 Days</option>
<option value="2y">2 Years</option> <option value="720h">1 Month</option>
<option value="all">All Available</option> <option value="90d">3 Months</option>
</select> <option value="6m">6 Months</option>
<option value="1y">1 Year</option>
<option value="2y">2 Years</option>
<option value="all">All Available</option>
</select>
</div>
<div>
<label for="enable-advanced">Enable advanced charting options:</label>
<input type="checkbox" id="enable-advanced" name="enable-advanced" />
</div>
</fieldset>
<fieldset id="advanced-options">
<legend>Advanced chart options</legend>
<fieldset id="advanced-region-options">
<legend>Multi-Region Selection</legend>
<label for="adv-r-us">US:</label>
<input type="checkbox" id="adv-r-us" name="adv-r-us" value="enable" disabled />
<label for="adv-r-eu">EU:</label>
<input type="checkbox" id="adv-r-eu" name="adv-r-eu" value="enable" disabled />
<label for="adv-r-kr">KR:</label>
<input type="checkbox" id="adv-r-kr" name="adv-r-kr" value="enable" disabled />
<label for="adv-r-tw">TW:</label>
<input type="checkbox" id="adv-r-tw" name="adv-r-tw" value="enable" disabled/>
</fieldset>
<fieldset id="basic-smoothing">
<label for="aggregate">Smoothing Function:</label>
<select name="aggregate" id="aggregate">
<option id='agg_none' value="none">None</option>
<option id='agg_davg' value="daily_mean">Daily Average</option>
<option id='agg_wavg' value="weekly_mean" disabled>Weekly Average</option>
</select>
</fieldset>
<fieldset id="y-start-options">
<label for="y-start">Start y-axis at 0:</label>
<input type="checkbox" id="y-start" name="y-start"/>
</fieldset>
</fieldset>
<div class="tooltip">
<button id="copyURLButton">
<span class="tooltiptext" id="urlTooltip">Copy to clipboard</span>
Copy URL to this Chart
</button>
</div>
<div>
<p><em>Looking for the classic WoW Token price? Find it <a href="https://classic.wowtoken.app">here!</a></em></p>
</div>
</div> </div>
<details id="about">
<summary>About this Site</summary>
This is a site developed to track the value of the World of Warcraft Token from various
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"
technologies. As such, my promise to you is never to use any tracking Javascript, and the
only logging is for debugging purposes of the backend - which does not get IPs.
</details>
<details id="what-is">
<summary>What is the WoW Token</summary>
The World of Warcraft 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
in retail World of Warcraft, or use gold to buy game time or Blizzard Balance. To find out
more, visit the support article on Blizzard's website
<a href="https://us.battle.net/support/en/article/31218">here</a>.
</details>
<div id="source"> <div id="source">
<p> <p>
<a href="https://github.com/sneaky-emily/wowtoken.app">Source</a> <a href="https://blog.emily.sh/wowtoken-app/">Source</a>
|
<a href="https://blog.emily.sh/2021/04/developing-a-simple-wow-token-tracker/">About</a>
</p> </p>
</div> </div>
</div> </div>

View File

@@ -1,17 +1,18 @@
import { import {
Chart, Chart,
Legend,
LinearScale,
LineController,
LineElement, LineElement,
PointElement, PointElement,
LineController,
LinearScale,
TimeSeriesScale, TimeSeriesScale,
Legend,
Title, Title,
Tooltip Tooltip
} from 'chart.js'; } from 'chart.js';
import $ from 'cash-dom';
import 'chartjs-adapter-dayjs-3'; import 'chartjs-adapter-dayjs-3';
import "./style.css"
// TODO: This file should be seperated into multiple with better ownership
Chart.register( Chart.register(
LineElement, LineElement,
@@ -24,28 +25,50 @@ Chart.register(
Tooltip Tooltip
) )
let current_region_selection = '' let currentRegionSelection = '';
let current_time_selection = '' let currentTimeSelection = '';
const current_price_hash = { let currentAggregateSelection = '';
let startYAtZero = false;
const currentPriceHash = {
us: 0, us: 0,
eu: 0, eu: 0,
kr: 0, kr: 0,
tw: 0 tw: 0
};
let chartData = {
us: [],
eu: [],
kr: [],
tw: []
} }
let chart_js_data; let chartOptions = {
us: {
color: 'gold'
},
eu: {
color: 'red'
},
kr: {
color: 'white'
},
tw: {
color: 'pink'
}
}
let chartJsData;
let ctx; let ctx;
let token_chart; let tokenChart;
function populateChart() { function populateChart() {
ctx = document.getElementById("token-chart").getContext('2d'); ctx = document.getElementById("token-chart").getContext('2d');
token_chart = new Chart(ctx, { tokenChart = new Chart(ctx, {
type: 'line', type: 'line',
data: { data: {
datasets: [{ datasets: [{
borderColor: 'gold', borderColor: 'gold',
label: current_region_selection.toUpperCase() + " WoW Token Price", label: currentRegionSelection.toUpperCase() + " WoW Token Price",
data: chart_js_data, data: chartJsData,
cubicInterpolationMode: 'monotone', cubicInterpolationMode: 'monotone',
pointRadius: 0 pointRadius: 0
}] }]
@@ -57,13 +80,48 @@ function populateChart() {
}, },
scales: { scales: {
x: { x: {
type: 'time' type: 'time',
grid: {
color: '#625f62',
},
ticks: {
color: '#a7a4ab',
font: {
size: 18,
}
},
time: {
unit: lookupTimeUnit(currentTimeSelection)
}
},
y: {
beginAtZero: startYAtZero,
grid: {
color: '#2f2c2f',
},
ticks: {
color: '#a7a4ab',
font: {
size: 18,
}
}
} }
}, },
} }
}); });
} }
function lookupTimeUnit(query){
const lookup = {
'h': 'day',
'd': 'week',
'm': 'month',
'y': 'month',
'l': 'year'
}
return lookup[query.charAt(query.length - 1)]
}
async function callUpdateURL() { async function callUpdateURL() {
let resp = await fetch("https://data.wowtoken.app/token/current.json"); let resp = await fetch("https://data.wowtoken.app/token/current.json");
@@ -79,22 +137,43 @@ function updateTokens(data) {
} }
function updateRegionalToken(region, data) { function updateRegionalToken(region, data) {
if (current_price_hash[region] !== data['price_data'][region]) { if (currentPriceHash[region] !== data['price_data'][region]) {
current_price_hash[region] = data['price_data'][region]; currentPriceHash[region] = data['price_data'][region];
if (region === current_region_selection) { if (region === currentRegionSelection) {
formatToken(); formatToken();
add_data_to_chart(region, data); if (currentAggregateSelection === 'none') {
addDataToChart(region, data);
}
} }
} }
} }
function add_data_to_chart(region, data) { function addDataToChart(region, data) {
if (token_chart) { if (tokenChart) {
const datum = {x: data['current_time'], y: data['price_data'][region]} const datum = {x: data['current_time'], y: data['price_data'][region]}
token_chart.data.datasets.forEach((dataset) => { tokenChart.data.datasets.forEach((dataset) => {
dataset.data.push(datum); dataset.data.push(datum);
}) })
token_chart.update(); tokenChart.update();
}
}
async function aggregateFunctionToggle() {
// TODO: We should probably make these global or something
// so if the need to be updated in the future we can do so easily
const smallTimes = ['72h', '168h', '336h'];
const longTimes = ['720h', '30d', '2190h', '90d', '1y', '2y', '6m', 'all'];
const idsToModify = ['agg_wavg']
if (smallTimes.includes(currentTimeSelection)) {
for (const id of idsToModify) {
let ele = document.getElementById(id);
ele.disabled = true;
}
} else if (longTimes.includes(currentTimeSelection)) {
for (const id of idsToModify) {
let ele = document.getElementById(id);
ele.disabled = false;
}
} }
} }
@@ -119,97 +198,237 @@ function removeLoader () {
} }
} }
export function updateRegionPreference(newRegion) { function updateRegionPreference(newRegion) {
if (newRegion !== current_region_selection) { if (newRegion !== currentRegionSelection) {
token_chart.destroy(); tokenChart.destroy();
addLoader(); addLoader();
current_region_selection = newRegion; currentRegionSelection = newRegion;
} }
formatToken(); formatToken();
pullChartData().then(populateChart); pullChartData().then(populateChart);
} }
export function updateTimePreference(newTime) { function updateTimePreference(newTime) {
if (newTime !== current_time_selection) { if (newTime !== currentTimeSelection) {
token_chart.destroy(); tokenChart.destroy();
addLoader(); addLoader();
current_time_selection = newTime; currentTimeSelection = newTime;
aggregateFunctionToggle();
} }
pullChartData().then(populateChart); pullChartData().then(populateChart);
} }
function updateAggregatePreference(newAggregate) {
if (newAggregate !== currentAggregateSelection) {
tokenChart.destroy();
addLoader();
currentAggregateSelection = newAggregate;
}
pullChartData().then(populateChart);
}
function toggleAdvancedSetting() {
let element = document.getElementById('advanced-options')
if (document.getElementById('enable-advanced').checked)
{
element.style.display = 'flex';
}
else
{
element.style.display = 'none';
}
}
function toggleStartYAtZero(){
startYAtZero = document.getElementById('y-start').checked;
if (tokenChart){
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("https://data.wowtoken.app/token/history/" + current_region_selection + "/" + current_time_selection + ".json"); let resp = await fetch(urlBuilder());
let chart_data = await resp.json(); let chartData = await resp.json();
let new_chart_js_data = []; let newChartJSData = [];
for (let i = 0; i < chart_data.length; i++) { for (let i = 0; i < chartData.length; i++) {
let datum = { let datum = {
x: chart_data[i]['time'], x: chartData[i]['time'],
y: chart_data[i]['value'] y: chartData[i]['value']
}; };
new_chart_js_data.push(datum); newChartJSData.push(datum);
} }
chart_js_data = new_chart_js_data; chartJsData = newChartJSData;
removeLoader(); removeLoader();
} }
async function updateChartData() {
token_chart.destroy();
pullChartData().then(populateChart);
}
function formatToken() { function formatToken() {
$("#token").html(current_price_hash[current_region_selection].toLocaleString()); document.getElementById("token").innerText = currentPriceHash[currentRegionSelection].toLocaleString();
} }
function detectURLQuery() { // TODO: These maybe able to be collapsed into a single function with params or a lambda
const urlSearchParams = new URLSearchParams(window.location.search)
const allowedRegions = ['us', 'eu', 'tw', 'kr'] function detectRegionQuery(urlSearchParams) {
if (urlSearchParams.has('region')) { const validRegions = ['us', 'eu', 'tw', 'kr'];
if (allowedRegions.includes(urlSearchParams.get('region').toLowerCase())) { if (validRegions.includes(urlSearchParams.get('region').toLowerCase())) {
current_region_selection = urlSearchParams.get('region').toLowerCase() currentRegionSelection = urlSearchParams.get('region').toLowerCase();
let region_ddl = document.getElementById('region') let regionDDL = document.getElementById('region');
for (let i = 0; i < region_ddl.options.length; i++){ for (let i = 0; i < regionDDL.options.length; i++) {
if (region_ddl.options[i].value === current_region_selection) { if (regionDDL.options[i].value === currentRegionSelection) {
region_ddl.options[i].selected = true; regionDDL.options[i].selected = true;
}
} }
} else {
console.log("An incorrect or malformed region selection was made in the query string")
} }
} else {
console.warn("An incorrect or malformed region selection was made in the query string");
} }
}
function detectTimeQuery(urlSearchParams) {
// In the future, we will allow all the times to be selected, // In the future, we will allow all the times to be selected,
// once I come up with a good reduction algorithm. // once I come up with a good reduction algorithm.
// For larger time selections, it's currently hardcoded into the backend // For larger time selections, it's currently hardcoded into the backend
const validTimes = ['72h', '168h', '336h', '720h', '30d', '90d', '1y', '2y', '6m', 'all']; const validTimes = ['72h', '168h', '336h', '720h', '30d', '2190h', '90d', '1y', '2y', '6m', 'all'];
if (urlSearchParams.has('time')) { if (validTimes.includes(urlSearchParams.get('time').toLowerCase())) {
if (validTimes.includes(urlSearchParams.get('time').toLowerCase())) { currentTimeSelection = urlSearchParams.get('time').toLowerCase();
current_time_selection = urlSearchParams.get('time').toLowerCase(); let timeDDL = document.getElementById('time');
let time_ddl = document.getElementById('time') for (let i = 0; i < timeDDL.options.length; i++) {
for (let i = 0; i < time_ddl.options.length; i++){ if (timeDDL.options[i].value === currentTimeSelection) {
if (time_ddl.options[i].value === current_time_selection) { timeDDL.options[i].selected = true;
time_ddl.options[i].selected = true;
}
} }
} else {
console.log("An incorrect or malformed time selection was made in the query string");
} }
} else {
console.warn("An incorrect or malformed time selection was made in the query string");
} }
} }
function detectAggregateQuery(urlSearchParams) {
const validOperations = ['none', 'daily_mean', 'weekly_mean'];
if (validOperations.includes(urlSearchParams.get('aggregate').toLowerCase())) {
currentAggregateSelection = urlSearchParams.get('aggregate').toLowerCase();
let aggregateDDL = document.getElementById('aggregate');
for (let i = 0; i < aggregateDDL.options.length; i++) {
if (aggregateDDL.options[i].value === currentAggregateSelection) {
aggregateDDL.options[i].selected = true;
}
}
aggregateFunctionToggle();
} else {
console.warn("An incorrect or malformed aggregate selection was made in the query string");
}
}
$(document).ready(function() { function detectZeroQuery(urlSearchParams) {
startYAtZero = urlSearchParams.get('startAtZero') === 'true';
let advOptions = document.getElementById('enable-advanced');
let startAtZeroOption = document.getElementById('y-start');
advOptions.checked = startYAtZero;
startAtZeroOption.checked = startYAtZero;
toggleAdvancedSetting();
toggleStartYAtZero();
}
function detectURLQuery() {
const urlSearchParams = new URLSearchParams(window.location.search);
if (urlSearchParams.has('region')) {
detectRegionQuery(urlSearchParams);
}
if (urlSearchParams.has('time')) {
detectTimeQuery(urlSearchParams);
}
if (urlSearchParams.has('aggregate')) {
detectAggregateQuery(urlSearchParams);
}
if (urlSearchParams.has('startAtZero')) {
detectZeroQuery(urlSearchParams)
}
}
function buildDeepLinksURL() {
let url = "https://wowtoken.app/?"
if (currentTimeSelection !== '72h'){
url += `time=${currentTimeSelection}&`
}
if (currentRegionSelection !== 'us'){
url += `region=${currentRegionSelection}&`
}
if (currentAggregateSelection !== '' && currentAggregateSelection !== 'none'){
url += `aggregate=${currentAggregateSelection}&`
}
if (startYAtZero !== false){
url += `startAtZero=${startYAtZero}&`
}
return url
}
function copyURL() {
let toolTip = document.getElementById('urlTooltip');
navigator.clipboard.writeText(buildDeepLinksURL()).then(
() => {
toolTip.innerHTML= "Copied the URL";
},
() => {
toolTip.innerHTML = "Unable to copy URL to clipboard";
}
);
}
function toolTipMouseOut() {
let tooltip = document.getElementById("urlTooltip");
tooltip.innerHTML = "Copy to clipboard";
}
function registerEventHandles() {
registerCopyHandlers();
registerOptionHandlers();
registerAdvancedHandlers();
}
function registerAdvancedHandlers() {
document.getElementById('enable-advanced').addEventListener('change', () => {
toggleAdvancedSetting();
})
document.getElementById('y-start').addEventListener('change', () => {
toggleStartYAtZero();
})
}
function registerCopyHandlers() {
document.getElementById('copyURLButton').addEventListener('click', function () {
copyURL();
})
document.getElementById('copyURLButton').addEventListener('mouseout', function () {
toolTipMouseOut();
})
}
function registerOptionHandlers() {
document.getElementById('region').addEventListener('change', function() { document.getElementById('region').addEventListener('change', function() {
updateRegionPreference(this.value); updateRegionPreference(this.value);
}); });
current_region_selection = document.getElementById('region').value; currentRegionSelection = document.getElementById('region').value;
document.getElementById('time').addEventListener('change', function() { document.getElementById('time').addEventListener('change', function() {
updateTimePreference(this.value); updateTimePreference(this.value);
}); });
current_time_selection = document.getElementById('time').value; currentTimeSelection = document.getElementById('time').value;
detectURLQuery(); document.getElementById('aggregate').addEventListener('change', function () {
callUpdateURL(); updateAggregatePreference(this.value);
setInterval(callUpdateURL, 60*1000); })
pullChartData().then(populateChart); currentAggregateSelection = document.getElementById('aggregate').value;
}); }
document.addEventListener('DOMContentLoaded', function () {
registerEventHandles();
detectURLQuery();
Promise.all([callUpdateURL(), pullChartData()]).then(populateChart)
setInterval(callUpdateURL, 60*1000);
}, false);

View File

@@ -137,9 +137,6 @@ input[type="radio"] {
padding: 0; padding: 0;
} }
input[type="search"] { input[type="search"] {
-webkit-appearance: textfield;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box; box-sizing: content-box;
} }
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-cancel-button,
@@ -318,15 +315,74 @@ h6 {
line-height: 75px; line-height: 75px;
font-size: 30px; font-size: 30px;
} }
.adv-options-container {
display: flex;
padding: 20px;
flex-flow: row wrap;
align-items: center;
justify-content: space-around;
}
.box > div {
border: solid #bfbdbf;
border-radius: 40px;
padding: 20px;
margin: 20px;
width: 200px;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
p { p {
margin: 0px; margin: 0;
padding: 0px; padding: 0;
line-height: 3em; line-height: 3em;
} }
details {
background-color: #073642;
border: 1px solid #aaa;
border-radius: 4px;
padding: 0.5em 0.5em 0;
font-size: 17px;
line-height: 1.5em;
margin: .5em 5vw;
}
details > summary {
color: #aaaaaa;
cursor: pointer;
font-weight: bold;
margin: -0.5em -0.5em 0;
padding: 0.5em;
}
details[open] {
padding: 0.5em;
}
details[open] summary {
border-bottom: 1px solid #aaa;
margin-bottom: 0.5em;
}
#option_select { #option_select {
font-size: 20px; font-size: 20px;
line-height: 40px;
display: flex;
flex-direction: column;
align-items: center;
align-content: center;
}
#option_select > div {
padding: 10px;
}
#option_select > fieldset {
padding-bottom: 20px;
max-width: fit-content;
} }
#token { #token {
@@ -352,12 +408,23 @@ p {
flex-direction: column; flex-direction: column;
} }
#advanced-options {
display: none;
flex-direction: column;
align-items: center;
align-content: center;
}
#advanced-options > fieldset {
margin: 10px;
}
.lds-ripple { .lds-ripple {
position: relative; position: relative;
align-self: center; align-self: center;
width: 80px; width: 80px;
height: 80px; height: 80px;
margin-bottom: -80px;
} }
.lds-ripple div { .lds-ripple div {
position: absolute; position: absolute;
@@ -369,6 +436,44 @@ p {
.lds-ripple div:nth-child(2) { .lds-ripple div:nth-child(2) {
animation-delay: -0.5s; animation-delay: -0.5s;
} }
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 280px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 80%;
left: -15%;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
@keyframes lds-ripple { @keyframes lds-ripple {
0% { 0% {
top: 36px; top: 36px;
@@ -392,8 +497,8 @@ p {
opacity: 1; opacity: 1;
} }
100% { 100% {
top: 0px; top: 0;
left: 0px; left: 0;
width: 72px; width: 72px;
height: 72px; height: 72px;
opacity: 0; opacity: 0;

View File

@@ -1,10 +1,38 @@
const path = require('path'); const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = { module.exports = {
entry: './src/index.js', entry: './src/index.js',
module: {
rules: [
{
test: /.s?css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
optimization: {
minimize: true,
minimizer: [
`...`,
new CssMinimizerPlugin(),
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
}),
new HtmlWebpackPlugin({
template: "src/index.html"
}),
],
output: { output: {
filename: 'bundle.js', filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
libraryTarget: 'window', libraryTarget: 'window',
clean: true,
}, },
}; };