f1tness_parser/app/static/js/main.js
2026-10-22 23:46:29 +03:00

111 lines
4.1 KiB
JavaScript

/**
* Main JavaScript file for Fitness Parser
* Uses jQuery for DOM manipulation
*/
$(document).ready(function() {
console.log('Fitness Parser JS loaded');
// Simple example functionality
$('.card').on('click', function() {
$(this).toggleClass('bg-light');
});
// Bootstrap tooltips (explanations of the metrics)
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(
(element) => new bootstrap.Tooltip(element)
);
// Exercise search: open the history right after a suggestion is picked from the list.
// Typing, pasting and deleting have their own inputType, so a half-typed name that
// equals a shorter exercise name doesn't submit early; Enter/button always work.
const $exerciseInput = $('#exercise-input');
if ($exerciseInput.length) {
const exerciseNames = new Set(
$('#exercise-names option').map((_, option) => option.value).get()
);
$exerciseInput.on('input', function(event) {
const inputType = event.originalEvent && event.originalEvent.inputType;
const picked = !inputType || inputType === 'insertReplacementText';
if (picked && exerciseNames.has(this.value)) {
this.form.submit();
}
});
}
// Exercise progress chart (Chart.js): two series over time, each on its own y axis.
// Points are [UTC timestamp in ms, value]; the x axis is linear so gaps between
// trainings are proportional to the real time.
const chartDataElement = document.getElementById('progress-chart-data');
if (chartDataElement && window.Chart) {
const series = JSON.parse(chartDataElement.textContent).series;
const colors = ['#0d6efd', '#fd7e14'];
const formatDate = (timestamp, options) =>
new Date(timestamp).toLocaleDateString('ru-RU', { ...options, timeZone: 'UTC' });
const scales = {
x: {
type: 'linear',
ticks: {
maxTicksLimit: 8,
callback: (value) => formatDate(value, { month: 'short', year: 'numeric' }),
},
},
};
series.forEach((item, index) => {
scales['y' + index] = {
position: index === 0 ? 'left' : 'right',
grid: { drawOnChartArea: index === 0 },
title: { display: true, text: item.label, color: colors[index] },
};
});
new Chart(document.getElementById('progress-chart'), {
type: 'line',
data: {
datasets: series.map((item, index) => ({
label: item.label,
data: item.points.map(([x, y]) => ({ x, y })),
yAxisID: 'y' + index,
borderColor: colors[index],
backgroundColor: colors[index],
borderWidth: 2,
pointRadius: 3,
tension: 0.2,
})),
},
options: {
maintainAspectRatio: false,
interaction: { mode: 'nearest', axis: 'x', intersect: false },
scales,
plugins: {
tooltip: {
callbacks: {
title: (items) => formatDate(items[0].parsed.x, {}),
},
},
},
},
});
}
// Tables with search, sorting and paging by DataTables
const tableOptions = {
pageLength: 50,
lengthMenu: [25, 50, 100, 200],
order: [], // keep the order from the server: newest training first
language: { url: document.body.dataset.datatablesLang },
};
// All trainings: date, trainer, exercise, approaches
$('#trainings-table').DataTable({
...tableOptions,
columnDefs: [{ targets: 3, orderable: false }], // approaches
});
// History of one exercise: date, trainer, approaches, max weight
$('#exercise-history-table').DataTable({
...tableOptions,
columnDefs: [{ targets: 2, orderable: false }], // approaches
});
});