You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ac-nh-turnip-prices/js/scripts.js

387 lines
10 KiB
JavaScript

//Reusable Fields
const getSellFields = function () {
let fields = []
for (var i = 2; i < 14; i++) {
fields.push($("#sell_" + i)[0])
}
return fields
}
const getFirstBuyRadios = function () {
return [
$("#first-time-radio-no")[0],
$("#first-time-radio-yes")[0]
];
}
const getPreviousPatternRadios = function () {
return [
$("#pattern-radio-unknown")[0],
$("#pattern-radio-fluctuating")[0],
$("#pattern-radio-small-spike")[0],
$("#pattern-radio-large-spike")[0],
$("#pattern-radio-decreasing")[0]
];
}
const getCheckedRadio = function (radio_array) {
return radio_array.find(radio => radio.checked === true).value;
}
const checkRadioByValue = function (radio_array, value) {
if (value === null) {
return;
}
value = value.toString();
radio_array.find(radio => radio.value == value).checked = true;
}
const sell_inputs = getSellFields()
const buy_input = $("#buy")
const first_buy_radios = getFirstBuyRadios()
const previous_pattern_radios = getPreviousPatternRadios()
const permalink_input = $('#permalink-input')
const permalink_button = $('#permalink-btn')
const snackbar = $('#snackbar')
//Functions
const fillFields = function (prices, first_buy, previous_pattern) {
checkRadioByValue(first_buy_radios, first_buy);
checkRadioByValue(previous_pattern_radios, previous_pattern);
buy_input.focus();
buy_input.val(prices[0] || '')
buy_input.blur();
const sell_prices = prices.slice(2)
sell_prices.forEach((price, index) => {
if (!price) {
return
} else {
const element = $("#sell_" + (index + 2));
element.focus();
element.val(price);
element.blur();
}
})
}
const initialize = function () {
try {
const previous = getPrevious();
const first_buy = previous[0];
const previous_pattern = previous[1];
const prices = previous[2];
if (prices === null) {
fillFields([], first_buy, previous_pattern)
} else {
fillFields(prices, first_buy, previous_pattern)
}
} catch (e) {
console.error(e);
}
$(document).trigger("input");
$("#permalink-btn").on("click", copyPermalink)
$("#reset").on("click", function () {
if (window.confirm(i18next.t("prices.reset-warning"))) {
sell_inputs.forEach(input => input.value = '')
fillFields([], false, -1)
update()
}
})
}
const updateLocalStorage = function (prices, first_buy, previous_pattern) {
try {
if (prices.length !== 14) throw "The data array needs exactly 14 elements to be valid"
localStorage.setItem("sell_prices", JSON.stringify(prices))
localStorage.setItem("first_buy", JSON.stringify(first_buy));
localStorage.setItem("previous_pattern", JSON.stringify(previous_pattern));
} catch (e) {
console.error(e)
}
}
const isEmpty = function (arr) {
const filtered = arr.filter(value => value !== null && value !== '' && !isNaN(value))
return filtered.length == 0
}
const getFirstBuyStateFromQuery = function (param) {
try {
const params = new URLSearchParams(window.location.search.substr(1));
const firstbuy_str = params.get(param);
if (firstbuy_str == null) {
return null;
}
firstbuy = null;
if (firstbuy_str == "1" || firstbuy_str == "yes" || firstbuy_str == "true") {
firstbuy = true;
} else if (firstbuy_str == "0" || firstbuy_str == "no" || firstbuy_str == "false") {
firstbuy = false;
}
return firstbuy;
} catch (e) {
return null;
}
}
const getFirstBuyStateFromLocalstorage = function () {
return JSON.parse(localStorage.getItem('first_buy'))
}
const getPreviousPatternStateFromLocalstorage = function () {
return JSON.parse(localStorage.getItem('previous_pattern'))
}
const getPreviousPatternStateFromQuery = function (param) {
try {
const params = new URLSearchParams(window.location.search.substr(1));
const pattern_str = params.get(param);
if (pattern_str == null) {
return null;
}
if (pattern_str == "0" || pattern_str == "fluctuating") {
pattern = 0;
} else if (pattern_str == "1" || pattern_str == "large-spike") {
pattern = 1;
} else if (pattern_str == "2" || pattern_str == "decreasing") {
pattern = 2;
} else if (pattern_str == "3" || pattern_str == "small-spike") {
pattern = 3;
} else {
pattern = -1;
}
return pattern;
} catch (e) {
return null;
}
}
const getPricesFromLocalstorage = function () {
try {
const sell_prices = JSON.parse(localStorage.getItem("sell_prices"));
if (!Array.isArray(sell_prices) || sell_prices.length !== 14) {
return null;
}
return sell_prices;
} catch (e) {
return null;
}
};
const getPricesFromQuery = function (param) {
try {
const params = new URLSearchParams(window.location.search.substr(1));
const sell_prices = params.get(param).split(".").map((x) => parseInt(x, 10));
if (!Array.isArray(sell_prices)) {
return null;
}
// Parse the array which is formatted like: [price, M-AM, M-PM, T-AM, T-PM, W-AM, W-PM, Th-AM, Th-PM, F-AM, F-PM, S-AM, S-PM, Su-AM, Su-PM]
// due to the format of local storage we need to double up the price at the start of the array.
sell_prices.unshift(sell_prices[0]);
// This allows us to fill out the missing fields at the end of the array
for (let i = sell_prices.length; i < 14; i++) {
sell_prices.push(0);
}
return sell_prices;
} catch (e) {
return null;
}
};
const getPreviousFromQuery = function () {
/* Check if valid prices are entered. Exit immediately if not. */
const prices = getPricesFromQuery("prices");
if (prices == null) {
return null;
}
console.log("Using data from query.");
window.populated_from_query = true;
return [
getFirstBuyStateFromQuery("first"),
getPreviousPatternStateFromQuery("pattern"),
prices
];
};
const getPreviousFromLocalstorage = function () {
return [
getFirstBuyStateFromLocalstorage(),
getPreviousPatternStateFromLocalstorage(),
getPricesFromLocalstorage()
];
};
/**
* Gets previous values. First tries to parse parameters,
* if none of them match then it looks in local storage.
* @return {[first time, previous pattern, prices]}
*/
const getPrevious = function () {
return getPreviousFromQuery() || getPreviousFromLocalstorage();
};
const getSellPrices = function () {
//Checks all sell inputs and returns an array with their values
return res = sell_inputs.map(function (input) {
return parseInt(input.value || '');
})
}
const getPriceClass = function(buy_price, max) {
const priceBrackets = [200, 30, 0, -30, -99];
let diff = max - buy_price;
for(var i=0; i<priceBrackets.length; i++) {
if(diff >= priceBrackets[i]) {
return "range" + i;
}
}
return "";
}
const displayPercentage = function(fraction) {
if (Number.isFinite(fraction)) {
let percent = fraction * 100;
if (percent >= 1) {
return percent.toPrecision(3) + '%';
} else if (percent >= 0.01) {
return percent.toFixed(2) + '%';
} else {
return '<0.01%';
}
} else {
return '—'
}
}
const calculateOutput = function (data, first_buy, previous_pattern) {
if (isEmpty(data)) {
$("#output").html("");
return;
}
let output_possibilities = "";
let predictor = new Predictor(data, first_buy, previous_pattern);
let analyzed_possibilities = predictor.analyze_possibilities();
let buy_price = parseInt(buy_input.val());
previous_pattern_number = ""
for (let poss of analyzed_possibilities) {
var out_line = "<tr><td class='table-pattern'>" + poss.pattern_description + "</td>";
const style_price = buy_price || poss.prices[0].min;
if (previous_pattern_number != poss.pattern_number) {
previous_pattern_number = poss.pattern_number
pattern_count = analyzed_possibilities
.filter(val => val.pattern_number == poss.pattern_number)
.length
out_line += `<td rowspan=${pattern_count}>${displayPercentage(poss.category_total_probability)}</td>`;
}
out_line += `<td>${displayPercentage(poss.probability)}</td>`;
for (let day of poss.prices.slice(2)) {
let price_class = getPriceClass(style_price, day.max);
if (day.min !== day.max) {
out_line += `<td class='${price_class}'>${day.min} ${i18next.t("output.to")} ${day.max}</td>`;
} else {
out_line += `<td class='${price_class}'>${day.min}</td>`;
}
}
var min_class = getPriceClass(style_price, poss.weekGuaranteedMinimum);
var max_class = getPriceClass(style_price, poss.weekMax);
out_line += `<td class='${min_class}'>${poss.weekGuaranteedMinimum}</td><td class='${max_class}'>${poss.weekMax}</td></tr>`;
output_possibilities += out_line
}
$("#output").html(output_possibilities)
update_chart(data, analyzed_possibilities);
}
const generatePermalink = function (buy_price, sell_prices, first_buy, previous_pattern) {
let searchParams = new URLSearchParams();
let pricesParam = buy_price ? buy_price.toString() : '';
if (!isEmpty(sell_prices)) {
const filtered = sell_prices.map(price => isNaN(price) ? '' : price).join('.');
pricesParam = pricesParam.concat('.', filtered);
}
if (pricesParam) {
searchParams.append('prices', pricesParam);
}
if (first_buy) {
searchParams.append('first', true);
}
if (previous_pattern !== -1) {
searchParams.append('pattern', previous_pattern);
}
return searchParams.toString() && window.location.origin.concat('?', searchParams.toString());
}
const copyPermalink = function () {
let text = permalink_input[0];
permalink_input.show();
text.select();
text.setSelectionRange(0, 99999); /* for mobile devices */
document.execCommand('copy');
permalink_input.hide();
flashMessage(i18next.t("prices.permalink-copied"));
}
const flashMessage = function(message) {
snackbar.text(message);
snackbar.addClass('show');
setTimeout(function () {
snackbar.removeClass('show')
snackbar.text('');
}, 3000);
}
const update = function () {
const sell_prices = getSellPrices();
const buy_price = parseInt(buy_input.val());
const first_buy = getCheckedRadio(first_buy_radios) == 'true';
const previous_pattern = parseInt(getCheckedRadio(previous_pattern_radios));
const permalink = generatePermalink(buy_price, sell_prices, first_buy, previous_pattern);
if (permalink) {
permalink_button.show();
} else {
permalink_button.hide();
}
permalink_input.val(permalink);
const prices = [buy_price, buy_price, ...sell_prices];
if (!window.populated_from_query) {
updateLocalStorage(prices, first_buy, previous_pattern);
}
calculateOutput(prices, first_buy, previous_pattern);
}