You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
14 KiB
475 lines
14 KiB
let combined_charts = [];
|
|
let player_charts = [];
|
|
|
|
const x_scale = {
|
|
display: true,
|
|
type: "linear",
|
|
stepSize: 1000 * 60 * 60 * 24,
|
|
ticks: {
|
|
callback: (value, index, ticks) => {
|
|
let tickdate = new Date(value);
|
|
return `${tickdate.getDate()}.${month_names[tickdate.getMonth()]}`;
|
|
}
|
|
}
|
|
}
|
|
const zoom_plugin = {
|
|
zoom: {
|
|
wheel: {
|
|
enabled: true,
|
|
},
|
|
pinch: {
|
|
enabled: true,
|
|
},
|
|
mode: "x",
|
|
onZoomComplete: function({chart}) {
|
|
const show_point_cutoff = 1000 * 60 * 60 * 24 * 3
|
|
const diff = parseInt(chart.scales.x.max) - parseInt(chart.scales.x.min);
|
|
const show_points = diff < show_point_cutoff;
|
|
const hide_points = diff >= show_point_cutoff;
|
|
let update_chart = false;
|
|
chart.data.datasets.forEach(dataset => {
|
|
const points_shown = dataset.pointRadius > 0
|
|
if (show_points && !points_shown) {
|
|
dataset.pointRadius = 3;
|
|
update_chart = true;
|
|
}
|
|
if (hide_points && points_shown) {
|
|
dataset.pointRadius = 0;
|
|
update_chart = true;
|
|
}
|
|
})
|
|
if (update_chart) chart.update();
|
|
}
|
|
},
|
|
pan: {
|
|
enabled: true,
|
|
mode: "x",
|
|
},
|
|
}
|
|
const trigger_legend_hover = function (e, legendItem, legend) {
|
|
if (legendItem.hidden) {
|
|
return;
|
|
}
|
|
legend.chart.data.datasets.forEach((dataset, i) => {
|
|
dataset.backgroundColor = (legendItem.datasetIndex === i || dataset.backgroundColor.length === 9) ? dataset.backgroundColor : dataset.backgroundColor + '3D';
|
|
dataset.borderColor = (legendItem.datasetIndex === i || dataset.borderColor.length === 9) ? dataset.borderColor : dataset.borderColor + '3D';
|
|
dataset.borderWidth = legendItem.datasetIndex === i ? 4 : 3;
|
|
dataset.pointRadius = dataset.pointRadius===0 ? 0 : 2;
|
|
});
|
|
legend.chart.update();
|
|
}
|
|
const trigger_legend_leave = function (e, legendItem, legend) {
|
|
legend.chart.data.datasets.forEach((dataset, i) => {
|
|
dataset.backgroundColor = dataset.backgroundColor.length === 9 ? dataset.backgroundColor.slice(0, -2) : dataset.backgroundColor;
|
|
dataset.borderColor = dataset.borderColor.length === 9 ? dataset.borderColor.slice(0, -2) : dataset.borderColor;
|
|
dataset.borderWidth = 3;
|
|
});
|
|
legend.chart.update();
|
|
}
|
|
const legend_plugin = {
|
|
position: "bottom",
|
|
labels: {
|
|
padding: 10,
|
|
useBorderRadius: true,
|
|
borderRadius: 2,
|
|
boxWidth: 20,
|
|
},
|
|
onHover: trigger_legend_hover,
|
|
onLeave: trigger_legend_leave,
|
|
onClick: function (e, legendItem, legend) {
|
|
if (legend.chart.isDatasetVisible(legendItem.datasetIndex)) {
|
|
trigger_legend_leave(e, legendItem, legend);
|
|
legend.chart.hide(legendItem.datasetIndex);
|
|
legendItem.hidden = true;
|
|
} else {
|
|
legend.chart.show(legendItem.datasetIndex);
|
|
legendItem.hidden = false;
|
|
trigger_legend_hover(e, legendItem, legend);
|
|
}
|
|
}
|
|
}
|
|
|
|
window.onload = create_charts;
|
|
|
|
async function create_charts() {
|
|
combined_charts.forEach(chart => chart.destroy());
|
|
combined_charts = [];
|
|
player_charts.forEach(chart => chart.destroy());
|
|
player_charts = [];
|
|
|
|
let player_rank_values = {};
|
|
let player_progress_values = {};
|
|
|
|
let player_entries = {}; // puuid zeigt auf player entries
|
|
let player_entries_byName = {}; // playername zeigt auf entries (damit im kombinierten Graphen die Tooltips korrekt gerendert werden können)
|
|
let player_accounts = {}; // puuid zeigt auf player account
|
|
|
|
const tooltip_plugin = {
|
|
callbacks: {
|
|
label: function (context) {
|
|
return format_rank(player_entries_byName[context.dataset.label][context.parsed.x / 1000]["tier"], player_entries_byName[context.dataset.label][context.parsed.x / 1000]["rank"], player_entries_byName[context.dataset.label][context.parsed.x / 1000]["points"])
|
|
},
|
|
title: items => {
|
|
let ms = items[0].raw.x;
|
|
let options = {
|
|
weekday: "short",
|
|
day: "numeric",
|
|
month: "short",
|
|
hour: "2-digit",
|
|
minute: "2-digit"
|
|
}
|
|
return new Date(ms).toLocaleDateString("de-DE", options);
|
|
},
|
|
beforeTitle: function (context) {
|
|
return context[0].dataset.label;
|
|
},
|
|
}
|
|
};
|
|
|
|
await fetch(`get.php`, {
|
|
method: "GET",
|
|
})
|
|
.then(res => res.json())
|
|
.then(result => {
|
|
player_entries = result["entries"];
|
|
player_accounts = result["accounts"];
|
|
|
|
let all_rank_yDatasets = []; // Datasets, also die einzelnen Linien im Graphen, beinhaltet player_rank_values
|
|
let all_progress_yDatasets = []; // Datasets, also die einzelnen Linien im Graphen, beinhaltet player_progress_values
|
|
|
|
let minval = -1;
|
|
let maxval = -1;
|
|
|
|
let color_counter = 0;
|
|
for (const puuid in player_entries) {
|
|
player_rank_values[puuid] = [];
|
|
player_progress_values[puuid] = [];
|
|
player_entries_byName[`${player_accounts[puuid]["gameName"]}#${player_accounts[puuid]["tagLine"]}`] = [];
|
|
|
|
let player_start_points = -1;
|
|
for (const timestamp in player_entries[puuid]) {
|
|
// Für alle Player Entries Punktzahl und Punktedifferenz berechnen
|
|
// Bei der Gelegenheit auch Entries in player_entries_byName eintragen
|
|
const current_points = rank_to_points(player_entries[puuid][timestamp]["tier"], player_entries[puuid][timestamp]["rank"], player_entries[puuid][timestamp]["points"]);
|
|
const adj_timestamp = parseInt(timestamp) * 1000;
|
|
player_rank_values[puuid].push({x: adj_timestamp, y: current_points});
|
|
player_entries_byName[`${player_accounts[puuid]["gameName"]}#${player_accounts[puuid]["tagLine"]}`][timestamp] = player_entries[puuid][timestamp];
|
|
if (player_start_points === -1) {
|
|
player_start_points = current_points;
|
|
player_progress_values[puuid].push({x: adj_timestamp, y: 0});
|
|
} else {
|
|
player_progress_values[puuid].push({
|
|
x: adj_timestamp,
|
|
y: current_points - player_start_points
|
|
});
|
|
}
|
|
if (minval === -1 || adj_timestamp < minval) {
|
|
minval = adj_timestamp;
|
|
}
|
|
if (maxval === -1 || adj_timestamp > maxval) {
|
|
maxval = adj_timestamp;
|
|
}
|
|
}
|
|
// Linie für den Spieler zu Datasets des Graphen hinzufügen
|
|
all_rank_yDatasets.push({
|
|
label: `${player_accounts[puuid]["gameName"]}#${player_accounts[puuid]["tagLine"]}`,
|
|
fill: false,
|
|
borderColor: getColor(color_counter),
|
|
backgroundColor: getColor(color_counter),
|
|
borderJoinStyle: "round",
|
|
data: player_rank_values[puuid],
|
|
spanGaps: true,
|
|
pointHitRadius: 16,
|
|
pointRadius: 0,
|
|
})
|
|
all_progress_yDatasets.push({
|
|
label: `${player_accounts[puuid]["gameName"]}#${player_accounts[puuid]["tagLine"]}`,
|
|
fill: false,
|
|
borderColor: getColor(color_counter),
|
|
backgroundColor: getColor(color_counter),
|
|
borderJoinStyle: "round",
|
|
data: player_progress_values[puuid],
|
|
spanGaps: true,
|
|
pointHitRadius: 16,
|
|
pointRadius: 0,
|
|
})
|
|
color_counter++;
|
|
}
|
|
// Graphen erstellen
|
|
combined_charts.push(new Chart(`progress-chart-combined`, {
|
|
type: "line",
|
|
data: {
|
|
datasets: all_rank_yDatasets,
|
|
},
|
|
options: {
|
|
plugins: {
|
|
tooltip: tooltip_plugin,
|
|
zoom: {...zoom_plugin},
|
|
legend: legend_plugin,
|
|
},
|
|
scales: {
|
|
x: x_scale,
|
|
y: {
|
|
display: true,
|
|
stepSize: 100,
|
|
ticks: {
|
|
callback: (value) => {
|
|
return points_to_rankstring(value, false);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
}
|
|
}));
|
|
combined_charts.push(new Chart(`progress-chart-combined-progress`, {
|
|
type: "line",
|
|
data: {
|
|
datasets: all_progress_yDatasets,
|
|
},
|
|
options: {
|
|
plugins: {
|
|
tooltip: tooltip_plugin,
|
|
zoom: {...zoom_plugin},
|
|
legend: legend_plugin,
|
|
},
|
|
scales: {
|
|
x: x_scale,
|
|
y: {
|
|
display: true,
|
|
},
|
|
},
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
}
|
|
}));
|
|
minval -= 7200000;
|
|
maxval += 7200000;
|
|
combined_charts.forEach(combined_chart => {
|
|
combined_chart.options.plugins.zoom.limits = {
|
|
x: {min: minval, max: maxval},
|
|
}
|
|
})
|
|
})
|
|
.catch(e => console.error(e))
|
|
|
|
const charts = document.getElementsByClassName("progress-chart");
|
|
for (const chart of charts) {
|
|
let puuid = chart.id.split("-");
|
|
puuid.splice(0, 2);
|
|
puuid = puuid.join("-");
|
|
let values = [];
|
|
let minval = Object.keys(player_entries[puuid])[0] * 1000 - 7200000;
|
|
let maxval = Object.keys(player_entries[puuid])[Object.keys(player_entries[puuid]).length - 1] * 1000 + 7200000;
|
|
for (const entriesKey in player_entries[puuid]) {
|
|
let points = rank_to_points(player_entries[puuid][entriesKey]["tier"], player_entries[puuid][entriesKey]["rank"], player_entries[puuid][entriesKey]["points"]);
|
|
values.push({x: parseInt(entriesKey) * 1000, y: points});
|
|
}
|
|
const player_chart = new Chart(`progress-chart-${puuid}`, {
|
|
type: "line",
|
|
data: {
|
|
datasets: [{
|
|
label: `${player_accounts[puuid]["gameName"]}#${player_accounts[puuid]["tagLine"]}`,
|
|
fill: false,
|
|
borderColor: "rgba(150,150,175)",
|
|
backgroundColor: "rgba(150,150,175)",
|
|
borderJoinStyle: "round",
|
|
data: values,
|
|
pointHitRadius: 16,
|
|
pointRadius: 0,
|
|
}]
|
|
},
|
|
options: {
|
|
plugins: {
|
|
legend: {display: false},
|
|
tooltip: tooltip_plugin,
|
|
zoom: {...zoom_plugin},
|
|
},
|
|
scales: {
|
|
x: x_scale,
|
|
y: {
|
|
display: true,
|
|
stepSize: 100,
|
|
ticks: {
|
|
callback: (value) => {
|
|
return points_to_rankstring(value, false);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
}
|
|
});
|
|
player_chart.options.plugins.zoom.limits = {
|
|
x: {min: minval, max: maxval},
|
|
}
|
|
player_charts.push(player_chart);
|
|
}
|
|
}
|
|
|
|
function rank_to_points(tier, rank, lp) {
|
|
const apex_tiers = (tier === "MASTER" || tier === "GRANDMASTER" || tier === "CHALLENGER");
|
|
const tiers = {
|
|
"DIAMOND": 2400,
|
|
"EMERALD": 2000,
|
|
"PLATINUM": 1600,
|
|
"GOLD": 1200,
|
|
"SILVER": 800,
|
|
"BRONZE": 400,
|
|
"IRON": 0,
|
|
};
|
|
const ranks = {
|
|
"I": 300,
|
|
"II": 200,
|
|
"III": 100,
|
|
"IV": 0,
|
|
};
|
|
if (apex_tiers) {
|
|
return 2800 + lp;
|
|
} else {
|
|
return tiers[tier] + ranks[rank] + lp;
|
|
}
|
|
}
|
|
|
|
function points_to_rankstring(points, include_LP = true) {
|
|
const apex_tiers = (points >= 2800);
|
|
let lp = (apex_tiers) ? points - 2800 : points % 100
|
|
let rank = (points - lp) % 400;
|
|
let tier = (points - lp - rank);
|
|
const tiers = {
|
|
2400: "Diamond",
|
|
2000: "Emerald",
|
|
1600: "Platinum",
|
|
1200: "Gold",
|
|
800: "Silver",
|
|
400: "Bronze",
|
|
0: "Iron",
|
|
};
|
|
const ranks = {
|
|
300: "I",
|
|
200: "II",
|
|
100: "III",
|
|
0: "IV",
|
|
};
|
|
|
|
let rank_string = (apex_tiers) ? "Master" : tiers[tier];
|
|
if (!apex_tiers) rank_string += ` ${ranks[rank]}`;
|
|
if (include_LP || apex_tiers) rank_string += ` ${lp} LP`;
|
|
return rank_string;
|
|
}
|
|
|
|
function format_rank(tier, rank, lp) {
|
|
tier = tier.charAt(0).toUpperCase() + tier.slice(1).toLowerCase();
|
|
const apex_tiers = (tier === "Master" || tier === "Grandmaster" || tier === "Challenger");
|
|
let rank_string = tier;
|
|
if (!apex_tiers) rank_string += ` ${rank}`;
|
|
rank_string += ` ${lp} LP`;
|
|
return rank_string;
|
|
}
|
|
|
|
function getColor(num) {
|
|
const colors = ["#33b1ff", "#d2a106", "#007d79", "#8a3ffc", "#ff7eb6", "#ba4e00", "#fa4d56", "#fff1f1", "#6fdc8c", "#4589ff", "#d12771", "#08bdba", "#bae6ff", "#d4bbff"];
|
|
|
|
return colors[num % 9];
|
|
}
|
|
|
|
function toggle_combined_chart() {
|
|
const comb_charts = this.parentNode.parentNode.querySelectorAll(`.leaderboard>.graph-wrapper`);
|
|
const chart = this.parentNode.parentNode.querySelector(`.graph-wrapper.${this.id}`);
|
|
if (chart.classList.contains("closed")) {
|
|
comb_charts.forEach(element => element.classList.add("closed"));
|
|
chart.classList.remove("closed");
|
|
} else {
|
|
chart.classList.add("closed");
|
|
}
|
|
}
|
|
|
|
function toggle_leaderboard_chart(event) {
|
|
if (this.classList.contains("closed")) {
|
|
this.classList.remove("closed");
|
|
} else {
|
|
if (event.target.nodeName === "CANVAS") return;
|
|
this.classList.add("closed");
|
|
}
|
|
}
|
|
|
|
document.querySelectorAll("button.open-general-graph").forEach(element => element.addEventListener("click", toggle_combined_chart));
|
|
document.querySelectorAll("button.leaderboard-element").forEach(element => element.addEventListener("mousedown", toggle_leaderboard_chart));
|
|
|
|
async function update_leaderboard_entries() {
|
|
this.disabled = true;
|
|
this.classList.add("button-updating")
|
|
let eventSource = new EventSource("./update.php");
|
|
eventSource.addEventListener("progress", e => {
|
|
this.style.setProperty("--button-loading-bar-width", `${e.data * 100}%`);
|
|
})
|
|
eventSource.addEventListener("forbidden", e => {
|
|
eventSource.close();
|
|
let response = JSON.parse(e.data);
|
|
const currenttime = new Date();
|
|
const updatetime = new Date(response.last);
|
|
let timediff = new Date(currenttime - updatetime);
|
|
let resttime = new Date( 1000 * 60 * response.limit - (currenttime - updatetime));
|
|
window.alert(`Das letzte Update wurde vor ${format_time_minsec(timediff)} durchgeführt. Versuche es in ${format_time_minsec(resttime)} noch einmal`);
|
|
reset_button(this);
|
|
})
|
|
eventSource.onerror = e => {
|
|
eventSource.close();
|
|
window.alert(`Beim Update ist ein Fehler aufgetreten. Versuche es später noch einmal`)
|
|
reset_button(this);
|
|
}
|
|
eventSource.addEventListener("done", e => {
|
|
eventSource.close();
|
|
reset_button(this);
|
|
|
|
update_leaderboard_elements();
|
|
})
|
|
|
|
async function reset_button(button) {
|
|
await new Promise(r => setTimeout(r,400)); // warten bis ladebalken am ende angekommen ist
|
|
button.style.setProperty("--button-loading-bar-opacity", `0`);
|
|
await new Promise(r => setTimeout(r,400)); // warten bis ladebalken verblasst ist
|
|
button.style.setProperty("--button-loading-bar-width", `0`);
|
|
await new Promise(r => setTimeout(r,400)); // warten bis ladebalken wieder am anfang angekommen ist
|
|
button.style.setProperty("--button-loading-bar-opacity", `1`);
|
|
button.disabled = false;
|
|
button.classList.remove("button-updating");
|
|
}
|
|
}
|
|
|
|
document.querySelector("button.update-leaderboard").addEventListener("click", update_leaderboard_entries);
|
|
|
|
function format_time_minsec(date) {
|
|
let format, trenner = "", min = "", nullausgleich = "";
|
|
if (date.getMinutes() === 0) {
|
|
format = " Sekunden";
|
|
} else {
|
|
min = date.getMinutes();
|
|
format = " Minuten";
|
|
trenner = ":";
|
|
if (date.getSeconds() < 10) {
|
|
nullausgleich = "0";
|
|
}
|
|
}
|
|
return min + trenner + nullausgleich + date.getSeconds() + format;
|
|
}
|
|
|
|
const month_names = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];
|
|
|
|
async function update_leaderboard_elements() {
|
|
fetch(`./leaderboard_list.php`, {
|
|
method: "GET",
|
|
})
|
|
.then(res => res.text())
|
|
.then(leaderboard_list => {
|
|
// replace updated Leaderboard
|
|
document.querySelector(".leaderboard-list").outerHTML = leaderboard_list;
|
|
// reapply EventListeners
|
|
document.querySelectorAll("button.leaderboard-element").forEach(element => element.addEventListener("click", toggle_leaderboard_chart));
|
|
// recreate charts
|
|
create_charts();
|
|
})
|
|
.catch(e => console.error(e));
|
|
} |