Map
This commit is contained in:
@@ -109,6 +109,44 @@ function mystat_activate() {
|
|||||||
// --- 2. MENU ADMINA I DASHBOARD ---
|
// --- 2. MENU ADMINA I DASHBOARD ---
|
||||||
add_action( 'admin_menu', 'mystat_add_admin_menu' );
|
add_action( 'admin_menu', 'mystat_add_admin_menu' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up admin-specific hooks.
|
||||||
|
*/
|
||||||
|
function mystat_admin_init_setup() {
|
||||||
|
add_filter( 'upload_mimes', 'mystat_add_gpx_mime_type' );
|
||||||
|
add_filter( 'wp_check_filetype_and_ext', 'mystat_fix_gpx_upload_permission', 10, 4 );
|
||||||
|
}
|
||||||
|
add_action( 'admin_init', 'mystat_admin_init_setup' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add GPX support to WordPress Media Library.
|
||||||
|
*
|
||||||
|
* @param array $mimes Allowed mime types.
|
||||||
|
* @return array Modified mime types.
|
||||||
|
*/
|
||||||
|
function mystat_add_gpx_mime_type( $mimes ) {
|
||||||
|
$mimes['gpx'] = 'application/gpx+xml';
|
||||||
|
return $mimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bypasses WordPress's strict file type check for GPX files.
|
||||||
|
* This is needed because WordPress can be overly cautious with XML-based files.
|
||||||
|
*
|
||||||
|
* @param array $data File data.
|
||||||
|
* @param string $file Full path to the file.
|
||||||
|
* @param string $filename The filename.
|
||||||
|
* @param array $mimes Mime types.
|
||||||
|
* @return array Modified file data.
|
||||||
|
*/
|
||||||
|
function mystat_fix_gpx_upload_permission( $data, $file, $filename, $mimes ) {
|
||||||
|
if ( strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) ) === 'gpx' ) {
|
||||||
|
$data['ext'] = 'gpx';
|
||||||
|
$data['type'] = 'application/gpx+xml';
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
function mystat_add_admin_menu() {
|
function mystat_add_admin_menu() {
|
||||||
add_menu_page(
|
add_menu_page(
|
||||||
'Moje Statystyki', // Tytuł strony
|
'Moje Statystyki', // Tytuł strony
|
||||||
@@ -164,6 +202,15 @@ function mystat_add_admin_menu() {
|
|||||||
'mystat-edit-activity', // Slug podmenu
|
'mystat-edit-activity', // Slug podmenu
|
||||||
'mystat_edit_activity_page' // Funkcja renderująca
|
'mystat_edit_activity_page' // Funkcja renderująca
|
||||||
);
|
);
|
||||||
|
|
||||||
|
add_submenu_page(
|
||||||
|
'moje-statystyki', // Slug rodzica
|
||||||
|
'Podsumowanie Roczne', // Tytuł strony
|
||||||
|
'Podsumowanie Roczne', // Tytuł w podmenu
|
||||||
|
'manage_options', // Wymagane uprawnienia
|
||||||
|
'mystat-yearly-summary', // Slug podmenu
|
||||||
|
'mystat_yearly_summary_page'// Funkcja renderująca
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mystat_dashboard_page() {
|
function mystat_dashboard_page() {
|
||||||
@@ -349,6 +396,201 @@ function mystat_equipment_page() {
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
SEC_TO_TIME(SUM(TIME_TO_SEC(duration))) as total_duration
|
||||||
|
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;
|
||||||
|
|
||||||
|
for ( $i = 1; $i <= 12; $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 ? $data->total_calories : 0,
|
||||||
|
'total_duration' => $data ? $data->total_duration : '00:00:00',
|
||||||
|
];
|
||||||
|
|
||||||
|
$total_year_distance += $full_year_summary[$i]->total_distance;
|
||||||
|
$total_year_calories += $full_year_summary[$i]->total_calories;
|
||||||
|
if ( $data && ! empty( $data->total_duration ) ) {
|
||||||
|
list($h, $m, $s) = explode(':', $data->total_duration);
|
||||||
|
$total_year_seconds += $h * 3600 + $m * 60 + $s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$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 = [];
|
||||||
|
$chart_data_distance = [];
|
||||||
|
foreach ($full_year_summary as $month_data) {
|
||||||
|
$chart_labels[] = $month_data->month_name;
|
||||||
|
$chart_data_distance[] = round((float)$month_data->total_distance, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
wp_add_inline_script('mystat-chart-loader', '
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const ctx = document.getElementById("mystatYearlyChart");
|
||||||
|
if (!ctx) return;
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: "bar",
|
||||||
|
data: {
|
||||||
|
labels: ' . json_encode($chart_labels) . ',
|
||||||
|
datasets: [{
|
||||||
|
label: "Dystans (km)",
|
||||||
|
data: ' . json_encode($chart_data_distance) . ',
|
||||||
|
backgroundColor: "rgba(52, 152, 219, 0.5)",
|
||||||
|
borderColor: "rgba(52, 152, 219, 1)",
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
title: { display: true, text: "Kilometry" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
');
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1>Podsumowanie Roczne</h1>
|
||||||
|
|
||||||
|
<div class="tablenav top">
|
||||||
|
<div class="alignleft actions">
|
||||||
|
<label for="filter-by-year" class="screen-reader-text">Filtruj według roku</label>
|
||||||
|
<form method="get" style="display: flex; gap: 5px; align-items: center;">
|
||||||
|
<input type="hidden" name="page" value="mystat-yearly-summary">
|
||||||
|
<select name="year" id="filter-by-year">
|
||||||
|
<?php foreach ( $available_years as $year_option ) : ?>
|
||||||
|
<option value="<?php echo esc_attr( $year_option ); ?>" <?php selected( $current_year, $year_option ); ?>><?php echo esc_html( $year_option ); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<?php submit_button( 'Filtruj', 'secondary', 'filter_action', false ); ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="postbox" style="margin-bottom: 20px;">
|
||||||
|
<div class="postbox-header"><h2 class="hndle">Wykres Dystansu w <?php echo esc_html($current_year); ?></h2></div>
|
||||||
|
<div class="inside">
|
||||||
|
<div style="position: relative; height:40vh; width:100%;">
|
||||||
|
<canvas id="mystatYearlyChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="wp-list-table widefat fixed striped">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Miesiąc</th><th>Dystans (km)</th><th>Kalorie (kcal)</th><th>Czas</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ( $full_year_summary as $month_data ) : ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo esc_html( $month_data->month_name ); ?></td>
|
||||||
|
<td><?php echo number_format( $month_data->total_distance, 2, ',', ' ' ); ?></td>
|
||||||
|
<td><?php echo number_format( $month_data->total_calories, 0, ',', ' ' ); ?></td>
|
||||||
|
<td><?php echo esc_html( $month_data->total_duration ); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<tr class="alternate">
|
||||||
|
<th>SUMA ROCZNA</th>
|
||||||
|
<th><?php echo number_format( $total_year_distance, 2, ',', ' ' ); ?></th>
|
||||||
|
<th><?php echo number_format( $total_year_calories, 0, ',', ' ' ); ?></th>
|
||||||
|
<th><?php echo esc_html( $total_year_duration_formatted ); ?></th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and parses a GPX file from a URL to extract track points.
|
||||||
|
*
|
||||||
|
* @param string $gpx_url The URL of the GPX file.
|
||||||
|
* @return array An array of [lat, lon] coordinates, or an empty array on failure.
|
||||||
|
*/
|
||||||
|
function mystat_get_track_from_gpx_url( $gpx_url ) {
|
||||||
|
if ( empty( $gpx_url ) ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = wp_remote_get( $gpx_url, [ 'timeout' => 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 [];
|
||||||
|
}
|
||||||
|
|
||||||
|
libxml_use_internal_errors( true );
|
||||||
|
$gpx = simplexml_load_string( $gpx_content );
|
||||||
|
libxml_clear_errors();
|
||||||
|
|
||||||
|
if ( $gpx === false ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$points = [];
|
||||||
|
if ( isset( $gpx->trk ) ) {
|
||||||
|
foreach ( $gpx->trk->trkseg as $trkseg ) {
|
||||||
|
foreach ( $trkseg->trkpt as $trkpt ) {
|
||||||
|
if ( isset( $trkpt['lat'] ) && isset( $trkpt['lon'] ) ) {
|
||||||
|
$points[] = [ (float) $trkpt['lat'], (float) $trkpt['lon'] ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $points;
|
||||||
|
}
|
||||||
|
|
||||||
function mystat_edit_activity_page() {
|
function mystat_edit_activity_page() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$activity_id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0;
|
$activity_id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0;
|
||||||
@@ -414,6 +656,39 @@ function mystat_view_activity_page() {
|
|||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Prepare map data if GPX exists
|
||||||
|
$track_points = [];
|
||||||
|
if ( ! empty( $activity->gpx_url ) ) {
|
||||||
|
// Note: For performance, you might want to cache the parsed points in post meta
|
||||||
|
// rather than parsing the file on every page load.
|
||||||
|
$track_points = mystat_get_track_from_gpx_url( $activity->gpx_url );
|
||||||
|
|
||||||
|
if ( ! empty( $track_points ) ) {
|
||||||
|
// Enqueue Leaflet assets. For simplicity, this is done here.
|
||||||
|
// A better approach is to use the 'admin_enqueue_scripts' hook.
|
||||||
|
wp_enqueue_style('leaflet-css', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css');
|
||||||
|
wp_enqueue_script('leaflet-js', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js', [], '1.9.4', true);
|
||||||
|
|
||||||
|
// Pass track data to a script
|
||||||
|
wp_register_script('mystat-map-loader', false);
|
||||||
|
wp_enqueue_script('mystat-map-loader');
|
||||||
|
wp_add_inline_script('mystat-map-loader',
|
||||||
|
'const mystat_track_points = ' . json_encode($track_points) . ';' .
|
||||||
|
'document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
if (typeof L === "undefined" || typeof mystat_track_points === "undefined" || mystat_track_points.length === 0) return;
|
||||||
|
const map = L.map("mystat-activity-map");
|
||||||
|
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
|
attribution: \'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors\'
|
||||||
|
}).addTo(map);
|
||||||
|
const polyline = L.polyline(mystat_track_points, {color: "#' . esc_js( ltrim($activity->color, '#') ) . '"}).addTo(map);
|
||||||
|
map.fitBounds(polyline.getBounds().pad(0.1));
|
||||||
|
L.marker(mystat_track_points[0]).addTo(map).bindPopup("Start");
|
||||||
|
L.marker(mystat_track_points[mystat_track_points.length - 1]).addTo(map).bindPopup("Koniec");
|
||||||
|
});'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
@@ -469,6 +744,19 @@ function mystat_view_activity_page() {
|
|||||||
<tr><th scope="row">Plik GPX</th><td><a href="<?php echo esc_url( $activity->gpx_url ); ?>" target="_blank">Pobierz plik GPX</a></td></tr>
|
<tr><th scope="row">Plik GPX</th><td><a href="<?php echo esc_url( $activity->gpx_url ); ?>" target="_blank">Pobierz plik GPX</a></td></tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<?php if ( ! empty( $track_points ) ) : ?>
|
||||||
|
<hr>
|
||||||
|
<h3>Mapa Trasy</h3>
|
||||||
|
<div id="mystat-activity-map" style="height: 450px; width: 100%; border: 1px solid #ddd;"></div>
|
||||||
|
<?php elseif ( ! empty( $activity->gpx_url ) ) : ?>
|
||||||
|
<hr>
|
||||||
|
<h3>Mapa Trasy</h3>
|
||||||
|
<div class="notice notice-warning inline">
|
||||||
|
<p>Nie udało się wczytać danych z pliku GPX lub plik jest uszkodzony/pusty.</p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -562,6 +850,9 @@ function mystat_handle_activity_form_submission() {
|
|||||||
* Renderowanie formularza HTML
|
* Renderowanie formularza HTML
|
||||||
*/
|
*/
|
||||||
function mystat_render_add_form( $activity = null ) {
|
function mystat_render_add_form( $activity = null ) {
|
||||||
|
// Enqueue media scripts for the uploader
|
||||||
|
wp_enqueue_media();
|
||||||
|
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$table_categories = $wpdb->prefix . 'mystat_categories';
|
$table_categories = $wpdb->prefix . 'mystat_categories';
|
||||||
$table_event_types = $wpdb->prefix . 'mystat_event_types';
|
$table_event_types = $wpdb->prefix . 'mystat_event_types';
|
||||||
@@ -689,11 +980,35 @@ function mystat_render_add_form( $activity = null ) {
|
|||||||
<th scope="row"><label for="strava_url">Link do Strava</label></th>
|
<th scope="row"><label for="strava_url">Link do Strava</label></th>
|
||||||
<td><input type="url" name="strava_url" id="strava_url" class="large-text" placeholder="https://www.strava.com/activities/..." value="<?php echo $is_edit_mode ? esc_attr( $activity->strava_url ) : ''; ?>"></td>
|
<td><input type="url" name="strava_url" id="strava_url" class="large-text" placeholder="https://www.strava.com/activities/..." value="<?php echo $is_edit_mode ? esc_attr( $activity->strava_url ) : ''; ?>"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><label for="gpx_url">Link do pliku GPX</label></th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="gpx_url" id="gpx_url" class="large-text" placeholder="Wklej URL lub wgraj plik..." value="<?php echo $is_edit_mode ? esc_attr( $activity->gpx_url ) : ''; ?>">
|
||||||
|
<button type="button" class="button" id="upload_gpx_button" style="margin-top: 5px;">Wgraj lub wybierz plik</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p class="submit">
|
<p class="submit">
|
||||||
<input type="submit" name="mystat_submit_activity" id="submit" class="button button-primary" value="<?php echo esc_attr( $button_text ); ?>">
|
<input type="submit" name="mystat_submit_activity" id="submit" class="button button-primary" value="<?php echo esc_attr( $button_text ); ?>">
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
$('#upload_gpx_button').click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var gpx_uploader = wp.media({
|
||||||
|
title: 'Wybierz plik GPX',
|
||||||
|
button: { text: 'Użyj tego pliku' },
|
||||||
|
multiple: false,
|
||||||
|
library: { type: ['application/gpx+xml', 'application/xml', 'text/plain'] }
|
||||||
|
})
|
||||||
|
.on('select', function() {
|
||||||
|
var attachment = gpx_uploader.state().get('selection').first().toJSON();
|
||||||
|
$('#gpx_url').val(attachment.url).trigger('change');
|
||||||
|
}).open();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
@@ -991,6 +1306,45 @@ function mystat_single_activity_shortcode_handler( $atts ) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
|
|
||||||
|
// Prepare map data if GPX exists
|
||||||
|
$track_points = [];
|
||||||
|
if ( ! empty( $activity->gpx_url ) ) {
|
||||||
|
$track_points = mystat_get_track_from_gpx_url( $activity->gpx_url );
|
||||||
|
|
||||||
|
if ( ! empty( $track_points ) ) {
|
||||||
|
// Enqueue scripts for the frontend
|
||||||
|
wp_enqueue_style('leaflet-css', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css');
|
||||||
|
wp_enqueue_script('leaflet-js', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js', [], '1.9.4', true);
|
||||||
|
|
||||||
|
$map_id = 'mystat-map-' . esc_attr( $activity->id );
|
||||||
|
|
||||||
|
// Pass track data to a script
|
||||||
|
wp_register_script('mystat-shortcode-map-loader-' . $activity->id, false);
|
||||||
|
wp_enqueue_script('mystat-shortcode-map-loader-' . $activity->id);
|
||||||
|
wp_add_inline_script('mystat-shortcode-map-loader-' . $activity->id,
|
||||||
|
'(function() {
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
if (typeof L === "undefined") return;
|
||||||
|
const trackPoints = ' . json_encode( $track_points ) . ';
|
||||||
|
const mapId = "' . esc_js($map_id) . '";
|
||||||
|
|
||||||
|
var container = L.DomUtil.get(mapId);
|
||||||
|
if(container != null) { container._leaflet_id = null; }
|
||||||
|
|
||||||
|
const map = L.map(mapId);
|
||||||
|
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
|
attribution: \'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>\'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
const polyline = L.polyline(trackPoints, {color: "#3498db"}).addTo(map);
|
||||||
|
map.fitBounds(polyline.getBounds().pad(0.1));
|
||||||
|
});
|
||||||
|
})();'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<div class="mystat-single-activity-shortcode">
|
<div class="mystat-single-activity-shortcode">
|
||||||
<h4><?php echo esc_html( $activity->title ); ?></h4>
|
<h4><?php echo esc_html( $activity->title ); ?></h4>
|
||||||
@@ -1009,6 +1363,10 @@ function mystat_single_activity_shortcode_handler( $atts ) {
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<?php if ( ! empty( $track_points ) ) : ?>
|
||||||
|
<div id="<?php echo $map_id; ?>" style="height: 350px; width: 100%; margin-top: 15px; border-radius: 5px;"></div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
.mystat-single-activity-shortcode { border: 1px solid #eee; padding: 15px; margin-bottom: 1.5em; border-radius: 5px; background: #f9f9f9; }
|
.mystat-single-activity-shortcode { border: 1px solid #eee; padding: 15px; margin-bottom: 1.5em; border-radius: 5px; background: #f9f9f9; }
|
||||||
|
|||||||
Reference in New Issue
Block a user