Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 71 additions & 17 deletions TransitWebViewer/Components/Maps/LeafletMap.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,88 @@
@inject IJSRuntime JsRuntime
@inject NavigationManager NavigationManager

<div id="map" style="height: 500px;"></div>
<div id="map" style="height: 90vh;"></div>


@code {
private IJSObjectReference? _leafletMap;

string TtssProxyUrl => $"{NavigationManager.BaseUri}api/vip";

private TtssApi? _ttssApi = null;

TtssApi TtssApi
{
get
{
if (_ttssApi is null)
{
_ttssApi =
new TtssApi
{
Language = "de",
BaseUri = new Uri("https://www.swp-potsdam.de/"),
ProxyUri = new Uri(TtssProxyUrl),
// ProxyUri = new Uri("http://localhost:5025/api/vip"),
};
}

return _ttssApi;
}
}

private Timer? Timer { get; set; } = null;

private async Task VehicleUpdate()
{
var ttssApi = new TtssApi
var dotNetReference = DotNetObjectReference.Create(this);
var vehiclesResponse = await TtssApi.GetVehiclesAsync(new VehicleRequest());
var vehicles = vehiclesResponse.Vehicles.Where(vehicle => vehicle is { IsDeleted: false, Position: not null }).ToArray();
foreach (var vehicle in vehicles)
{
const string lineBreak = "<br />";
var direction = new Func<string>(() =>
{
var direction = vehicle.Direction ?? "unbekannt";
var firstSpace = direction.IndexOf(" ", StringComparison.Ordinal);
if (firstSpace > -1 && direction[..firstSpace] == direction[(firstSpace + 1)..(firstSpace * 2 + 1)])
{
direction = direction[firstSpace..];
}

direction = direction.Replace("->", $"{lineBreak}-> ");
return string.Join(lineBreak, direction.Split("//").Select(part => part.Trim()).ToArray());
})();
await JsRuntime.InvokeVoidAsync(
"leafletMap.vehicleAt",
dotNetReference,
_leafletMap,
vehicle.VehicleId,
vehicle.Position!.Latitude,
vehicle.Position.Longitude,
direction,
vehicle.Color?.Replace("0x", "#") ?? "#000000",
vehicle.TripId
);
}

// See https://github.com/dotnet/aspnetcore/issues/8743#issuecomment-476261870 for the cast to `object`.
await JsRuntime.InvokeVoidAsync("leafletMap.keepOnlyVehicles", (object)vehicles.Select(vehicle => vehicle.VehicleId).ToArray());
}

[JSInvokable(nameof(OnOpenTripMarker))]
public async Task OnOpenTripMarker(string? tripId)
{
if (tripId is null)
{
Language = "de",
BaseUri = new Uri("https://www.swp-potsdam.de/"),
ProxyUri = new Uri(TtssProxyUrl),
// ProxyUri = new Uri("http://localhost:5177"),
};
var vehicles = await ttssApi.GetVehiclesAsync(new VehicleRequest());
foreach (var vehicle in vehicles.Vehicles)
await Console.Error.WriteLineAsync("Cannot render trip path as no trip is was set.");
return;
}

var paths = await TtssApi.GetTripPathsAsync(new TripPathsRequest { TripId = tripId });
foreach (var path in paths.Paths)
{
if (vehicle.IsDeleted) continue;
if (vehicle.Position is null) continue;
await JsRuntime.InvokeAsync<IJSObjectReference>(
"leafletMap.vehicleAt", _leafletMap, vehicle.Position.Latitude, vehicle.Position.Longitude, vehicle.Direction ?? "unbekannt"
await JsRuntime.InvokeVoidAsync(
"leafletMap.drawRoute", _leafletMap, path.Waypoints, path.Color, true, tripId
);
}
}
Expand All @@ -42,9 +98,7 @@
"leafletMap.initialize", "map", 52.395833, 13.061389, 13
);

await VehicleUpdate();

// Timer = new Timer(_ => Task.Run(VehicleUpdate), null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
Timer = new Timer(_ => Task.Run(VehicleUpdate), null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
}
}

Expand Down
2 changes: 1 addition & 1 deletion TransitWebViewer/TransitWebViewer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.4" PrivateAssets="all" />
<PackageReference Include="TtssClient" Version="1.3.0" />
<PackageReference Include="TtssClient" Version="1.4.1" />
</ItemGroup>

<ItemGroup>
Expand Down
90 changes: 88 additions & 2 deletions TransitWebViewer/wwwroot/leafletInterop.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
const vehicles = {};
const routes = {};
const removeAllRoutes = () => {
for (const [tripId, polyline] of Object.entries(routes)) {
polyline.remove();
delete routes[tripId];
}
};
window.leafletMap = {
initialize: function (mapId, lat, lng, zoom) {
// Initialize the Leaflet map
Expand All @@ -12,8 +20,86 @@ window.leafletMap = {
return map;
},

vehicleAt: function (map, lat, lng, popupText) {
return L.marker([lat, lng]).addTo(map)
vehicleAt: function (dotNetObject, map, vehicleId, lat, lng, popupText, colour, tripId) {
if (vehicles[vehicleId]) {
const [marker, oldTripId] = vehicles[vehicleId];
marker.setLatLng([lat, lng]);
marker.color = colour;
marker.setTooltipContent(popupText);
if (marker.isPopupOpen() && marker.getPopup().content !== popupText) {
console.log(`Resetting popup old '${marker.getPopup().content}' new '${popupText}'.`);
marker.closePopup();
marker.openPopup();
}
if (oldTripId !== tripId) {
console.log(`Resetting trip ${tripId} (was ${oldTripId}) (${popupText}).`);
if (routes[oldTripId]) {
console.log("Redrawing!");
removeAllRoutes();
dotNetObject.invokeMethodAsync('OnOpenTripMarker', tripId);
}
vehicles[vehicleId] = [marker, tripId];
}
return;
}
const marker = L.circleMarker([lat, lng], { color: colour });
vehicles[vehicleId] = [marker, tripId];
return marker
.addTo(map)
.on('popupopen', _event => {
if (routes[tripId]) {
return;
}
removeAllRoutes();
dotNetObject.invokeMethodAsync('OnOpenTripMarker', tripId);
})
// .on('popupclose', _event => {
// if (routes[tripId]) {
// routes[tripId].remove();
// delete routes[tripId];
// } else {
// console.warn(`Could not remove path of trip ${tripId}.`);
// }
// })
.bindPopup(popupText);
// return L.marker([lat, lng]).addTo(map)
// .bindPopup(popupText);
},

keepOnlyVehicles: function (vehicleIds, a) {
for (const [vehicleId, [marker, tripId]] of Object.entries(vehicles)) {
if (vehicleIds.includes(vehicleId)) {
continue;
}
marker.remove();
if (routes[tripId]) {
routes[tripId].remove();
delete routes[tripId];
}
delete vehicles[vehicleId];
}
},

drawRoute: function (map, points, colour, focus, tripId) {
const leafletPoints = points.map(point => new L.LatLng(point.latitude, point.longitude));
const polyline = new L.polyline(leafletPoints, {
color: colour,
weight: 3,
opacity: 1,
smoothFactor: 1,
});
if (tripId) {
if (routes[tripId]) {
routes[tripId].remove();
}
routes[tripId] = polyline;
} else {
console.warn(`Could not store polyline for colour ${colour}.`);
}
if (focus) {
map.fitBounds(polyline.getBounds());
}
polyline.addTo(map);
return polyline.bringToBack();
}
};