diff --git a/src/fetchData.js b/src/fetchData.js index 395b1c2..ac57677 100644 --- a/src/fetchData.js +++ b/src/fetchData.js @@ -6,7 +6,7 @@ export default async function fetchData(currentRegionSelection, currentTimeSelec 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][0]), respData[i][1]); + const datum = new Datum(new Date(respData[i][0]), respData[i][1]); data.push(datum); } return data; diff --git a/src/index.html b/src/index.html index ffd26d0..5a0c4a6 100644 --- a/src/index.html +++ b/src/index.html @@ -62,6 +62,12 @@ +
+ + +
diff --git a/src/index.js b/src/index.js index 3263aaa..51c0e53 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import fetchData from "./fetchData"; import {updateHighTime} from "./highTime"; import {updateLowTime} from "./lowTime"; import {addLoader, removeLoader} from "./loader"; +import {allowOverlay, forceOverlayOff, isOverlaySelected} from "./overlay"; import TokenChart from "./tokenChart"; import Datum from "./datum"; @@ -66,7 +67,6 @@ async function updateRegionPreference(newRegion) { currentRegionSelection = newRegion; } formatToken(); - chart = new TokenChart(); await pullChartData(); } @@ -76,7 +76,12 @@ async function updateTimePreference(newTime) { addLoader(); currentTimeSelection = newTime; } - chart = new TokenChart(); + if (newTime === "all") { + forceOverlayOff(); + } + else { + allowOverlay(); + } await pullChartData(); updateHighTime(); updateLowTime(); @@ -88,7 +93,6 @@ async function updateAggregatePreference(newAggregate) { addLoader(); currentAggregateSelection = newAggregate; } - chart = new TokenChart(); await pullChartData(); } @@ -109,16 +113,28 @@ function toggleStartYAtZero(){ chart.toggleYStart(startYAtZero); } +async function toggleOverlay() { + await chart.destroyChart(); + addLoader(); + await 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()) { await chart.createChart(currentRegionSelection, currentTimeSelection, startYAtZero, chartData[currentRegionSelection]); } else { for (let i = 0; i < chartData[currentRegionSelection].length; 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(); } @@ -151,6 +167,9 @@ function detectTimeQuery(urlSearchParams) { const validTimes = ['72h', '168h', '336h', '720h', '30d', '2190h', '90d', '1y', '2y', '6m', 'all']; if (validTimes.includes(urlSearchParams.get('time').toLowerCase())) { currentTimeSelection = urlSearchParams.get('time').toLowerCase(); + if (currentTimeSelection === 'all') { + forceOverlayOff(); + } let timeDDL = document.getElementById('time'); for (let i = 0; i < timeDDL.options.length; i++) { if (timeDDL.options[i].value === currentTimeSelection) { @@ -249,6 +268,8 @@ function registerEventHandles() { registerAdvancedHandlers(); } +// TODO: These need to be moved out into probably tokenChart if not other files + function registerAdvancedHandlers() { document.getElementById('enable-advanced').addEventListener('change', () => { toggleAdvancedSetting(); @@ -256,6 +277,9 @@ function registerAdvancedHandlers() { document.getElementById('y-start').addEventListener('change', () => { toggleStartYAtZero(); }) + document.getElementById('period-overlay').addEventListener('change', () => { + toggleOverlay(); + }) } function registerCopyHandlers() { diff --git a/src/overlay.js b/src/overlay.js new file mode 100644 index 0000000..9300a98 --- /dev/null +++ b/src/overlay.js @@ -0,0 +1,27 @@ +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 allowOverlay(){ + const periodOverlayField = document.getElementById("period-overlay-options"); + periodOverlayField.style.display = 'flex'; +} + +export {isOverlaySelected, getOverlayTime, setOverlayLabelTime, forceOverlayOff, allowOverlay}; \ No newline at end of file diff --git a/src/tokenChart.js b/src/tokenChart.js index ecee38f..97edbe2 100644 --- a/src/tokenChart.js +++ b/src/tokenChart.js @@ -24,6 +24,7 @@ Chart.register( import {updateHighVal} from "./highTime"; import {updateLowVal} from "./lowTime"; +import {isOverlaySelected, getOverlayTime, setOverlayLabelTime} from "./overlay"; function lookupTimeUnit(query){ const lookup = { @@ -36,6 +37,24 @@ function lookupTimeUnit(query){ 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 { constructor() { this._context = document.getElementById("token-chart").getContext('2d'); @@ -54,9 +73,104 @@ export default class TokenChart { return this._lowDatum; } - async createChart(region, time, yLevel, data) { + async #newChart(chartConfig) { + this._chart = new Chart(this._context, chartConfig); + } + + async #createOverlayChart(region, time, yLevel, data){ 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 { + + this._lastDatum = data[i]; + if (this._highDatum === null || this._lastDatum.getPrice() > this._highDatum.getPrice()) { + this._highDatum = data[i]; + } + + if (this._lowDatum === null || this._lowDatum.getPrice() > this._lastDatum.getPrice()) { + this._lowDatum = 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++) { this._lastDatum = data[i]; @@ -74,10 +188,7 @@ export default class TokenChart { }) } - updateHighVal(this.highDatum); - updateLowVal(this.lowDatum); - - this._chart = new Chart(this._context, { + const chartConfig = { type: 'line', data: { datasets: [{ @@ -123,7 +234,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._lastDatum.getPrice() !== lateUpdateData.getPrice() && @@ -160,12 +289,7 @@ export default class TokenChart { this._lowDatum = datum; updateLowVal(this.lowDatum); } - this._chart.data.datasets.forEach((dataset) => { - dataset.data.push({ - x: datum.getX(), - y: datum.getY(), - }) - }); + this._chart.data.datasets[0].data.push(datum); this._chart.update(); }