Zdefiniuj strefę prywatności, aby ukryć początek i koniec swoich tras GPX. Punkty wewnątrz tego okręgu nie będą wyświetlane na mapie.';
echo '
Aby znaleźć swoje współrzędne, kliknij prawym przyciskiem myszy na mapie Google w wybranym miejscu - współrzędne pojawią się jako pierwsza pozycja w menu.
';
}
function mystat_render_lat_field() {
$options = get_option( 'mystat_privacy_options' );
$latitude = isset( $options['latitude'] ) ? esc_attr( $options['latitude'] ) : '';
echo "";
}
function mystat_render_lon_field() {
$options = get_option( 'mystat_privacy_options' );
$longitude = isset( $options['longitude'] ) ? esc_attr( $options['longitude'] ) : '';
echo "";
}
function mystat_render_radius_field() {
$options = get_option( 'mystat_privacy_options' );
$radius = isset( $options['radius'] ) ? esc_attr( $options['radius'] ) : '500';
echo " metrów";
}
function mystat_sanitize_privacy_options( $input ) {
$sanitized_input = [];
if ( isset( $input['latitude'] ) ) {
$sanitized_input['latitude'] = floatval( str_replace( ',', '.', $input['latitude'] ) );
}
if ( isset( $input['longitude'] ) ) {
$sanitized_input['longitude'] = floatval( str_replace( ',', '.', $input['longitude'] ) );
}
if ( isset( $input['radius'] ) ) {
$sanitized_input['radius'] = abs( intval( $input['radius'] ) );
}
return $sanitized_input;
}
function mystat_yearly_summary_page() {
global $wpdb;
$table_activities = $wpdb->prefix . 'mystat_activities';
$current_year = isset( $_GET['year'] ) ? intval( $_GET['year'] ) : current_time( 'Y' );
// Pobierz dostępne lata z bazy danych
$available_years = $wpdb->get_col( "SELECT DISTINCT YEAR(date) FROM $table_activities ORDER BY YEAR(date) DESC" );
if ( empty( $available_years ) ) {
$available_years = [current_time('Y')]; // Domyślny rok, jeśli brak danych
}
// Zapytanie SQL do grupowania danych miesięcznie
$sql = $wpdb->prepare("
SELECT
MONTH(date) as month_num,
SUM(distance) as total_distance,
SUM(calories) as total_calories,
SUM(TIME_TO_SEC(duration)) as total_seconds,
COUNT(id) as activity_count
FROM $table_activities
WHERE YEAR(date) = %d
GROUP BY month_num
ORDER BY month_num ASC
", $current_year);
$monthly_summary = $wpdb->get_results( $sql, OBJECT_K ); // OBJECT_K zwróci tablicę z kluczami będącymi numerami miesięcy
// Przygotowanie danych dla wszystkich 12 miesięcy
$full_year_summary = [];
$total_year_distance = 0;
$total_year_calories = 0;
$total_year_seconds = 0;
// Określ, ile miesięcy pokazać, aby uniknąć zer dla przyszłych miesięcy
$this_year = (int) current_time('Y');
$this_month = (int) current_time('n');
$loop_until_month = 12; // Domyślnie dla lat ubiegłych
if ( $current_year == $this_year ) {
// Dla bieżącego roku, pokaż miesiące do bieżącego miesiąca
$loop_until_month = $this_month;
} elseif ( $current_year > $this_year ) {
// Dla przyszłych lat, pokaż miesiące tylko do ostatniego, w którym są dane
$last_month_with_data = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(MONTH(date)) FROM $table_activities WHERE YEAR(date) = %d", $current_year ) );
$loop_until_month = $last_month_with_data ? (int) $last_month_with_data : 0;
}
for ( $i = 1; $i <= $loop_until_month; $i++ ) {
$month_name = date_i18n( 'F', mktime( 0, 0, 0, $i, 10 ) ); // Nazwa miesiąca
$data = isset( $monthly_summary[$i] ) ? $monthly_summary[$i] : null;
$full_year_summary[$i] = (object) [
'month_name' => $month_name,
'total_distance' => $data ? $data->total_distance : 0,
'total_calories' => $data ? (int)$data->total_calories : 0,
'total_seconds' => $data ? (int)$data->total_seconds : 0,
'activity_count' => $data ? (int)$data->activity_count : 0,
];
$total_year_distance += $full_year_summary[$i]->total_distance;
$total_year_seconds += $full_year_summary[$i]->total_seconds;
$total_year_calories += $full_year_summary[$i]->total_calories;
}
$total_year_hours = floor($total_year_seconds / 3600);
$total_year_minutes = floor(($total_year_seconds % 3600) / 60);
$total_year_duration_formatted = sprintf('%d godz. %d min.', $total_year_hours, $total_year_minutes);
// Przygotowanie danych dla wykresu
$chart_labels_js = [];
$chart_datasets = [
'distance' => [],
'duration' => [],
'calories' => [],
'activities' => [],
];
foreach ($full_year_summary as $month_data) {
$chart_labels_js[] = $month_data->month_name;
$chart_datasets['distance'][] = round((float)$month_data->total_distance, 2);
$chart_datasets['duration'][] = round($month_data->total_seconds / 3600, 2); // w godzinach
$chart_datasets['calories'][] = $month_data->total_calories;
$chart_datasets['activities'][] = $month_data->activity_count;
}
// Włączenie skryptów dla Chart.js
wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', [], null, true);
wp_register_script('mystat-chart-loader', false);
wp_enqueue_script('mystat-chart-loader');
$chart_configs = [
'distance' => [
'label' => 'Dystans (km)',
'data' => $chart_datasets['distance'],
'backgroundColor' => 'rgba(52, 152, 219, 0.5)',
'borderColor' => 'rgba(52, 152, 219, 1)',
'yAxisLabel' => 'Kilometry'
],
'duration' => [
'label' => 'Czas trwania (godz.)',
'data' => $chart_datasets['duration'],
'backgroundColor' => 'rgba(26, 188, 156, 0.5)',
'borderColor' => 'rgba(26, 188, 156, 1)',
'yAxisLabel' => 'Godziny'
],
'calories' => [
'label' => 'Kalorie (kcal)',
'data' => $chart_datasets['calories'],
'backgroundColor' => 'rgba(231, 76, 60, 0.5)',
'borderColor' => 'rgba(231, 76, 60, 1)',
'yAxisLabel' => 'kcal'
],
'activities' => [
'label' => 'Liczba aktywności',
'data' => $chart_datasets['activities'],
'backgroundColor' => 'rgba(241, 196, 15, 0.5)',
'borderColor' => 'rgba(241, 196, 15, 1)',
'yAxisLabel' => 'Ilość'
],
];
wp_add_inline_script('mystat-chart-loader', '
document.addEventListener("DOMContentLoaded", function() {
const chartLabels = ' . json_encode($chart_labels_js) . ';
const chartConfigs = ' . json_encode($chart_configs) . ';
let activeChart = null;
const tabs = document.querySelectorAll(".nav-tab");
tabs.forEach(tab => {
tab.addEventListener("click", function(e) {
e.preventDefault();
tabs.forEach(t => t.classList.remove("nav-tab-active"));
this.classList.add("nav-tab-active");
const chartType = this.getAttribute("href").substring(1);
renderChart(chartType);
});
});
function renderChart(type) {
if (activeChart) {
activeChart.destroy();
}
const config = chartConfigs[type];
const ctx = document.getElementById("mystatYearlyChart").getContext("2d");
activeChart = new Chart(ctx, {
type: "bar",
data: {
labels: chartLabels,
datasets: [{
label: config.label,
data: config.data,
backgroundColor: config.backgroundColor,
borderColor: config.borderColor,
borderWidth: 1
}]
},
options: {
responsive: true, maintainAspectRatio: false,
scales: { y: { beginAtZero: true, title: { display: true, text: config.yAxisLabel } } }
}
});
}
// Render initial chart
if (tabs.length > 0) {
renderChart(tabs[0].getAttribute("href").substring(1));
}
});
');
?>
Podsumowanie Roczne
Wykresy dla
Miesiąc
Dystans (km)
Kalorie (kcal)
Czas
month_name ); ?>
total_distance, 2, ',', ' ' ); ?>
total_calories, 0, ',', ' ' ); ?>
total_seconds) ); ?>
SUMA ROCZNA
20 ] );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
return [];
}
$gpx_content = wp_remote_retrieve_body( $response );
if ( empty( $gpx_content ) ) {
return [];
}
// --- Privacy Zone ---
$privacy_options = get_option( 'mystat_privacy_options' );
$privacy_enabled = false;
$privacy_center_lat = 0;
$privacy_center_lon = 0;
$privacy_radius_km = 0;
if ( ! empty( $privacy_options['latitude'] ) && ! empty( $privacy_options['longitude'] ) && ! empty( $privacy_options['radius'] ) ) {
$privacy_enabled = true;
$privacy_center_lat = (float) $privacy_options['latitude'];
$privacy_center_lon = (float) $privacy_options['longitude'];
$privacy_radius_km = ( (int) $privacy_options['radius'] ) / 1000; // Convert meters to km
}
libxml_use_internal_errors( true );
$gpx = simplexml_load_string( $gpx_content );
libxml_clear_errors();
if ( $gpx === false ) {
return [];
}
$track_data = [
'points' => [],
'elevation_profile' => [],
];
$raw_points = [];
// Extract raw points with lat, lon, ele
if ( isset( $gpx->trk ) ) {
foreach ( $gpx->trk->trkseg as $trkseg ) {
foreach ( $trkseg->trkpt as $trkpt ) {
if ( isset( $trkpt['lat'], $trkpt['lon'] ) ) {
$raw_points[] = [
'lat' => (float) $trkpt['lat'],
'lon' => (float) $trkpt['lon'],
'ele' => isset( $trkpt->ele ) ? (float) $trkpt->ele : null,
];
}
}
}
}
if ( empty( $raw_points ) ) {
return $track_data;
}
// Process raw points to calculate profile
$cumulative_distance = 0;
$elevation_profile = [];
$map_points = [];
$haversine = function( $lat1, $lon1, $lat2, $lon2 ) {
$earth_radius = 6371; // in km
$dLat = deg2rad( $lat2 - $lat1 );
$dLon = deg2rad( $lon2 - $lon1 );
$a = sin( $dLat / 2 ) * sin( $dLat / 2 ) +
cos( deg2rad( $lat1 ) ) * cos( deg2rad( $lat2 ) ) *
sin( $dLon / 2 ) * sin( $dLon / 2 );
$c = 2 * atan2( sqrt( $a ), sqrt( 1 - $a ) );
return $earth_radius * $c;
};
foreach ( $raw_points as $i => $point ) {
// Check if point is inside privacy zone
$is_in_privacy_zone = false;
if ( $privacy_enabled ) {
$distance_from_center = $haversine( $privacy_center_lat, $privacy_center_lon, $point['lat'], $point['lon'] );
if ( $distance_from_center <= $privacy_radius_km ) {
$is_in_privacy_zone = true;
}
}
// Only process points outside the privacy zone
if ( ! $is_in_privacy_zone ) {
$map_points[] = [ $point['lat'], $point['lon'] ];
if ( $i > 0 ) {
$prev_point = $raw_points[ $i - 1 ];
$cumulative_distance += $haversine( $prev_point['lat'], $prev_point['lon'], $point['lat'], $point['lon'] );
}
if ( ! is_null( $point['ele'] ) ) {
$elevation_profile[] = [ 'distance' => round( $cumulative_distance, 3 ), 'elevation' => round( $point['ele'], 2 ) ];
}
}
}
$track_data['points'] = $map_points;
$track_data['elevation_profile'] = $elevation_profile;
return $track_data;
}
function mystat_infographic_page() {
global $wpdb;
$table_activities = $wpdb->prefix . 'mystat_activities';
$table_categories = $wpdb->prefix . 'mystat_categories';
$current_year = isset( $_GET['year'] ) ? intval( $_GET['year'] ) : current_time( 'Y' );
// Pobierz dostępne lata z bazy danych
$available_years = $wpdb->get_col( "SELECT DISTINCT YEAR(date) FROM $table_activities ORDER BY YEAR(date) DESC" );
if ( empty( $available_years ) ) {
$available_years = [current_time('Y')]; // Domyślny rok, jeśli brak danych
}
// --- 1. Statystyki ogólne (wszystkie lata) ---
$overall_stats = $wpdb->get_row("
SELECT
SUM(distance) as total_distance,
SEC_TO_TIME(SUM(TIME_TO_SEC(duration))) as total_duration,
SUM(total_elevation_gain) as total_elevation_gain,
COUNT(id) as total_activities
FROM $table_activities
");
// --- 2. Statystyki dla wybranego roku ---
$yearly_stats = $wpdb->get_row($wpdb->prepare("
SELECT
SUM(distance) as total_distance,
SEC_TO_TIME(SUM(TIME_TO_SEC(duration))) as total_duration,
SUM(total_elevation_gain) as total_elevation_gain,
COUNT(id) as total_activities
FROM $table_activities
WHERE YEAR(date) = %d
", $current_year));
// --- 3. Dane dla wykresu kołowego (dystans per kategoria dla wybranego roku) ---
$category_distance_data = $wpdb->get_results($wpdb->prepare("
SELECT c.name as category_name, c.color, SUM(a.distance) as total_distance
FROM $table_activities a
LEFT JOIN $table_categories c ON a.category_id = c.id
WHERE YEAR(a.date) = %d
GROUP BY c.name, c.color
HAVING SUM(a.distance) > 0
ORDER BY total_distance DESC
", $current_year));
$chart_labels = [];
$chart_data = [];
$chart_colors = [];
foreach ($category_distance_data as $data) {
$chart_labels[] = $data->category_name;
$chart_data[] = round((float)$data->total_distance, 2);
$chart_colors[] = $data->color;
}
// Włączenie skryptów dla Chart.js
wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', [], null, true);
wp_register_script('mystat-infographic-chart-loader', false);
wp_enqueue_script('mystat-infographic-chart-loader');
wp_add_inline_script('mystat-infographic-chart-loader', '
document.addEventListener("DOMContentLoaded", function() {
const ctx = document.getElementById("mystatCategoryPieChart");
if (!ctx) return;
new Chart(ctx, {
type: "pie",
data: {
labels: ' . json_encode($chart_labels) . ',
datasets: [{
data: ' . json_encode($chart_data) . ',
backgroundColor: ' . json_encode($chart_colors) . ',
hoverOffset: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: "right",
},
title: {
display: true,
text: "Dystans wg kategorii w ' . esc_js($current_year) . '"
}
}
}
});
});
');
?>
Infografika Statystyk Sportowych
Statystyki Ogólne (wszystkie lata)
Dystans
total_distance, 2, ',', ' '); ?> km
Czas
total_duration); ?>
Wznios
total_elevation_gain, 0, ',', ' '); ?> m
Aktywności
total_activities, 0, ',', ' '); ?>
Statystyki dla
Dystans
total_distance, 2, ',', ' '); ?> km
Czas
total_duration); ?>
Wznios
total_elevation_gain, 0, ',', ' '); ?> m
Aktywności
total_activities, 0, ',', ' '); ?>
Rozkład Dystansu wg Kategorii w
Importuj aktywności z pliku CSV
';
// Handle the form submission
if ( 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $_POST['mystat_csv_import_nonce_field'] ) ) {
mystat_handle_csv_import();
}
// Display the form
?>
Instrukcje i formularz importu
Aby zaimportować dane, możesz wgrać plik CSV LUB wkleić dane bezpośrednio w pole tekstowe poniżej. Ta druga opcja jest zalecana, jeśli napotykasz błędy z plikiem.
Wymagane kolumny:Data, Tytuł, Dystans oraz Typ aktywności (lub Kategoria).
Dystans i prędkość: użyj kropki jako separatora dziesiętnego (np. 10.5).
Nazwy w kolumnach Typ aktywności, Sprzęt, Typ wydarzenia muszą dokładnie odpowiadać nazwom zdefiniowanym w ustawieniach wtyczki. Jeśli nazwa nie zostanie znaleziona, wiersz zostanie pominięty.
';
}
function mystat_handle_csv_import() {
global $wpdb;
if ( ! isset( $_POST['mystat_csv_import_nonce_field'] ) || ! wp_verify_nonce( $_POST['mystat_csv_import_nonce_field'], 'mystat_csv_import_nonce' ) ) {
echo '
';
}
// Pobieranie danych z bazy
$table_activities = $wpdb->prefix . 'mystat_activities';
$sql = $wpdb->prepare("
SELECT a.*, c.name as category_name, c.color as category_color, et.name as event_type_name, eq.name as equipment_name
FROM $table_activities a
LEFT JOIN {$wpdb->prefix}mystat_categories c ON a.category_id = c.id
LEFT JOIN {$wpdb->prefix}mystat_event_types et ON a.event_type_id = et.id
LEFT JOIN {$wpdb->prefix}mystat_equipment eq ON a.equipment_id = eq.id
WHERE a.id = %d
", $activity_id);
$activity = $wpdb->get_row( $sql );
if ( ! $activity ) {
return '
Błąd: Nie znaleziono wpisu o ID ' . esc_html($activity_id) . '.