better ui

This commit is contained in:
didier committed 2025-01-05 19:43:30 -05:00
1 parent e0b0ca48f2
commit 84abee712d
6 files changed
+66 -17

No files matched your search

+9 -2
View File
@@ -17,9 +17,16 @@ public class ApiController: Controller
_logger = logger; _logger = logger;
} }
public JsonResult Roads(string city, int year=2025) public ActionResult Roads(string city, string date="")
{ {
return Json(_dataService.GetRoads(city, year)); var extractDate = Util.ParseDateOnly(date);
if (!extractDate.HasValue)
{
return BadRequest($"Cannot parse provided date {date}. The date must be in the format yyyy-MM-dd.");
}
return Json(_dataService.GetRoads(city, extractDate.Value));
} }
} }
+4 -3
View File
@@ -5,7 +5,7 @@ using YongeStreet.Services;
namespace YongeStreet.Controllers; namespace YongeStreet.Controllers;
public record CityModel(string City, IList<CityRoadLengthStats> CityRoadLengthStats); public record CityModel(string City, IList<CityRoadLengthStats> CityRoadLengthStats, DateOnly Date);
public record IndexModel(IList<CityOverview> Cities); public record IndexModel(IList<CityOverview> Cities);
@@ -20,10 +20,11 @@ public class HomeController : Controller
_dataService = dataService; _dataService = dataService;
} }
public IActionResult City(string city) public IActionResult City(string city, string date)
{ {
var cityRoadLengthStats = _dataService.GetCityRoadLengthStats(city); var cityRoadLengthStats = _dataService.GetCityRoadLengthStats(city);
return View(new CityModel(city, cityRoadLengthStats)); var parsedDate = Util.ParseDateOnly(date) ?? new DateOnly(2025, 1, 1);
return View(new CityModel(city, cityRoadLengthStats, parsedDate ));
} }
public IActionResult Index() public IActionResult Index()
+21
View File
@@ -0,0 +1,21 @@
namespace YongeStreet.Controllers;
public static class Util
{
public static DateOnly? ParseDateOnly(string? date)
{
if (string.IsNullOrEmpty(date))
{
return new DateOnly(2025, 1, 1);
}
try
{
return DateOnly.ParseExact(date, "yyyy-MM-dd");
}
catch (FormatException e)
{
return null;
}
}
}
+9 -9
View File
@@ -4,9 +4,9 @@ namespace YongeStreet.Services;
public record Road(int RelationId, List<List<double>> Points); public record Road(int RelationId, List<List<double>> Points);
public record CityOverview(string Name, double TotalStreetSize, IList<int> AvailableYears); public record CityOverview(string Name, double TotalStreetSize, IList<DateOnly> AvailableDates);
public record CityRoadLengthStats(string Name, double MunicipalRoadLength, int Year); public record CityRoadLengthStats(string Name, double MunicipalRoadLength, DateOnly Date);
public class DataService public class DataService
{ {
@@ -20,7 +20,7 @@ public class DataService
"unclassified"]; "unclassified"];
private readonly string path = "/home/didier/dev/YongeStreet/real.duckdb"; private readonly string path = "/home/didier/dev/YongeStreet/real.duckdb";
public IList<Road> GetRoads(string city, int year) public IList<Road> GetRoads(string city, DateOnly extractDate)
{ {
using var duckDBConnection = new DuckDBConnection($"Data Source={path};ACCESS_MODE=READ_ONLY"); using var duckDBConnection = new DuckDBConnection($"Data Source={path};ACCESS_MODE=READ_ONLY");
duckDBConnection.Open(); duckDBConnection.Open();
@@ -34,7 +34,7 @@ public class DataService
AND list_contains($allowed_highway, highway) AND list_contains($allowed_highway, highway)
"""; """;
command.Parameters.Add(new DuckDBParameter("city_name", city)); command.Parameters.Add(new DuckDBParameter("city_name", city));
command.Parameters.Add(new DuckDBParameter("extract_date", new DateOnly(year, 1, 1))); command.Parameters.Add(new DuckDBParameter("extract_date", extractDate));
command.Parameters.Add(new DuckDBParameter("allowed_highway", CITY_STREET_HIGHWAY)); command.Parameters.Add(new DuckDBParameter("allowed_highway", CITY_STREET_HIGHWAY));
using var reader = command.ExecuteReader(); using var reader = command.ExecuteReader();
@@ -57,7 +57,7 @@ public class DataService
command.CommandText = """ command.CommandText = """
SELECT city_name, SELECT city_name,
SUM(length) FILTER (list_contains($allowed_highway, highway) AND extract_date = (Date '2025-01-01')) AS length, SUM(length) FILTER (list_contains($allowed_highway, highway) AND extract_date = (Date '2025-01-01')) AS length,
LIST(DISTINCT extract('year' FROM extract_date)) AS available_years LIST(DISTINCT extract_date) AS available_years
FROM city_road FROM city_road
GROUP BY city_name GROUP BY city_name
ORDER BY length desc ORDER BY length desc
@@ -70,7 +70,7 @@ public class DataService
while (reader.Read()) while (reader.Read())
ret.Add(new CityOverview(reader.GetString(0), ret.Add(new CityOverview(reader.GetString(0),
reader.GetDouble(1), reader.GetDouble(1),
reader.GetFieldValue<List<int>>(2))); reader.GetFieldValue<List<DateOnly>>(2)));
return ret; return ret;
} }
@@ -83,11 +83,11 @@ public class DataService
using var command = duckDBConnection.CreateCommand(); using var command = duckDBConnection.CreateCommand();
command.CommandText = """ command.CommandText = """
SELECT SUM(length) FILTER (list_contains($allowed_highway, highway)) AS length, SELECT SUM(length) FILTER (list_contains($allowed_highway, highway)) AS length,
extract('year' FROM extract_date) AS year extract_date AS date
FROM city_road FROM city_road
WHERE city_name = $city_name WHERE city_name = $city_name
GROUP BY extract_date GROUP BY extract_date
ORDER BY year DESC ORDER BY date DESC
"""; """;
command.Parameters.Add(new DuckDBParameter("city_name", city)); command.Parameters.Add(new DuckDBParameter("city_name", city));
command.Parameters.Add(new DuckDBParameter("allowed_highway", CITY_STREET_HIGHWAY)); command.Parameters.Add(new DuckDBParameter("allowed_highway", CITY_STREET_HIGHWAY));
@@ -98,7 +98,7 @@ public class DataService
{ {
ret.Add(new CityRoadLengthStats(city, ret.Add(new CityRoadLengthStats(city,
reader.GetInt32(0), reader.GetInt32(0),
reader.GetInt32(1))); reader.GetFieldValue<DateOnly>(1)));
} }
return ret; return ret;
+22 -2
View File
@@ -1,9 +1,14 @@
@using System.Runtime.InteropServices.JavaScript
@model YongeStreet.Controllers.CityModel @model YongeStreet.Controllers.CityModel
@{ @{
ViewData["Title"] = "La Province"; ViewData["Title"] = "La Province";
} }
<div>
<h2>@Model.City - @Model.Date.ToString("yyyy-MM-dd")</h2>
</div>
<div class="uk-height-large uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light" <div class="uk-height-large uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light"
style="background-color: black" style="background-color: black"
id="leaflet-map" id="leaflet-map"
@@ -19,10 +24,25 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach(var stats in Model.CityRoadLengthStats)
@foreach (var stats in Model.CityRoadLengthStats)
{ {
<tr> <tr>
<td>@stats.Year</td> <td>
@if (stats.Date != Model.Date)
{
@Html.ActionLink(stats.Date.ToString("yyyy-MM-dd"),
"City",
"Home",
new { City = Model.City, Date = stats.Date.ToString("yyyy-MM-dd"), })
}
else
{
@stats.Date.ToString("yyyy-MM-dd")
}
</td>
<td>@((stats.MunicipalRoadLength / 1000).ToString("N"))</td> <td>@((stats.MunicipalRoadLength / 1000).ToString("N"))</td>
<td></td> <td></td>
</tr> </tr>
+1 -1
View File
@@ -21,7 +21,7 @@
<tr> <tr>
<td>@Html.ActionLink(city.Name, "City", "Home", new {City=city.Name})</td> <td>@Html.ActionLink(city.Name, "City", "Home", new {City=city.Name})</td>
<td>@((city.TotalStreetSize / 1000 ).ToString("N"))</td> <td>@((city.TotalStreetSize / 1000 ).ToString("N"))</td>
<td>@string.Join(", ", city.AvailableYears)</td> <td>@string.Join(", ", city.AvailableDates)</td>
</tr> </tr>
} }