mirror of
https://github.com/seemueller-io/yachtpit.git
synced 2025-09-08 22:46:45 +00:00

* WIP: Enable dynamic AIS stream handling based on user location and map focus. - Prevent AIS stream from starting immediately; start upon user interaction. - Add `ais_stream_started` state for WebSocket management. - Extend `useRealAISProvider` with `userLocationLoaded` and `mapFocused` to control stream. - Update frontend components to handle geolocation and map focus. - Exclude test files from compilation Introduce WebSocket integration for AIS services - Added WebSocket-based `useRealAISProvider` React hook for real-time AIS vessel data. - Created various tests including unit, integration, and browser tests to validate WebSocket functionality. - Added `ws` dependency to enable WebSocket communication. - Implemented vessel data mapping and bounding box handling for dynamic updates. * **Introduce Neumorphic UI design with new themes and styles** - Added NeumorphicTheme implementation for light and dark modes. - Refactored `LayerSelector` and `MapNext` components to use the neumorphic style and color utilities. - Updated `menu.rs` with neumorphic-inspired button and background styling. - Enhanced GPS feed and vessel popups with neumorphic visuals, improving clarity and aesthetics. - Temporarily disabled base-map dependency in `yachtpit` for isolation testing. * update names in layer selector * Update search button text to "Search..." for better clarity. * Add key event handlers for search and result selection in App.tsx * Implement AIS Test Map application with WebSocket-based vessel tracking and Mapbox integration. * Refactor AIS server to use Axum framework with shared stream manager and state handling. Fix metadata key mismatch in frontend vessel mapper. * Remove AIS provider integration and related vessel markers * Remove `ais-test-map` application, including dependencies, configuration, and source files. * ais data feed functional, bb query is overshot, performance degraded * Add AIS module as a build dependency --------- Co-authored-by: geoffsee <>
134 lines
5.3 KiB
HTML
134 lines
5.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>AIS WebSocket Browser Test</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
.status { padding: 10px; margin: 10px 0; border-radius: 5px; }
|
|
.connected { background-color: #d4edda; color: #155724; }
|
|
.disconnected { background-color: #f8d7da; color: #721c24; }
|
|
.error { background-color: #fff3cd; color: #856404; }
|
|
.message { background-color: #f8f9fa; padding: 10px; margin: 5px 0; border-left: 3px solid #007bff; }
|
|
.vessel-data { background-color: #e7f3ff; padding: 10px; margin: 5px 0; border-left: 3px solid #28a745; }
|
|
#messages { max-height: 400px; overflow-y: auto; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>AIS WebSocket Browser Test</h1>
|
|
<div id="status" class="status disconnected">Disconnected</div>
|
|
<button id="connectBtn">Connect</button>
|
|
<button id="disconnectBtn" disabled>Disconnect</button>
|
|
<button id="setBoundingBoxBtn" disabled>Set Bounding Box</button>
|
|
|
|
<h2>Messages</h2>
|
|
<div id="messages"></div>
|
|
|
|
<script>
|
|
let ws = null;
|
|
const statusDiv = document.getElementById('status');
|
|
const messagesDiv = document.getElementById('messages');
|
|
const connectBtn = document.getElementById('connectBtn');
|
|
const disconnectBtn = document.getElementById('disconnectBtn');
|
|
const setBoundingBoxBtn = document.getElementById('setBoundingBoxBtn');
|
|
|
|
function updateStatus(message, className) {
|
|
statusDiv.textContent = message;
|
|
statusDiv.className = `status ${className}`;
|
|
}
|
|
|
|
function addMessage(message, className = 'message') {
|
|
const div = document.createElement('div');
|
|
div.className = className;
|
|
div.innerHTML = `<strong>${new Date().toLocaleTimeString()}</strong>: ${message}`;
|
|
messagesDiv.appendChild(div);
|
|
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
|
}
|
|
|
|
function connect() {
|
|
if (ws && ws.readyState === WebSocket.OPEN) return;
|
|
|
|
updateStatus('Connecting...', 'error');
|
|
ws = new WebSocket('ws://localhost:3000/ws');
|
|
|
|
ws.onopen = function() {
|
|
updateStatus('Connected', 'connected');
|
|
addMessage('Connected to AIS WebSocket server');
|
|
connectBtn.disabled = true;
|
|
disconnectBtn.disabled = false;
|
|
setBoundingBoxBtn.disabled = false;
|
|
};
|
|
|
|
ws.onmessage = function(event) {
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
|
|
// Handle different message types
|
|
if (typeof data === 'string' || data.type) {
|
|
addMessage(`Server message: ${JSON.stringify(data)}`);
|
|
} else if (data.mmsi) {
|
|
// AIS vessel data
|
|
const vesselInfo = `
|
|
<strong>Vessel Data:</strong><br>
|
|
MMSI: ${data.mmsi || 'N/A'}<br>
|
|
Name: ${data.ship_name || 'N/A'}<br>
|
|
Position: ${data.latitude || 'N/A'}, ${data.longitude || 'N/A'}<br>
|
|
Speed: ${data.speed_over_ground || 'N/A'} knots<br>
|
|
Course: ${data.course_over_ground || 'N/A'}°<br>
|
|
Type: ${data.ship_type || 'N/A'}
|
|
`;
|
|
addMessage(vesselInfo, 'vessel-data');
|
|
} else {
|
|
addMessage(`Unknown data: ${JSON.stringify(data)}`);
|
|
}
|
|
} catch (e) {
|
|
addMessage(`Raw message: ${event.data}`);
|
|
}
|
|
};
|
|
|
|
ws.onerror = function(error) {
|
|
updateStatus('Error', 'error');
|
|
addMessage(`WebSocket error: ${error}`);
|
|
};
|
|
|
|
ws.onclose = function(event) {
|
|
updateStatus('Disconnected', 'disconnected');
|
|
addMessage(`Connection closed: ${event.code} - ${event.reason}`);
|
|
connectBtn.disabled = false;
|
|
disconnectBtn.disabled = true;
|
|
setBoundingBoxBtn.disabled = true;
|
|
};
|
|
}
|
|
|
|
function disconnect() {
|
|
if (ws) {
|
|
ws.close();
|
|
}
|
|
}
|
|
|
|
function setBoundingBox() {
|
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
const message = {
|
|
type: 'set_bounding_box',
|
|
bounding_box: {
|
|
sw_lat: 33.7,
|
|
sw_lon: -118.3,
|
|
ne_lat: 33.8,
|
|
ne_lon: -118.2
|
|
}
|
|
};
|
|
ws.send(JSON.stringify(message));
|
|
addMessage('Sent bounding box configuration');
|
|
}
|
|
}
|
|
|
|
connectBtn.addEventListener('click', connect);
|
|
disconnectBtn.addEventListener('click', disconnect);
|
|
setBoundingBoxBtn.addEventListener('click', setBoundingBox);
|
|
|
|
// Auto-connect on page load
|
|
connect();
|
|
</script>
|
|
</body>
|
|
</html> |