Integration and add heat map demo
- Implemented OpenStreetMap using WebView with Leaflet.js - Added OpenStreetMapView component with interactive map functionality - Created heat map visualization with color-coded intensity - Added 30 dummy location points around San Francisco Bay Area - Implemented location tracking with real-time pin placement - Added comprehensive UI with two-row button layout - Features: Start/Stop tracking, Center map, Demo heat map, Clear demo, Reset map - Added location count display and confirmation dialogs - Updated project structure and documentation - All functionality tested and working on Android emulator
This commit is contained in:
269
LocationTrackerApp/MainPage.xaml.cs
Normal file
269
LocationTrackerApp/MainPage.xaml.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using LocationTrackerApp.Components;
|
||||
using LocationTrackerApp.Models;
|
||||
|
||||
namespace LocationTrackerApp;
|
||||
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
private bool _isTracking = false;
|
||||
private List<LocationData> _trackedLocations = new();
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeMap();
|
||||
}
|
||||
|
||||
private void InitializeMap()
|
||||
{
|
||||
// The OpenStreetMapView initializes itself with a default location
|
||||
// Add some dummy location data to demonstrate heat map functionality
|
||||
AddDummyLocationData();
|
||||
}
|
||||
|
||||
private void AddDummyLocationData()
|
||||
{
|
||||
// Add dummy location data around San Francisco Bay Area to demonstrate heat map
|
||||
var dummyLocations = new List<LocationData>
|
||||
{
|
||||
// Golden Gate Bridge area (high frequency)
|
||||
new LocationData { Latitude = 37.8199, Longitude = -122.4783, Timestamp = DateTime.UtcNow.AddMinutes(-30) },
|
||||
new LocationData { Latitude = 37.8200, Longitude = -122.4780, Timestamp = DateTime.UtcNow.AddMinutes(-29) },
|
||||
new LocationData { Latitude = 37.8201, Longitude = -122.4777, Timestamp = DateTime.UtcNow.AddMinutes(-28) },
|
||||
new LocationData { Latitude = 37.8198, Longitude = -122.4785, Timestamp = DateTime.UtcNow.AddMinutes(-27) },
|
||||
new LocationData { Latitude = 37.8202, Longitude = -122.4775, Timestamp = DateTime.UtcNow.AddMinutes(-26) },
|
||||
|
||||
// Fisherman's Wharf area (medium frequency)
|
||||
new LocationData { Latitude = 37.8080, Longitude = -122.4177, Timestamp = DateTime.UtcNow.AddMinutes(-25) },
|
||||
new LocationData { Latitude = 37.8085, Longitude = -122.4175, Timestamp = DateTime.UtcNow.AddMinutes(-24) },
|
||||
new LocationData { Latitude = 37.8082, Longitude = -122.4180, Timestamp = DateTime.UtcNow.AddMinutes(-23) },
|
||||
|
||||
// Union Square area (medium frequency)
|
||||
new LocationData { Latitude = 37.7879, Longitude = -122.4075, Timestamp = DateTime.UtcNow.AddMinutes(-22) },
|
||||
new LocationData { Latitude = 37.7882, Longitude = -122.4078, Timestamp = DateTime.UtcNow.AddMinutes(-21) },
|
||||
new LocationData { Latitude = 37.7877, Longitude = -122.4072, Timestamp = DateTime.UtcNow.AddMinutes(-20) },
|
||||
|
||||
// Mission District area (low frequency)
|
||||
new LocationData { Latitude = 37.7599, Longitude = -122.4148, Timestamp = DateTime.UtcNow.AddMinutes(-19) },
|
||||
new LocationData { Latitude = 37.7602, Longitude = -122.4150, Timestamp = DateTime.UtcNow.AddMinutes(-18) },
|
||||
|
||||
// Castro District area (low frequency)
|
||||
new LocationData { Latitude = 37.7611, Longitude = -122.4350, Timestamp = DateTime.UtcNow.AddMinutes(-17) },
|
||||
|
||||
// SOMA area (medium frequency)
|
||||
new LocationData { Latitude = 37.7749, Longitude = -122.4194, Timestamp = DateTime.UtcNow.AddMinutes(-16) },
|
||||
new LocationData { Latitude = 37.7752, Longitude = -122.4197, Timestamp = DateTime.UtcNow.AddMinutes(-15) },
|
||||
new LocationData { Latitude = 37.7747, Longitude = -122.4191, Timestamp = DateTime.UtcNow.AddMinutes(-14) },
|
||||
new LocationData { Latitude = 37.7750, Longitude = -122.4194, Timestamp = DateTime.UtcNow.AddMinutes(-13) },
|
||||
|
||||
// Financial District area (high frequency)
|
||||
new LocationData { Latitude = 37.7946, Longitude = -122.3998, Timestamp = DateTime.UtcNow.AddMinutes(-12) },
|
||||
new LocationData { Latitude = 37.7949, Longitude = -122.4001, Timestamp = DateTime.UtcNow.AddMinutes(-11) },
|
||||
new LocationData { Latitude = 37.7944, Longitude = -122.3995, Timestamp = DateTime.UtcNow.AddMinutes(-10) },
|
||||
new LocationData { Latitude = 37.7952, Longitude = -122.4004, Timestamp = DateTime.UtcNow.AddMinutes(-9) },
|
||||
new LocationData { Latitude = 37.7947, Longitude = -122.3999, Timestamp = DateTime.UtcNow.AddMinutes(-8) },
|
||||
new LocationData { Latitude = 37.7950, Longitude = -122.4002, Timestamp = DateTime.UtcNow.AddMinutes(-7) },
|
||||
|
||||
// North Beach area (low frequency)
|
||||
new LocationData { Latitude = 37.8044, Longitude = -122.4098, Timestamp = DateTime.UtcNow.AddMinutes(-6) },
|
||||
|
||||
// Chinatown area (medium frequency)
|
||||
new LocationData { Latitude = 37.7941, Longitude = -122.4078, Timestamp = DateTime.UtcNow.AddMinutes(-5) },
|
||||
new LocationData { Latitude = 37.7944, Longitude = -122.4081, Timestamp = DateTime.UtcNow.AddMinutes(-4) },
|
||||
new LocationData { Latitude = 37.7938, Longitude = -122.4075, Timestamp = DateTime.UtcNow.AddMinutes(-3) },
|
||||
|
||||
// Marina District area (low frequency)
|
||||
new LocationData { Latitude = 37.8026, Longitude = -122.4430, Timestamp = DateTime.UtcNow.AddMinutes(-2) },
|
||||
|
||||
// Presidio area (low frequency)
|
||||
new LocationData { Latitude = 37.7989, Longitude = -122.4662, Timestamp = DateTime.UtcNow.AddMinutes(-1) }
|
||||
};
|
||||
|
||||
_trackedLocations.AddRange(dummyLocations);
|
||||
UpdateLocationCount();
|
||||
}
|
||||
|
||||
private void UpdateLocationCount()
|
||||
{
|
||||
LocationCountLabel.Text = $"Locations: {_trackedLocations.Count}";
|
||||
}
|
||||
|
||||
private async void OnStartTrackingClicked(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_isTracking)
|
||||
{
|
||||
// Request location permissions
|
||||
var status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
|
||||
if (status != PermissionStatus.Granted)
|
||||
{
|
||||
await DisplayAlert("Permission Required", "Location permission is required to track your location.", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
// Start location tracking
|
||||
_isTracking = true;
|
||||
StartTrackingBtn.Text = "Tracking...";
|
||||
StartTrackingBtn.BackgroundColor = Colors.Orange;
|
||||
StopTrackingBtn.IsEnabled = true;
|
||||
|
||||
// Simulate location tracking
|
||||
_ = Task.Run(async () => await SimulateLocationTracking());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlert("Error", $"Failed to start tracking: {ex.Message}", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStopTrackingClicked(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_isTracking)
|
||||
{
|
||||
_isTracking = false;
|
||||
StartTrackingBtn.Text = "Start Tracking";
|
||||
StartTrackingBtn.BackgroundColor = Colors.Green;
|
||||
StopTrackingBtn.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DisplayAlert("Error", $"Failed to stop tracking: {ex.Message}", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SimulateLocationTracking()
|
||||
{
|
||||
while (_isTracking)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get current location
|
||||
var location = await Geolocation.GetLocationAsync();
|
||||
if (location != null)
|
||||
{
|
||||
// Update UI on main thread
|
||||
MainThread.BeginInvokeOnMainThread(async () =>
|
||||
{
|
||||
// Add location to tracked locations
|
||||
var locationData = new LocationData
|
||||
{
|
||||
Latitude = location.Latitude,
|
||||
Longitude = location.Longitude,
|
||||
Timestamp = DateTime.UtcNow
|
||||
};
|
||||
_trackedLocations.Add(locationData);
|
||||
UpdateLocationCount();
|
||||
|
||||
// Add pin to OpenStreetMap
|
||||
await MainMap.AddLocationPinAsync(location, $"Current Location {_trackedLocations.Count}", 0.8);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle location errors
|
||||
System.Diagnostics.Debug.WriteLine($"Location error: {ex.Message}");
|
||||
}
|
||||
|
||||
// Wait 5 seconds before next update
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnCenterMapClicked(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Request location permissions if not already granted
|
||||
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
|
||||
if (status != PermissionStatus.Granted)
|
||||
{
|
||||
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
|
||||
if (status != PermissionStatus.Granted)
|
||||
{
|
||||
await DisplayAlert("Permission Required", "Location permission is required to center the map.", "OK");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current location
|
||||
var location = await Geolocation.GetLocationAsync();
|
||||
if (location != null)
|
||||
{
|
||||
// Clear existing pins
|
||||
await MainMap.ClearMapAsync();
|
||||
|
||||
// Add a pin for current location
|
||||
await MainMap.AddLocationPinAsync(location, $"Your Location\nLat: {location.Latitude:F6}\nLng: {location.Longitude:F6}", 1.0);
|
||||
|
||||
await DisplayAlert("Location Found", $"Map centered on your location:\nLat: {location.Latitude:F6}\nLng: {location.Longitude:F6}", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
await DisplayAlert("Error", "Unable to get your current location.", "OK");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlert("Error", $"Failed to center map: {ex.Message}", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnHeatMapClicked(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_trackedLocations.Any())
|
||||
{
|
||||
// Load tracked locations into the heat map
|
||||
await MainMap.LoadLocationDataAsync(_trackedLocations);
|
||||
await DisplayAlert("Heat Map", $"Heat map updated with {_trackedLocations.Count} locations.\n\nAreas with higher frequency appear in red/yellow, lower frequency in blue.", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
await DisplayAlert("No Data", "No location data available. Start tracking to create a heat map.", "OK");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlert("Error", $"Failed to update heat map: {ex.Message}", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnClearDemoClicked(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await DisplayAlert("Clear Demo Data", "Are you sure you want to clear all demo location data?", "Yes", "No");
|
||||
if (result)
|
||||
{
|
||||
_trackedLocations.Clear();
|
||||
await MainMap.ClearMapAsync();
|
||||
UpdateLocationCount();
|
||||
await DisplayAlert("Demo Cleared", "All demo location data has been cleared.", "OK");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlert("Error", $"Failed to clear demo data: {ex.Message}", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnResetMapClicked(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
await MainMap.ClearMapAsync();
|
||||
await DisplayAlert("Map Reset", "Map has been reset to default view.", "OK");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await DisplayAlert("Error", $"Failed to reset map: {ex.Message}", "OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user