Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2b03b44
introduced fixed font size classes: xl, big (bg), medium (md) and sma…
uwptv Oct 14, 2025
35f0206
Adjusted some font sizes and flex values for lower screen resolutions
uwptv Oct 14, 2025
f27118f
adjusted visuals for d3 data graphs on lower screen resolutions, made…
uwptv Oct 15, 2025
39c75a0
font size properties are now used everywhere
uwptv Oct 15, 2025
ccff0d3
added zoom functionality
uwptv Oct 16, 2025
febfffb
adjusted tick sizes and labels for timeline view
uwptv Oct 16, 2025
92e4f49
changed ticks text size in timeline view
uwptv Oct 16, 2025
f3fa36b
Alternating ticks only appear on lower screen resolutions
uwptv Oct 17, 2025
4b2ba3b
nodes now increase in radius on smaller screens
uwptv Oct 17, 2025
23ffe6b
decreased stroke width so focus is more on nodes
uwptv Oct 17, 2025
626281a
similarity view now has a vertical mdoe which serves on lower screen …
uwptv Oct 17, 2025
0fe91f8
Labels in ULayout are now not overflowing on certain resolutions
uwptv Oct 25, 2025
d224379
decreased some font sizes and padding
uwptv Oct 25, 2025
02a005e
made timeline container have normal aspect ratio
uwptv Oct 25, 2025
6307be1
zooming only at lower screen sizes
uwptv Oct 29, 2025
0e56b58
aligned controls for similarity and timeline at the left on lower scr…
uwptv Oct 29, 2025
88845f0
Info circles scale with font size now
uwptv Oct 29, 2025
66bb717
Fixed node spacing and curves
uwptv Oct 29, 2025
2285116
adjusted font sizes mainly for modals and info circles
uwptv Oct 29, 2025
5ef85a8
decreased height of bar charts
uwptv Oct 29, 2025
117c5d9
changed toggle sidebar filter and breakpoints where navbar elements hide
uwptv Oct 29, 2025
aaee179
slider is now responsive
uwptv Oct 29, 2025
286c2dd
increased min-height of barcharts to 25vh
uwptv Oct 29, 2025
b7cf081
adjusted node sizes so they dont overlap
uwptv Nov 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 92 additions & 53 deletions static/scripts/barChart.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { filterData, cleanDataString, specialOrders, showStudyModal, defaultColors } from "./dataUtility.mjs";
import {
filterData,
cleanDataString,
specialOrders,
showStudyModal,
defaultColors,
} from "./dataUtility.mjs";

// The available categories passed by the server for the bar charts
const categories = $("body").data("filter-categories");
const questionCirclePath = $("#toggle-menu-container").data("question-circle-path");
const questionCirclePath = $("#toggle-menu-container").data(
"question-circle-path"
);
const explanations = $("body").data("explanations");

/*
Expand All @@ -15,7 +23,9 @@ const explanations = $("body").data("explanations");

// Function to create Modal HTML for a given category and label
function createModalHTML(category, label) {
const activeData = filterData(JSON.parse(window.sessionStorage.getItem('filters')));
const activeData = filterData(
JSON.parse(window.sessionStorage.getItem("filters"))
);
const fullCategory = getFullCategory(category);

const tableHTML = `
Expand All @@ -32,11 +42,18 @@ function createModalHTML(category, label) {
</tr>
</thead>
<tbody>
${activeData.filter(entry => entry[fullCategory].toString().includes(label)).map(elem =>
`
${activeData
.filter((entry) => entry[fullCategory].toString().includes(label))
.map(
(elem) =>
`
<tr>
<td>
<img class="info-circle" src="${$("#table-modal-body").data("url-path-info-circle")}" alt="Info cirle for this row" title="Information about this row" data-id="${elem["ID"]}"/>
<img class="info-circle" src="${$("#table-modal-body").data(
"url-path-info-circle"
)}" alt="Info cirle for this row" title="Information about this row" data-id="${
elem["ID"]
}"/>
</td>
<td>${elem["ID"]}</td>
<td>${elem["Main Author"]}</td>
Expand All @@ -46,7 +63,8 @@ function createModalHTML(category, label) {
<td>${elem["Gesture"]}</td>
</tr>
`
).join("")}
)
.join("")}
</tbody>
</table>
`;
Expand All @@ -64,8 +82,10 @@ function createModalHTML(category, label) {
// Creates all bar charts based on the data passed by the server and the currently active filters (categories and value filters)
function createBarCharts() {
$("#chartsContainer").empty(); // Clear the charts container
const filters = JSON.parse(window.sessionStorage.getItem('filters'));
const activeCategories = filters.categoryFilters.map(cat => getFullCategory(cat)).filter(cat => cat !== undefined);
const filters = JSON.parse(window.sessionStorage.getItem("filters"));
const activeCategories = filters.categoryFilters
.map((cat) => getFullCategory(cat))
.filter((cat) => cat !== undefined);
// Remove "Main Author" category if it is in the active categories
const firstAuthorIndex = activeCategories.indexOf("Main Author");
if (firstAuthorIndex !== -1) {
Expand All @@ -78,27 +98,31 @@ function createBarCharts() {
if (activeData.length === 0) {
$("#hiddenChartsMessage").hide();
$("#hiddenChartsList").empty();
$("#chartsContainer").html("<p class='text-center mx-auto'>No studies available for the selected sidebar filters. Please select some of the criteria from the sidebar at the right.</p>");
$("#chartsContainer").html(
"<p class='text-center mx-auto'>No studies available for the selected sidebar filters. Please select some of the criteria from the sidebar at the right.</p>"
);
return;
};
}

if (activeCategories.length === 0) {
// Reset the hidden charts message and list
$("#hiddenChartsMessage").hide();
$("#hiddenChartsList").empty();
$("#chartsContainer").html("<p class='text-center mx-auto'>No studies found for the selected filters. Please select some of the criteria from the toggle menu at the top.</p>");
$("#chartsContainer").html(
"<p class='text-center mx-auto'>No studies found for the selected filters. Please select some of the criteria from the toggle menu at the top.</p>"
);
return;
}

// Create a bar chart for each active category
for (const category of activeCategories) {
// Only provide the data needed for the current category
const barData = activeData.map(entry => entry[category]);
const barData = activeData.map((entry) => entry[category]);

// Create the bar chart for the current category
createBarChart(barData, category);
}

// Update the visibility of the charts based on the maximum number of bars set in the dropdown menu
updateVisibility();
}
Expand Down Expand Up @@ -126,7 +150,7 @@ function createBarChart(barData, category) {
chartTitleElement.className = "chart-title";
chartTitleElement.innerHTML = `
<h5>${chartTitle}</h5>
<img src="${questionCirclePath}" title="${explanations[category]}" alt="Information about the category of this chart">
<img src="${questionCirclePath}" class="question-circle" title="${explanations[category]}" alt="Information about the category of this chart">
`;

const chartContainer = document.createElement("div");
Expand All @@ -137,7 +161,6 @@ function createBarChart(barData, category) {
canvas.id = "chart-" + category.replaceAll(" ", "€");
chartContainer.appendChild(canvas);


// Append the chart container to the element for all charts
$("#chartsContainer").append(chartWrapper);
chartWrapper.appendChild(chartTitleElement);
Expand Down Expand Up @@ -165,7 +188,7 @@ function createBarChartData(barData, category) {
// The keys of the occurrences will be the labels for the chart
const labels = Object.keys(occurrences).sort((a, b) => {
// Check if the labels are all convertable to numbers
if (Object.keys(occurrences).every(key => !isNaN(key))) {
if (Object.keys(occurrences).every((key) => !isNaN(key))) {
return parseFloat(a) - parseFloat(b);
}

Expand All @@ -176,13 +199,17 @@ function createBarChartData(barData, category) {

return {
labels: labels,
datasets: [{
data: labels.map(label => occurrences[label]),
backgroundColor: labels.map((_, index) => defaultColors[index % defaultColors.length]),
barThickness: "flex",
maxBarThickness: 50,
}]
}
datasets: [
{
data: labels.map((label) => occurrences[label]),
backgroundColor: labels.map(
(_, index) => defaultColors[index % defaultColors.length]
),
barThickness: "flex",
maxBarThickness: 50,
},
],
};
}

// Creating the chart options based on the category
Expand All @@ -196,43 +223,45 @@ function createChartOptions(category) {
},
tooltip: {
callbacks: {
label: function(tooltipItem) {
label: function (tooltipItem) {
return `${tooltipItem.raw} studies. Click for list!`;
}
}
},
},
},
},
scales: {
x: {
ticks: {
autoSkip: false,
callback: function(value, index, ticks) {
callback: function (value, index, ticks) {
const label = this.getLabelForValue(value);

// Limit the number of characters displayed on the x-axis
return label.length > 20 ? label.slice(0, 20) + '...' : label;
return label.length > 20 ? label.slice(0, 20) + "..." : label;
},
maxRotation: 40,
padding: 2,
}
},
},
y: {
beginAtZero: true,
ticks: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1,
}
}
},
},
},
onClick: function(event, elements, chart) {
onClick: function (event, elements, chart) {
if (elements.length === 0) return;
const label = chart.data.labels[elements[0].index];

const tableHTML = createModalHTML(category, label);
$("#modal-header-info").text(`Studies for ${category.split("_").pop()} filtered by "${label}"`);
$("#modal-header-info").text(
`Studies for ${category.split("_").pop()} filtered by "${label}"`
);
$("#rowDetailsContainerBarCharts").html(tableHTML);
$("#table-modal").modal("show");
},
}
};
}

// Finds the full category name based on the short name provided by the checkbox
Expand All @@ -249,8 +278,10 @@ function getFullCategory(category) {

function updateVisibility() {
const maxBars = parseInt($("#maxBarsDropdown").val());
const filters = JSON.parse(window.sessionStorage.getItem('filters'));
const activeCategories = filters.categoryFilters.map(cat => getFullCategory(cat)).filter(cat => cat !== undefined);
const filters = JSON.parse(window.sessionStorage.getItem("filters"));
const activeCategories = filters.categoryFilters
.map((cat) => getFullCategory(cat))
.filter((cat) => cat !== undefined);
// Remove "Main Author" category if it is in the active categories
const firstAuthorIndex = activeCategories.indexOf("Main Author");
if (firstAuthorIndex !== -1) {
Expand All @@ -264,7 +295,9 @@ function updateVisibility() {
// Hide all charts that exceed the maximum number of bars
for (const category of activeCategories) {
const chart = Chart.getChart("chart-" + category.replaceAll(" ", "€"));
const chartWrapper = document.getElementById("chart-wrapper-" + category.replaceAll(" ", "€"));
const chartWrapper = document.getElementById(
"chart-wrapper-" + category.replaceAll(" ", "€")
);

// if there are no labels, dont show the chart
if (chart.data.labels.length === 0) {
Expand All @@ -278,13 +311,19 @@ function updateVisibility() {
chartWrapper.style.display = "none";

// Add a message to the hidden charts list
$("#hiddenChartsList").append(`<li id="message-${category}"><strong>${category.split("_").pop()}</strong>: ${chart.data.labels.length} bars (exceeds threshold of ${maxBars})</li>`);
$("#hiddenChartsList").append(
`<li id="message-${category}"><strong>${category
.split("_")
.pop()}</strong>: ${
chart.data.labels.length
} bars (exceeds threshold of ${maxBars})</li>`
);
} else {
// Show the chart if it does not exceed the maximum number of bars
chartWrapper.style.display = "flex";
}
}

// If there is at least one hidden chart, show the hidden charts message
if ($("#hiddenChartsList").children().length > 0) {
$("#hiddenChartsMessage").show();
Expand All @@ -299,40 +338,40 @@ function updateVisibility() {
- Modals are set up to show study details when a info-circle is clicked
- When values in the sidebar are changed, the charts are updated accordingly
*/
$(document).ready(function() {
$(document).ready(function () {
// Create bar charts for each category that is currently selected
createBarCharts();

// When the maximum number of displayed bars is changed, create the view again
$("#maxBarsDropdown").on("change", function() {
$("#maxBarsDropdown").on("change", function () {
// Remove all existing charts and hidden messages
updateVisibility();
})
});

// Add an event listener to the every category checkbox
$(".form-check-input").on("change", function () {
$(".form-check-input").on("change", function () {
createBarCharts();
});

// Add an event listener to each value filter checkbox
$(".value-filter").on("change", function() {
$(".value-filter").on("change", function () {
createBarCharts();
});

// Add an event listener to the exclusive filters button
$(".exclusive-filter").on("click", function() {
$(".exclusive-filter").on("click", function () {
createBarCharts();
});

// Use Event Delegation to handle clicks on the info-circle images
$("#rowDetailsContainerBarCharts").on("click", ".info-circle", function(e) {
$("#rowDetailsContainerBarCharts").on("click", ".info-circle", function (e) {
const id = e.target.getAttribute("data-id");
showStudyModal(id);
});

$(".range-slider").each(function() {
this.noUiSlider.on("end", function() {
$(".range-slider").each(function () {
this.noUiSlider.on("end", function () {
createBarCharts();
});
});
});
});
Loading