Fix some nitpicks

This commit is contained in:
Eugene Burmakin 2025-08-01 18:39:01 +02:00
parent 0e8baf493e
commit c4c829b4b0
7 changed files with 72 additions and 63 deletions

View file

@ -81,7 +81,7 @@ export default class extends BaseController {
this.userSettings = {}; this.userSettings = {};
} }
this.clearFogRadius = parseInt(this.userSettings.fog_of_war_meters) || 50; this.clearFogRadius = parseInt(this.userSettings.fog_of_war_meters) || 50;
this.fogLinethreshold = parseInt(this.userSettings.fog_of_war_threshold) || 90; this.fogLineThreshold = parseInt(this.userSettings.fog_of_war_threshold) || 90;
// Store route opacity as decimal (0-1) internally // Store route opacity as decimal (0-1) internally
this.routeOpacity = parseFloat(this.userSettings.route_opacity) || 0.6; this.routeOpacity = parseFloat(this.userSettings.route_opacity) || 0.6;
this.distanceUnit = this.userSettings.maps?.distance_unit || "km"; this.distanceUnit = this.userSettings.maps?.distance_unit || "km";
@ -119,9 +119,6 @@ export default class extends BaseController {
const div = L.DomUtil.create('div', 'leaflet-control-stats'); const div = L.DomUtil.create('div', 'leaflet-control-stats');
let distance = parseInt(this.element.dataset.distance) || 0; let distance = parseInt(this.element.dataset.distance) || 0;
const pointsNumber = this.element.dataset.points_number || '0'; const pointsNumber = this.element.dataset.points_number || '0';
// Original stats data loading disabled:
// let distance = parseInt(this.element.dataset.distance) || 0;
// const pointsNumber = this.element.dataset.points_number || '0';
// Convert distance to miles if user prefers miles (assuming backend sends km) // Convert distance to miles if user prefers miles (assuming backend sends km)
if (this.distanceUnit === 'mi') { if (this.distanceUnit === 'mi') {
@ -237,7 +234,7 @@ export default class extends BaseController {
// Add visits buttons after calendar button to position them below // Add visits buttons after calendar button to position them below
this.visitsManager.addDrawerButton(); this.visitsManager.addDrawerButton();
// Initialize Live Map Handler // Initialize Live Map Handler
this.initializeLiveMapHandler(); this.initializeLiveMapHandler();
} }
@ -322,7 +319,7 @@ export default class extends BaseController {
heatmapLayer: this.heatmapLayer, heatmapLayer: this.heatmapLayer,
fogOverlay: this.fogOverlay fogOverlay: this.fogOverlay
}; };
const options = { const options = {
maxPoints: 1000, maxPoints: 1000,
routeOpacity: this.routeOpacity, routeOpacity: this.routeOpacity,
@ -330,15 +327,15 @@ export default class extends BaseController {
distanceUnit: this.distanceUnit, distanceUnit: this.distanceUnit,
userSettings: this.userSettings, userSettings: this.userSettings,
clearFogRadius: this.clearFogRadius, clearFogRadius: this.clearFogRadius,
fogLinethreshold: this.fogLinethreshold, fogLineThreshold: this.fogLineThreshold,
// Pass existing data to LiveMapHandler // Pass existing data to LiveMapHandler
existingMarkers: this.markers || [], existingMarkers: this.markers || [],
existingMarkersArray: this.markersArray || [], existingMarkersArray: this.markersArray || [],
existingHeatmapMarkers: this.heatmapMarkers || [] existingHeatmapMarkers: this.heatmapMarkers || []
}; };
this.liveMapHandler = new LiveMapHandler(this.map, layers, options); this.liveMapHandler = new LiveMapHandler(this.map, layers, options);
// Enable live map handler if live mode is already enabled // Enable live map handler if live mode is already enabled
if (this.liveMapEnabled) { if (this.liveMapEnabled) {
this.liveMapHandler.enable(); this.liveMapHandler.enable();
@ -601,7 +598,7 @@ export default class extends BaseController {
// Enable fog of war when layer is added // Enable fog of war when layer is added
this.fogOverlay = event.layer; this.fogOverlay = event.layer;
if (this.markers && this.markers.length > 0) { if (this.markers && this.markers.length > 0) {
this.updateFog(this.markers, this.clearFogRadius, this.fogLinethreshold); this.updateFog(this.markers, this.clearFogRadius, this.fogLineThreshold);
} }
} }
@ -718,7 +715,7 @@ export default class extends BaseController {
// Update fog if enabled // Update fog if enabled
if (this.map.hasLayer(this.fogOverlay)) { if (this.map.hasLayer(this.fogOverlay)) {
this.updateFog(this.markers, this.clearFogRadius, this.fogLinethreshold); this.updateFog(this.markers, this.clearFogRadius, this.fogLineThreshold);
} }
}) })
.catch(error => { .catch(error => {
@ -756,12 +753,12 @@ export default class extends BaseController {
return null; return null;
} }
updateFog(markers, clearFogRadius, fogLinethreshold) { updateFog(markers, clearFogRadius, fogLineThreshold) {
const fog = document.getElementById('fog'); const fog = document.getElementById('fog');
if (!fog) { if (!fog) {
initializeFogCanvas(this.map); initializeFogCanvas(this.map);
} }
requestAnimationFrame(() => drawFogCanvas(this.map, markers, clearFogRadius, fogLinethreshold)); requestAnimationFrame(() => drawFogCanvas(this.map, markers, clearFogRadius, fogLineThreshold));
} }
initializeDrawControl() { initializeDrawControl() {
@ -1388,7 +1385,7 @@ export default class extends BaseController {
// Initialize fog of war if enabled in settings // Initialize fog of war if enabled in settings
if (this.userSettings.fog_of_war_enabled) { if (this.userSettings.fog_of_war_enabled) {
this.updateFog(this.markers, this.clearFogRadius, this.fogLinethreshold); this.updateFog(this.markers, this.clearFogRadius, this.fogLineThreshold);
} }
// Initialize visits manager functionality // Initialize visits manager functionality

View file

@ -7,8 +7,8 @@ import BaseController from "./base_controller"
import L from "leaflet" import L from "leaflet"
import { createAllMapLayers } from "../maps/layers" import { createAllMapLayers } from "../maps/layers"
import { createPopupContent } from "../maps/popups" import { createPopupContent } from "../maps/popups"
import { showFlashMessage } from '../maps/helpers'; import { showFlashMessage } from "../maps/helpers"
import { fetchAndDisplayPhotos } from '../maps/photos'; import { fetchAndDisplayPhotos } from "../maps/photos"
export default class extends BaseController { export default class extends BaseController {
static targets = ["container", "startedAt", "endedAt"] static targets = ["container", "startedAt", "endedAt"]

View file

@ -23,7 +23,7 @@ export function initializeFogCanvas(map) {
return fog; return fog;
} }
export function drawFogCanvas(map, markers, clearFogRadius, fogLinethreshold) { export function drawFogCanvas(map, markers, clearFogRadius, fogLineThreshold) {
const fog = document.getElementById('fog'); const fog = document.getElementById('fog');
// Return early if fog element doesn't exist or isn't a canvas // Return early if fog element doesn't exist or isn't a canvas
if (!fog || !(fog instanceof HTMLCanvasElement)) return; if (!fog || !(fog instanceof HTMLCanvasElement)) return;
@ -55,7 +55,7 @@ export function drawFogCanvas(map, markers, clearFogRadius, fogLinethreshold) {
// 4) Mark which pts are part of a line // 4) Mark which pts are part of a line
const connected = new Array(pts.length).fill(false); const connected = new Array(pts.length).fill(false);
for (let i = 0; i < pts.length - 1; i++) { for (let i = 0; i < pts.length - 1; i++) {
if (pts[i + 1].time - pts[i].time <= fogLinethreshold) { if (pts[i + 1].time - pts[i].time <= fogLineThreshold) {
connected[i] = true; connected[i] = true;
connected[i + 1] = true; connected[i + 1] = true;
} }
@ -78,7 +78,7 @@ export function drawFogCanvas(map, markers, clearFogRadius, fogLinethreshold) {
ctx.strokeStyle = 'rgba(255,255,255,1)'; ctx.strokeStyle = 'rgba(255,255,255,1)';
for (let i = 0; i < pts.length - 1; i++) { for (let i = 0; i < pts.length - 1; i++) {
if (pts[i + 1].time - pts[i].time <= fogLinethreshold) { if (pts[i + 1].time - pts[i].time <= fogLineThreshold) {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(pts[i].pixel.x, pts[i].pixel.y); ctx.moveTo(pts[i].pixel.x, pts[i].pixel.y);
ctx.lineTo(pts[i + 1].pixel.x, pts[i + 1].pixel.y); ctx.lineTo(pts[i + 1].pixel.x, pts[i + 1].pixel.y);
@ -119,7 +119,7 @@ export function createFogOverlay() {
// Draw initial fog if we have markers // Draw initial fog if we have markers
if (controller.markers && controller.markers.length > 0) { if (controller.markers && controller.markers.length > 0) {
drawFogCanvas(map, controller.markers, controller.clearFogRadius, controller.fogLinethreshold); drawFogCanvas(map, controller.markers, controller.clearFogRadius, controller.fogLineThreshold);
} }
} }
} }
@ -134,7 +134,7 @@ export function createFogOverlay() {
// Redraw fog after resize // Redraw fog after resize
if (this._controller && this._controller.markers) { if (this._controller && this._controller.markers) {
drawFogCanvas(map, this._controller.markers, this._controller.clearFogRadius, this._controller.fogLinethreshold); drawFogCanvas(map, this._controller.markers, this._controller.clearFogRadius, this._controller.fogLineThreshold);
} }
} }
}; };
@ -155,9 +155,9 @@ export function createFogOverlay() {
}, },
// Method to update fog when markers change // Method to update fog when markers change
updateFog: function(markers, clearFogRadius, fogLinethreshold) { updateFog: function(markers, clearFogRadius, fogLineThreshold) {
if (this._map) { if (this._map) {
drawFogCanvas(this._map, markers, clearFogRadius, fogLinethreshold); drawFogCanvas(this._map, markers, clearFogRadius, fogLineThreshold);
} }
} }
}); });

View file

@ -33,7 +33,7 @@ export class LiveMapHandler {
this.distanceUnit = options.distanceUnit || 'km'; this.distanceUnit = options.distanceUnit || 'km';
this.userSettings = options.userSettings || {}; this.userSettings = options.userSettings || {};
this.clearFogRadius = options.clearFogRadius || 100; this.clearFogRadius = options.clearFogRadius || 100;
this.fogLinethreshold = options.fogLinethreshold || 10; this.fogLineThreshold = options.fogLineThreshold || 10;
// State tracking // State tracking
this.isEnabled = false; this.isEnabled = false;

View file

@ -1,12 +1,23 @@
import { createPopupContent } from "./popups"; import { createPopupContent } from "./popups";
const MARKER_DATA_INDICES = {
LATITUDE: 0,
LONGITUDE: 1,
BATTERY: 2,
ALTITUDE: 3,
TIMESTAMP: 4,
VELOCITY: 5,
ID: 6,
COUNTRY: 7
};
/** /**
* MarkerFactory - Centralized marker creation with consistent styling * MarkerFactory - Centralized marker creation with consistent styling
* *
* This module provides reusable marker creation functions to ensure * This module provides reusable marker creation functions to ensure
* consistent styling and prevent code duplication between different * consistent styling and prevent code duplication between different
* map components. * map components.
* *
* Memory-safe: Creates fresh instances, no shared references that could * Memory-safe: Creates fresh instances, no shared references that could
* cause memory leaks. * cause memory leaks.
*/ */
@ -29,7 +40,7 @@ export function createStandardIcon(color = 'blue', size = 8) {
/** /**
* Create a basic marker for live streaming (no drag handlers, minimal features) * Create a basic marker for live streaming (no drag handlers, minimal features)
* Memory-efficient for high-frequency creation/destruction * Memory-efficient for high-frequency creation/destruction
* *
* @param {Array} point - Point data [lat, lng, battery, altitude, timestamp, velocity, id, country] * @param {Array} point - Point data [lat, lng, battery, altitude, timestamp, velocity, id, country]
* @param {Object} options - Optional marker configuration * @param {Object} options - Optional marker configuration
* @returns {L.Marker} Leaflet marker instance * @returns {L.Marker} Leaflet marker instance
@ -39,7 +50,7 @@ export function createLiveMarker(point, options = {}) {
const velocity = point[5] || 0; // velocity is at index 5 const velocity = point[5] || 0; // velocity is at index 5
const markerColor = velocity < 0 ? 'orange' : 'blue'; const markerColor = velocity < 0 ? 'orange' : 'blue';
const size = options.size || 8; const size = options.size || 8;
return L.marker([lat, lng], { return L.marker([lat, lng], {
icon: createStandardIcon(markerColor, size), icon: createStandardIcon(markerColor, size),
// Live markers don't need these heavy features // Live markers don't need these heavy features
@ -54,8 +65,8 @@ export function createLiveMarker(point, options = {}) {
/** /**
* Create a full-featured marker with drag handlers and popups * Create a full-featured marker with drag handlers and popups
* Used for static map display where full interactivity is needed * Used for static map display where full interactivity is needed
* *
* @param {Array} point - Point data [lat, lng, battery, altitude, timestamp, velocity, id, country] * @param {Array} point - Point data [lat, lng, battery, altitude, timestamp, velocity, id, country]
* @param {number} index - Marker index in the array * @param {number} index - Marker index in the array
* @param {Object} userSettings - User configuration * @param {Object} userSettings - User configuration
* @param {string} apiKey - API key for backend operations * @param {string} apiKey - API key for backend operations
@ -67,7 +78,7 @@ export function createInteractiveMarker(point, index, userSettings, apiKey, rend
const pointId = point[6]; // ID is at index 6 const pointId = point[6]; // ID is at index 6
const velocity = point[5] || 0; // velocity is at index 5 const velocity = point[5] || 0; // velocity is at index 5
const markerColor = velocity < 0 ? 'orange' : 'blue'; const markerColor = velocity < 0 ? 'orange' : 'blue';
const marker = L.marker([lat, lng], { const marker = L.marker([lat, lng], {
icon: createStandardIcon(markerColor), icon: createStandardIcon(markerColor),
draggable: true, draggable: true,
@ -79,20 +90,20 @@ export function createInteractiveMarker(point, index, userSettings, apiKey, rend
markerData: point, // Store the complete marker data markerData: point, // Store the complete marker data
renderer: renderer renderer: renderer
}); });
// Add popup // Add popup
marker.bindPopup(createPopupContent(point, userSettings.timezone, userSettings.distanceUnit)); marker.bindPopup(createPopupContent(point, userSettings.timezone, userSettings.distanceUnit));
// Add drag event handlers // Add drag event handlers
addDragHandlers(marker, apiKey, userSettings); addDragHandlers(marker, apiKey, userSettings);
return marker; return marker;
} }
/** /**
* Create a simplified marker with minimal features * Create a simplified marker with minimal features
* Used for simplified rendering mode * Used for simplified rendering mode
* *
* @param {Array} point - Point data [lat, lng, battery, altitude, timestamp, velocity, id, country] * @param {Array} point - Point data [lat, lng, battery, altitude, timestamp, velocity, id, country]
* @param {Object} userSettings - User configuration (optional) * @param {Object} userSettings - User configuration (optional)
* @returns {L.Marker} Leaflet marker with basic drag support * @returns {L.Marker} Leaflet marker with basic drag support
@ -101,36 +112,36 @@ export function createSimplifiedMarker(point, userSettings = {}) {
const [lat, lng] = point; const [lat, lng] = point;
const velocity = point[5] || 0; const velocity = point[5] || 0;
const markerColor = velocity < 0 ? 'orange' : 'blue'; const markerColor = velocity < 0 ? 'orange' : 'blue';
const marker = L.marker([lat, lng], { const marker = L.marker([lat, lng], {
icon: createStandardIcon(markerColor), icon: createStandardIcon(markerColor),
draggable: true, draggable: true,
autoPan: true autoPan: true
}); });
// Add popup if user settings provided // Add popup if user settings provided
if (userSettings.timezone && userSettings.distanceUnit) { if (userSettings.timezone && userSettings.distanceUnit) {
marker.bindPopup(createPopupContent(point, userSettings.timezone, userSettings.distanceUnit)); marker.bindPopup(createPopupContent(point, userSettings.timezone, userSettings.distanceUnit));
} }
// Add simple drag handlers // Add simple drag handlers
marker.on('dragstart', function() { marker.on('dragstart', function() {
this.closePopup(); this.closePopup();
}); });
marker.on('dragend', function(e) { marker.on('dragend', function(e) {
const newLatLng = e.target.getLatLng(); const newLatLng = e.target.getLatLng();
this.setLatLng(newLatLng); this.setLatLng(newLatLng);
this.openPopup(); this.openPopup();
}); });
return marker; return marker;
} }
/** /**
* Add comprehensive drag handlers to a marker * Add comprehensive drag handlers to a marker
* Handles polyline updates and backend synchronization * Handles polyline updates and backend synchronization
* *
* @param {L.Marker} marker - The marker to add handlers to * @param {L.Marker} marker - The marker to add handlers to
* @param {string} apiKey - API key for backend operations * @param {string} apiKey - API key for backend operations
* @param {Object} userSettings - User configuration * @param {Object} userSettings - User configuration
@ -140,14 +151,14 @@ function addDragHandlers(marker, apiKey, userSettings) {
marker.on('dragstart', function(e) { marker.on('dragstart', function(e) {
this.closePopup(); this.closePopup();
}); });
marker.on('drag', function(e) { marker.on('drag', function(e) {
const newLatLng = e.target.getLatLng(); const newLatLng = e.target.getLatLng();
const map = e.target._map; const map = e.target._map;
const pointIndex = e.target.options.pointIndex; const pointIndex = e.target.options.pointIndex;
const originalLat = e.target.options.originalLat; const originalLat = e.target.options.originalLat;
const originalLng = e.target.options.originalLng; const originalLng = e.target.options.originalLng;
// Find polylines by iterating through all map layers // Find polylines by iterating through all map layers
map.eachLayer((layer) => { map.eachLayer((layer) => {
// Check if this is a LayerGroup containing polylines // Check if this is a LayerGroup containing polylines
@ -190,7 +201,7 @@ function addDragHandlers(marker, apiKey, userSettings) {
e.target.options.originalLat = newLatLng.lat; e.target.options.originalLat = newLatLng.lat;
e.target.options.originalLng = newLatLng.lng; e.target.options.originalLng = newLatLng.lng;
}); });
marker.on('dragend', function(e) { marker.on('dragend', function(e) {
const newLatLng = e.target.getLatLng(); const newLatLng = e.target.getLatLng();
const pointId = e.target.options.pointId; const pointId = e.target.options.pointId;
@ -231,12 +242,12 @@ function addDragHandlers(marker, apiKey, userSettings) {
const updatedMarkerData = [ const updatedMarkerData = [
parseFloat(data.latitude), parseFloat(data.latitude),
parseFloat(data.longitude), parseFloat(data.longitude),
originalMarkerData[2], // battery originalMarkerData[MARKER_DATA_INDICES.BATTERY],
originalMarkerData[3], // altitude originalMarkerData[MARKER_DATA_INDICES.ALTITUDE],
originalMarkerData[4], // timestamp originalMarkerData[MARKER_DATA_INDICES.TIMESTAMP],
originalMarkerData[5], // velocity originalMarkerData[MARKER_DATA_INDICES.VELOCITY],
data.id, // id data.id,
originalMarkerData[7] // country originalMarkerData[MARKER_DATA_INDICES.COUNTRY]
]; ];
// Update the marker's stored data // Update the marker's stored data
@ -258,4 +269,4 @@ function addDragHandlers(marker, apiKey, userSettings) {
alert('Failed to update point position. Please try again.'); alert('Failed to update point position. Please try again.');
}); });
}); });
} }

View file

@ -1,4 +1,5 @@
import { createInteractiveMarker, createSimplifiedMarker } from "./marker_factory"; import { createInteractiveMarker, createSimplifiedMarker } from "./marker_factory";
import { haversineDistance } from "./helpers";
export function createMarkersArray(markersData, userSettings, apiKey) { export function createMarkersArray(markersData, userSettings, apiKey) {
// Create a canvas renderer // Create a canvas renderer
@ -29,11 +30,8 @@ export function createSimplifiedMarkers(markersData, renderer, userSettings) {
const [prevLat, prevLon, , , prevTimestamp] = previousMarker; const [prevLat, prevLon, , , prevTimestamp] = previousMarker;
const timeDiff = currTimestamp - prevTimestamp; const timeDiff = currTimestamp - prevTimestamp;
// Note: haversineDistance function would need to be imported or implemented // Use haversineDistance for accurate distance calculation
// For now, using simple distance calculation const distance = haversineDistance(prevLat, prevLon, currLat, currLon, 'km') * 1000; // Convert to meters
const latDiff = currLat - prevLat;
const lngDiff = currLon - prevLon;
const distance = Math.sqrt(latDiff * latDiff + lngDiff * lngDiff) * 111000; // Rough conversion to meters
// Keep the marker if it's far enough in distance or time // Keep the marker if it's far enough in distance or time
if (distance >= distanceThreshold || timeDiff >= timeThreshold) { if (distance >= distanceThreshold || timeDiff >= timeThreshold) {

View file

@ -491,11 +491,14 @@ export class VisitsManager {
// Update the drawer content if it's being opened - but don't fetch visits automatically // Update the drawer content if it's being opened - but don't fetch visits automatically
if (this.drawerOpen) { if (this.drawerOpen) {
console.log('Drawer opened - showing placeholder message');
// Just show a placeholder message in the drawer, don't fetch visits
const container = document.getElementById('visits-list'); const container = document.getElementById('visits-list');
if (container) { if (container) {
container.innerHTML = '<p class="text-gray-500">Enable "Suggested Visits" or "Confirmed Visits" layers to see visits data</p>'; container.innerHTML = `
<div class="text-gray-500 text-center p-4">
<p class="mb-2">No visits data loaded</p>
<p class="text-sm">Enable "Suggested Visits" or "Confirmed Visits" layers from the map controls to view visits.</p>
</div>
`;
} }
} }
// Note: Layer visibility is now controlled by the layer control, not the drawer state // Note: Layer visibility is now controlled by the layer control, not the drawer state
@ -578,12 +581,12 @@ export class VisitsManager {
console.log('Visit circles populated - layer control will manage visibility'); console.log('Visit circles populated - layer control will manage visibility');
console.log('visitCircles layer count:', this.visitCircles.getLayers().length); console.log('visitCircles layer count:', this.visitCircles.getLayers().length);
console.log('confirmedVisitCircles layer count:', this.confirmedVisitCircles.getLayers().length); console.log('confirmedVisitCircles layer count:', this.confirmedVisitCircles.getLayers().length);
// Check if the layers are currently enabled in the layer control and ensure they're visible // Check if the layers are currently enabled in the layer control and ensure they're visible
const layerControl = this.map._layers; const layerControl = this.map._layers;
let suggestedVisitsEnabled = false; let suggestedVisitsEnabled = false;
let confirmedVisitsEnabled = false; let confirmedVisitsEnabled = false;
// Check layer control state // Check layer control state
Object.values(layerControl || {}).forEach(layer => { Object.values(layerControl || {}).forEach(layer => {
if (layer.name === 'Suggested Visits' && this.map.hasLayer(layer.layer)) { if (layer.name === 'Suggested Visits' && this.map.hasLayer(layer.layer)) {
@ -593,7 +596,7 @@ export class VisitsManager {
confirmedVisitsEnabled = true; confirmedVisitsEnabled = true;
} }
}); });
console.log('Layer control state:', { suggestedVisitsEnabled, confirmedVisitsEnabled }); console.log('Layer control state:', { suggestedVisitsEnabled, confirmedVisitsEnabled });
} catch (error) { } catch (error) {
console.error('Error fetching visits:', error); console.error('Error fetching visits:', error);
@ -679,7 +682,7 @@ export class VisitsManager {
displayVisits(visits) { displayVisits(visits) {
// Always create map circles regardless of drawer state // Always create map circles regardless of drawer state
this.createMapCircles(visits); this.createMapCircles(visits);
// Update drawer UI only if container exists // Update drawer UI only if container exists
const container = document.getElementById('visits-list'); const container = document.getElementById('visits-list');
if (!container) { if (!container) {