|
|
@ -46,130 +46,48 @@ const zoom_plugin = { |
|
|
|
mode: "x", |
|
|
|
mode: "x", |
|
|
|
}, |
|
|
|
}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const trigger_legend_hover = function (e, legendItem, legend) { |
|
|
|
let hovered = false; |
|
|
|
if (legendItem.hidden) { |
|
|
|
const trigger_legend_hover = function (legendItem, chart) { |
|
|
|
|
|
|
|
if (chart.legend.legendItems[legendItem.datasetIndex].hidden || hovered) { |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
hovered = true; |
|
|
|
legend.chart.data.datasets.forEach((dataset, i) => { |
|
|
|
chart.data.datasets.forEach((dataset, i) => { |
|
|
|
|
|
|
|
dataset.backgroundColor = (legendItem.datasetIndex === i || dataset.backgroundColor.length === 9) ? dataset.backgroundColor : dataset.backgroundColor + '3D'; |
|
|
|
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.borderColor = (legendItem.datasetIndex === i || dataset.borderColor.length === 9) ? dataset.borderColor : dataset.borderColor + '3D'; |
|
|
|
dataset.borderWidth = legendItem.datasetIndex === i ? 4 : 3; |
|
|
|
dataset.borderWidth = legendItem.datasetIndex === i ? 4 : 3; |
|
|
|
dataset.pointRadius = dataset.pointRadius===0 ? 0 : 2; |
|
|
|
dataset.pointRadius = dataset.pointRadius===0 ? 0 : 2; |
|
|
|
}); |
|
|
|
}); |
|
|
|
chart.update(); |
|
|
|
legend.chart.update(); |
|
|
|
} |
|
|
|
} |
|
|
|
const trigger_legend_leave = function (chart) { |
|
|
|
const trigger_legend_leave = function (e, legendItem, legend) { |
|
|
|
chart.data.datasets.forEach((dataset, i) => { |
|
|
|
legend.chart.data.datasets.forEach((dataset, i) => { |
|
|
|
dataset.backgroundColor = dataset.backgroundColor.length === 9 ? dataset.backgroundColor.slice(0, -2) : dataset.backgroundColor; |
|
|
|
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.borderColor = dataset.borderColor.length === 9 ? dataset.borderColor.slice(0, -2) : dataset.borderColor; |
|
|
|
dataset.borderWidth = 3; |
|
|
|
dataset.borderWidth = 3; |
|
|
|
}); |
|
|
|
}); |
|
|
|
chart.update(); |
|
|
|
legend.chart.update(); |
|
|
|
hovered = false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
const trigger_legend_click = function (item) { |
|
|
|
const legend_plugin = { |
|
|
|
combined_charts.forEach(c_chart => { |
|
|
|
position: "bottom", |
|
|
|
if (c_chart.isDatasetVisible(item.datasetIndex)) { |
|
|
|
labels: { |
|
|
|
trigger_legend_leave(c_chart) |
|
|
|
padding: 10, |
|
|
|
c_chart.hide(item.datasetIndex); |
|
|
|
useBorderRadius: true, |
|
|
|
c_chart.legend.legendItems[item.datasetIndex].hidden = 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 { |
|
|
|
} else { |
|
|
|
c_chart.show(item.datasetIndex); |
|
|
|
legend.chart.show(legendItem.datasetIndex); |
|
|
|
c_chart.legend.legendItems[item.datasetIndex].hidden = false; |
|
|
|
legendItem.hidden = false; |
|
|
|
trigger_legend_hover(item, c_chart) |
|
|
|
trigger_legend_hover(e, legendItem, legend); |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// break hover state when mouseout fails to trigger
|
|
|
|
|
|
|
|
window.onmousemove = (e) => { |
|
|
|
|
|
|
|
if (hovered && (e.target.closest("ul") === null || !e.target.closest("ul").classList.contains("legend-list"))) { |
|
|
|
|
|
|
|
console.log("breaking hover") |
|
|
|
|
|
|
|
combined_charts.forEach(chart => { |
|
|
|
|
|
|
|
trigger_legend_leave(chart); |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
const get_create_LegendList = (chart, id) => { |
|
|
|
|
|
|
|
let created = false; |
|
|
|
|
|
|
|
const legendContainer = document.getElementById(id); |
|
|
|
|
|
|
|
let listContainer = legendContainer.querySelector("ul"); |
|
|
|
|
|
|
|
if (!listContainer) { |
|
|
|
|
|
|
|
created = true; |
|
|
|
|
|
|
|
listContainer = document.createElement("ul"); |
|
|
|
|
|
|
|
listContainer.classList.add('legend-list'); |
|
|
|
|
|
|
|
legendContainer.appendChild(listContainer); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return {list: listContainer, created: created}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const htmlLegendPlugin = { |
|
|
|
|
|
|
|
id: 'htmlLegend', |
|
|
|
|
|
|
|
afterUpdate(chart, args, options) { |
|
|
|
|
|
|
|
function sort_legend(a,b) { |
|
|
|
|
|
|
|
const a_values = chart.data.datasets[a.datasetIndex].data |
|
|
|
|
|
|
|
const b_values = chart.data.datasets[b.datasetIndex].data |
|
|
|
|
|
|
|
const a_value = a_values[a_values.length - 1].y; |
|
|
|
|
|
|
|
const b_value = b_values[b_values.length - 1].y; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (a_value > b_value) { |
|
|
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
} else if (a_value < b_value) { |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//console.log("update")
|
|
|
|
|
|
|
|
const legendList = get_create_LegendList(chart, options.containerID); |
|
|
|
|
|
|
|
const ul = legendList.list; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reuse the built-in legendItems generator
|
|
|
|
|
|
|
|
const items = chart.options.plugins.legend.labels.generateLabels(chart); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
items.sort(sort_legend); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
items.forEach((item, i) => { |
|
|
|
|
|
|
|
if (legendList.created) { |
|
|
|
|
|
|
|
const li = document.createElement('li'); |
|
|
|
|
|
|
|
li.classList.add("legend-element"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
li.onmouseover = () => {trigger_legend_hover(item, chart)}; |
|
|
|
|
|
|
|
li.onmouseout = () => {trigger_legend_leave(chart)}; |
|
|
|
|
|
|
|
li.onclick = () => {trigger_legend_click(item)}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Color box
|
|
|
|
|
|
|
|
const boxSpan = document.createElement('span'); |
|
|
|
|
|
|
|
boxSpan.style.background = item.fillStyle; |
|
|
|
|
|
|
|
boxSpan.style.borderColor = item.strokeStyle; |
|
|
|
|
|
|
|
boxSpan.style.borderWidth = item.lineWidth + 'px'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Text
|
|
|
|
|
|
|
|
const textContainer = document.createElement('p'); |
|
|
|
|
|
|
|
textContainer.style.color = item.fontColor; |
|
|
|
|
|
|
|
textContainer.style.textDecoration = item.hidden ? 'line-through' : ''; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const text = document.createTextNode(item.text); |
|
|
|
|
|
|
|
textContainer.appendChild(text); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
li.appendChild(boxSpan); |
|
|
|
|
|
|
|
li.appendChild(textContainer); |
|
|
|
|
|
|
|
ul.appendChild(li); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
const list_element = ul.querySelector(`li.legend-element:nth-of-type(${i+1})`); |
|
|
|
|
|
|
|
const boxSpan = list_element.querySelector("span"); |
|
|
|
|
|
|
|
const textContainer = list_element.querySelector("p"); |
|
|
|
|
|
|
|
boxSpan.style.background = item.fillStyle; |
|
|
|
|
|
|
|
boxSpan.style.borderColor = item.strokeStyle; |
|
|
|
|
|
|
|
boxSpan.style.borderWidth = item.lineWidth + 'px'; |
|
|
|
|
|
|
|
textContainer.style.color = item.fontColor; |
|
|
|
|
|
|
|
textContainer.style.textDecoration = item.hidden ? 'line-through' : ''; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.onload = create_charts; |
|
|
|
window.onload = create_charts; |
|
|
|
|
|
|
|
|
|
|
@ -287,12 +205,7 @@ async function create_charts() { |
|
|
|
plugins: { |
|
|
|
plugins: { |
|
|
|
tooltip: tooltip_plugin, |
|
|
|
tooltip: tooltip_plugin, |
|
|
|
zoom: {...zoom_plugin}, |
|
|
|
zoom: {...zoom_plugin}, |
|
|
|
legend: { |
|
|
|
legend: legend_plugin, |
|
|
|
display: false, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
htmlLegend: { |
|
|
|
|
|
|
|
containerID: 'legend-rank-graph', |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
scales: { |
|
|
|
scales: { |
|
|
|
x: x_scale, |
|
|
|
x: x_scale, |
|
|
@ -308,8 +221,7 @@ async function create_charts() { |
|
|
|
}, |
|
|
|
}, |
|
|
|
responsive: true, |
|
|
|
responsive: true, |
|
|
|
maintainAspectRatio: false, |
|
|
|
maintainAspectRatio: false, |
|
|
|
}, |
|
|
|
} |
|
|
|
plugins: [htmlLegendPlugin], |
|
|
|
|
|
|
|
})); |
|
|
|
})); |
|
|
|
combined_charts.push(new Chart(`progress-chart-combined-progress`, { |
|
|
|
combined_charts.push(new Chart(`progress-chart-combined-progress`, { |
|
|
|
type: "line", |
|
|
|
type: "line", |
|
|
@ -320,12 +232,7 @@ async function create_charts() { |
|
|
|
plugins: { |
|
|
|
plugins: { |
|
|
|
tooltip: tooltip_plugin, |
|
|
|
tooltip: tooltip_plugin, |
|
|
|
zoom: {...zoom_plugin}, |
|
|
|
zoom: {...zoom_plugin}, |
|
|
|
legend: { |
|
|
|
legend: legend_plugin, |
|
|
|
display: false, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
htmlLegend: { |
|
|
|
|
|
|
|
containerID: 'legend-progress-graph', |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
scales: { |
|
|
|
scales: { |
|
|
|
x: x_scale, |
|
|
|
x: x_scale, |
|
|
@ -335,8 +242,7 @@ async function create_charts() { |
|
|
|
}, |
|
|
|
}, |
|
|
|
responsive: true, |
|
|
|
responsive: true, |
|
|
|
maintainAspectRatio: false, |
|
|
|
maintainAspectRatio: false, |
|
|
|
}, |
|
|
|
} |
|
|
|
plugins: [htmlLegendPlugin], |
|
|
|
|
|
|
|
})); |
|
|
|
})); |
|
|
|
minval -= 7200000; |
|
|
|
minval -= 7200000; |
|
|
|
maxval += 7200000; |
|
|
|
maxval += 7200000; |
|
|
@ -473,20 +379,14 @@ function toggle_combined_chart() { |
|
|
|
const comb_charts = this.parentNode.parentNode.querySelectorAll(`.leaderboard>.graph-wrapper`); |
|
|
|
const comb_charts = this.parentNode.parentNode.querySelectorAll(`.leaderboard>.graph-wrapper`); |
|
|
|
const chart = this.parentNode.parentNode.querySelector(`.graph-wrapper.${this.id}`); |
|
|
|
const chart = this.parentNode.parentNode.querySelector(`.graph-wrapper.${this.id}`); |
|
|
|
const buttons = document.querySelectorAll("button.open-general-graph"); |
|
|
|
const buttons = document.querySelectorAll("button.open-general-graph"); |
|
|
|
const legend = document.querySelector(`#combined-chart-legends #legend-${this.id}`) |
|
|
|
|
|
|
|
const all_legends = document.querySelectorAll(`#combined-chart-legends .chart-legend`); |
|
|
|
|
|
|
|
all_legends.forEach(element => {element.classList.add("hidden")}); |
|
|
|
|
|
|
|
legend.classList.remove("hidden"); |
|
|
|
|
|
|
|
if (chart.classList.contains("closed")) { |
|
|
|
if (chart.classList.contains("closed")) { |
|
|
|
comb_charts.forEach(element => element.classList.add("closed")); |
|
|
|
comb_charts.forEach(element => element.classList.add("closed")); |
|
|
|
buttons.forEach(element => element.classList.remove("dropdown-open")); |
|
|
|
buttons.forEach(element => element.classList.remove("dropdown-open")); |
|
|
|
chart.classList.remove("closed"); |
|
|
|
chart.classList.remove("closed"); |
|
|
|
this.classList.add("dropdown-open"); |
|
|
|
this.classList.add("dropdown-open"); |
|
|
|
document.querySelector("#combined-chart-legends").classList.remove("hidden"); |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
chart.classList.add("closed"); |
|
|
|
chart.classList.add("closed"); |
|
|
|
this.classList.remove("dropdown-open"); |
|
|
|
this.classList.remove("dropdown-open"); |
|
|
|
document.querySelector("#combined-chart-legends").classList.add("hidden"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -571,7 +471,7 @@ async function update_leaderboard_elements() { |
|
|
|
// replace updated Leaderboard
|
|
|
|
// replace updated Leaderboard
|
|
|
|
document.querySelector(".leaderboard-list").outerHTML = leaderboard_list; |
|
|
|
document.querySelector(".leaderboard-list").outerHTML = leaderboard_list; |
|
|
|
// reapply EventListeners
|
|
|
|
// reapply EventListeners
|
|
|
|
document.querySelectorAll("button.leaderboard-element").forEach(element => element.addEventListener("mousedown", toggle_leaderboard_chart)); |
|
|
|
document.querySelectorAll("button.leaderboard-element").forEach(element => element.addEventListener("click", toggle_leaderboard_chart)); |
|
|
|
// recreate charts
|
|
|
|
// recreate charts
|
|
|
|
create_charts(); |
|
|
|
create_charts(); |
|
|
|
}) |
|
|
|
}) |
|
|
|