From a78552d37d222509bee0e9432a07bf553a0afff0 Mon Sep 17 00:00:00 2001 From: AlexKven Date: Wed, 10 Jun 2020 10:10:21 -0700 Subject: [PATCH] #30 Add bounds property to the map. --- .../BlazorLeaflet.Samples/Pages/Index.razor | 4 +- .../BlazorLeaflet/LeafletInterops.cs | 17 ++++- BlazorLeaflet/BlazorLeaflet/Map.cs | 65 ++++++++++++++++++- BlazorLeaflet/BlazorLeaflet/Models/Bounds.cs | 26 ++++++++ .../wwwroot/leafletBlazorInterops.js | 5 +- 5 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 BlazorLeaflet/BlazorLeaflet/Models/Bounds.cs diff --git a/BlazorLeaflet/BlazorLeaflet.Samples/Pages/Index.razor b/BlazorLeaflet/BlazorLeaflet.Samples/Pages/Index.razor index a1183e9..751c060 100644 --- a/BlazorLeaflet/BlazorLeaflet.Samples/Pages/Index.razor +++ b/BlazorLeaflet/BlazorLeaflet.Samples/Pages/Index.razor @@ -19,6 +19,7 @@
+

Map bounds: @_map.Bounds?.ToString()

@code { @@ -66,7 +67,8 @@ Radius = 10f }; _map.AddLayer(_circle); - }; + }; + _map.OnBoundsChanged += (s, e) => this.StateHasChanged(); } private LatLng _startAt = new LatLng(47.5574007f, 16.3918687f); diff --git a/BlazorLeaflet/BlazorLeaflet/LeafletInterops.cs b/BlazorLeaflet/BlazorLeaflet/LeafletInterops.cs index 369338b..cdc1ed5 100644 --- a/BlazorLeaflet/BlazorLeaflet/LeafletInterops.cs +++ b/BlazorLeaflet/BlazorLeaflet/LeafletInterops.cs @@ -60,6 +60,21 @@ public static ValueTask GetCenter(IJSRuntime jsRuntime, string mapId) => jsRuntime.InvokeAsync($"{_BaseObjectContainer}.getCenter", mapId); public static ValueTask GetZoom(IJSRuntime jsRuntime, string mapId) => - jsRuntime.InvokeAsync($"{_BaseObjectContainer}.getZoom", mapId); + jsRuntime.InvokeAsync($"{_BaseObjectContainer}.getZoom", mapId); + + // Private class only for deserialization from JSON (since the JSON names on the bounds are "_southWest" + // with the _). Since deserialization in JSRuntime is non-customizable, this is a good solution for now. + private class _Bounds + { + public LatLng _southWest { get; set; } + public LatLng _northEast { get; set; } + + public Bounds AsBounds() => new Bounds(_southWest, _northEast); + } + + public static async Task GetBounds(IJSRuntime jsRuntime, string mapId) + { + return (await jsRuntime.InvokeAsync<_Bounds>($"{_BaseObjectContainer}.getBounds", mapId)).AsBounds(); + } } } diff --git a/BlazorLeaflet/BlazorLeaflet/Map.cs b/BlazorLeaflet/BlazorLeaflet/Map.cs index 84cd33c..1ba6d60 100644 --- a/BlazorLeaflet/BlazorLeaflet/Map.cs +++ b/BlazorLeaflet/BlazorLeaflet/Map.cs @@ -25,6 +25,12 @@ public class Map /// public float Zoom { get; set; } + + /// + /// Map bounds + /// + public Bounds Bounds { get; private set; } + /// /// Minimum zoom level of the map. If not specified and at least one /// GridLayer or TileLayer is in the map, the lowest of their minZoom @@ -74,6 +80,19 @@ public void RaiseOnInitialized() { _isInitialized = true; OnInitialized?.Invoke(); + RunTaskInBackground(UpdateBounds); + } + + private async void RunTaskInBackground(Func task) + { + try + { + await task(); + } + catch (Exception ex) + { + NotifyBackgroundExceptionOccurred(ex); + } } /// @@ -171,6 +190,14 @@ public void PanTo(PointF position, bool animate = false, float duration = 0.25f, public async Task GetCenter() => await LeafletInterops.GetCenter(_jsRuntime, Id); public async Task GetZoom() => await LeafletInterops.GetZoom(_jsRuntime, Id); + public async Task GetBounds() => await LeafletInterops.GetBounds(_jsRuntime, Id); + + + private async Task UpdateBounds() + { + Bounds = await GetBounds(); + OnBoundsChanged?.Invoke(this, new EventArgs()); + } #region events @@ -215,11 +242,41 @@ public void PanTo(PointF position, bool animate = false, float duration = 0.25f, public event MapEventHandler OnZoomEnd; [JSInvokable] - public void NotifyZoomEnd(Event e) => OnZoomEnd?.Invoke(this, e); + public async void NotifyZoomEnd(Event e) + { + try + { + await UpdateBounds(); + } + catch (Exception ex) + { + NotifyBackgroundExceptionOccurred(ex); + } + finally + { + OnZoomEnd?.Invoke(this, e); + } + } public event MapEventHandler OnMoveEnd; [JSInvokable] - public void NotifyMoveEnd(Event e) => OnMoveEnd?.Invoke(this, e); + public async void NotifyMoveEnd(Event e) + { + try + { + await UpdateBounds(); + } + catch (Exception ex) + { + NotifyBackgroundExceptionOccurred(ex); + } + finally + { + OnMoveEnd?.Invoke(this, e); + } + } + + public event EventHandler OnBoundsChanged; public event MouseEventHandler OnMouseMove; [JSInvokable] @@ -241,6 +298,10 @@ public void PanTo(PointF position, bool animate = false, float duration = 0.25f, [JSInvokable] public void NotifyPreClick(MouseEvent eventArgs) => OnPreClick?.Invoke(this, eventArgs); + public event EventHandler BackgroundExceptionOccurred; + private void NotifyBackgroundExceptionOccurred(Exception exception) => + BackgroundExceptionOccurred?.Invoke(this, exception); + #endregion events #region InteractiveLayerEvents diff --git a/BlazorLeaflet/BlazorLeaflet/Models/Bounds.cs b/BlazorLeaflet/BlazorLeaflet/Models/Bounds.cs new file mode 100644 index 0000000..d05c0e7 --- /dev/null +++ b/BlazorLeaflet/BlazorLeaflet/Models/Bounds.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; + +namespace BlazorLeaflet.Models +{ + public class Bounds + { + [DataMember(Name = "_northEast")] + public LatLng NorthEast { get; set; } + + [DataMember(Name = "_southWest")] + public LatLng SouthWest { get; set; } + + public Bounds() { } + public Bounds(LatLng southWest, LatLng northEast) + { + NorthEast = northEast; + SouthWest = southWest; + } + + public override string ToString() => + $"NE: {NorthEast.Lat} N, {NorthEast.Lng} E; SW: {SouthWest.Lat} N, {SouthWest.Lng} E"; + } +} diff --git a/BlazorLeaflet/BlazorLeaflet/wwwroot/leafletBlazorInterops.js b/BlazorLeaflet/BlazorLeaflet/wwwroot/leafletBlazorInterops.js index 88c53e1..fac31e6 100644 --- a/BlazorLeaflet/BlazorLeaflet/wwwroot/leafletBlazorInterops.js +++ b/BlazorLeaflet/BlazorLeaflet/wwwroot/leafletBlazorInterops.js @@ -1,4 +1,4 @@ -maps = {}; +maps = {}; layers = {}; window.leafletBlazor = { @@ -206,6 +206,9 @@ window.leafletBlazor = { }, getZoom: function (mapId) { return maps[mapId].getZoom(); + }, + getBounds: function (mapId) { + return maps[mapId].getBounds(); } };