Add interactive Base 4 track map with Leaflet.js

- Created new track-map page with aerial image and SVG overlay
- Implemented custom rotated square markers with obstacle numbers
- Added admin edit mode for placing and repositioning markers
- Database migration for track_obstacles table
- Modal form for adding new obstacles (replaces browser alerts)
- Drag-to-reposition functionality with auto-save
- Color-coded markers (green/red/black/split) for difficulty levels
- Clickable popups showing obstacle details
- Added track-map to navigation menu and sitemap
- URL rewrite rule for clean /track-map URL
This commit is contained in:
twotalesanimation
2025-12-12 12:00:20 +02:00
parent 48ee7592b2
commit cce181e2d0
15 changed files with 14213 additions and 107 deletions

View File

@@ -0,0 +1,164 @@
<?php
/**
* TRACK OBSTACLES API ENDPOINT
*
* Returns all track obstacles as JSON for the interactive map.
*
* Usage:
* GET /src/processors/track-obstacles.php?action=getAll
*
* Response:
* {
* "status": "success",
* "data": [
* {
* "obstacle_id": 1,
* "name": "Rock Crawl",
* "x_position": 150,
* "y_position": 200,
* "difficulty": "medium",
* "description": "Navigate through rocky terrain...",
* "image_path": "assets/images/obstacles/obstacle1.jpg",
* "marker_color": "green"
* },
* ...
* ]
* }
*/
// Set headers for JSON response
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
// Load configuration and database
$rootPath = dirname(dirname(__DIR__));
require_once($rootPath . "/src/config/env.php");
require_once($rootPath . "/src/config/connection.php");
require_once($rootPath . "/src/config/functions.php");
require_once($rootPath . "/classes/DatabaseService.php");
// Get database instance
$db = new DatabaseService($conn);
try {
// Get action from query string
$action = $_GET['action'] ?? 'getAll';
if ($action === 'getAll') {
// Fetch all obstacles from the database
$sql = "SELECT
obstacle_id,
obstacle_number,
name,
x_position,
y_position,
difficulty,
description,
image_path,
marker_color
FROM track_obstacles
ORDER BY obstacle_id ASC";
$result = $conn->query($sql);
if ($result === false) {
throw new Exception("Database query failed: " . $conn->error);
}
$obstacles = [];
while ($row = $result->fetch_assoc()) {
$obstacles[] = $row;
}
echo json_encode([
'status' => 'success',
'data' => $obstacles
]);
} elseif ($action === 'create') {
// Create new obstacle (superadmin only)
$role = getUserRole();
if ($role !== 'superadmin') {
http_response_code(403);
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$sql = "INSERT INTO track_obstacles
(obstacle_number, name, x_position, y_position, difficulty, description, marker_color)
VALUES (?, ?, ?, ?, ?, ?, ?)";
$insertId = $db->insert($sql, [
$input['obstacle_number'],
$input['name'],
$input['x_position'],
$input['y_position'],
$input['difficulty'],
$input['description'],
$input['marker_color']
], 'ssiisss');
if ($insertId) {
echo json_encode([
'status' => 'success',
'message' => 'Obstacle created',
'obstacle_id' => $insertId
]);
} else {
throw new Exception("Failed to create obstacle: " . $db->getLastError());
}
} elseif ($action === 'updatePosition') {
// Update obstacle position (superadmin only)
$role = getUserRole();
if ($role !== 'superadmin') {
http_response_code(403);
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$sql = "UPDATE track_obstacles
SET x_position = ?, y_position = ?
WHERE obstacle_id = ?";
$result = $db->update($sql, [
$input['x_position'],
$input['y_position'],
$input['obstacle_id']
], 'iii');
if ($result !== false) {
echo json_encode([
'status' => 'success',
'message' => 'Position updated'
]);
} else {
throw new Exception("Failed to update position: " . $db->getLastError());
}
} else {
// Invalid action
http_response_code(400);
echo json_encode([
'status' => 'error',
'message' => 'Invalid action specified'
]);
}
} catch (Exception $e) {
// Return error response
http_response_code(500);
echo json_encode([
'status' => 'error',
'message' => 'Server error: ' . $e->getMessage()
]);
}
exit();
?>