Skip to content

Commit

Permalink
Clean up implementation, clustering improvement & API accessability
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickztar committed Nov 16, 2024
1 parent acbd37e commit 0f38f30
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 45 deletions.
11 changes: 10 additions & 1 deletion ClientSideDemo/Pages/AdvancedMarkerComponent.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@using GoogleMapsComponents.Maps
@using GoogleMapsComponents.Maps.Coordinates
@using GoogleMapsComponents.Maps.Extension
<AdvancedGoogleMap @ref="@_map1" Id="map1" Options="@_mapOptions">
<AdvancedGoogleMap @ref="@_map1" Id="map1" Options="@_mapOptions" OnMarkersChanged="@OnMarkersChanged">
@foreach (var markerRef in Markers.Where(x => x.Visible))
{
<MarkerComponent
Expand Down Expand Up @@ -84,6 +84,15 @@
}
}

async Task OnMarkersChanged()
{
if (_markerClustering != null)
{
await _markerClustering.ClearMarkers();
await _markerClustering.AddMarkers(_map1.Markers);
}
}

async Task ClearClustering()
{
if (_markerClustering != null)
Expand Down
2 changes: 1 addition & 1 deletion ClientSideDemo/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private static async Task Main(string[] args)

builder.Services.AddBlazorGoogleMaps(new MapApiLoadOptions("AIzaSyBdkgvniMdyFPAcTlcZivr8f30iU-kn1T0")
{
Version = "beta"
Version = "weekly"
});

builder.RootComponents.Add<App>("app");
Expand Down
21 changes: 18 additions & 3 deletions GoogleMapsComponents/AdvancedGoogleMap.razor
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@

internal Guid? MapId => MapRef?.InteropObject.Guid;

public IEnumerable<IMarker> Markers => MapComponents.Select(x => x.Value.ToMarker());
internal readonly Dictionary<Guid, MarkerComponent> MapComponents = [];
public int MarkerCount => MapComponents.Count;
public IEnumerable<MarkerComponent> Markers => MapComponents.Select(x => x.Value);
private readonly Dictionary<Guid, MarkerComponent> MapComponents = [];
internal DotNetObjectReference<AdvancedGoogleMap>? callbackRef;

[Parameter]
Expand All @@ -32,6 +33,9 @@

[Parameter]
public EventCallback OnAfterInit { get; set; }

[Parameter]
public EventCallback OnMarkersChanged { get; set; }

[Parameter]
public string? CssClass { get; set; }
Expand All @@ -50,7 +54,6 @@

private async Task AfterInit()
{

await OnAfterInit.InvokeAsync();
}

Expand All @@ -67,6 +70,18 @@
if (MapComponents.TryGetValue(markerId, out var markerComponent))
await markerComponent.MarkerDragged(position);
}

internal void AddMarker(MarkerComponent marker)
{
MapComponents.TryAdd(marker.Guid, marker);
OnMarkersChanged.InvokeAsync();
}

internal void RemoveMarker(MarkerComponent marker)
{
MapComponents.Remove(marker.Guid);
OnMarkersChanged.InvokeAsync();
}

public async ValueTask DisposeAsync()
{
Expand Down
7 changes: 1 addition & 6 deletions GoogleMapsComponents/Maps/MarkerClustering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@ public virtual async Task SetMap(Map map)
/// <summary>
/// Removes provided markers from the clusterer's internal list of source markers.
/// </summary>
public virtual async Task RemoveMarkers(IEnumerable<Marker> markers, bool noDraw = false)
{
await _jsObjectRef.JSRuntime.InvokeVoidAsync("blazorGoogleMaps.objectManager.removeClusteringMarkers", _jsObjectRef.Guid.ToString(), markers, noDraw);
}

public async Task RemoveMarkers(IEnumerable<AdvancedMarkerElement> markers, bool noDraw = false)
public virtual async Task RemoveMarkers(IEnumerable<IMarker> markers, bool noDraw = false)
{
await _jsObjectRef.JSRuntime.InvokeVoidAsync("blazorGoogleMaps.objectManager.removeClusteringMarkers", _jsObjectRef.Guid.ToString(), markers, noDraw);
}
Expand Down
64 changes: 39 additions & 25 deletions GoogleMapsComponents/Maps/MarkerComponent.razor.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using GoogleMapsComponents.Maps.Extension;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace GoogleMapsComponents.Maps;

public partial class MarkerComponent : IAsyncDisposable
public partial class MarkerComponent : IAsyncDisposable, IMarker
{
public MarkerComponent()
{
Guid = Guid.NewGuid();
_componentId = "marker_" + Guid.ToString("N");
_guid = Guid.NewGuid();
_componentId = "marker_" + _guid.ToString("N");
}
private readonly string _componentId;
private bool hasRendered = false;
internal bool IsDisposed = false;
private Guid _guid;

public Guid Guid { get; }
public Guid Guid => Id ?? _guid;

[Inject]
private IJSRuntime JS { get; set; } = default!;
Expand All @@ -27,84 +29,86 @@ public MarkerComponent()
private AdvancedGoogleMap MapRef { get; set; } = default!;

[Parameter]
[JsonIgnore]
public RenderFragment? ChildContent { get; set; }

[Parameter, JsonIgnore]
public Guid? Id { get; set; }

/// <summary>
/// Latitude in degrees. Values will be clamped to the range [-90, 90].
/// This means that if the value specified is less than -90, it will be set to -90.
/// And if the value is greater than 90, it will be set to 90.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public double Lat { get; set; }

/// <summary>
/// Longitude in degrees. Values outside the range [-180, 180] will be wrapped so that they fall within the range.
/// For example, a value of -190 will be converted to 170. A value of 190 will be converted to -170.
/// This reflects the fact that longitudes wrap around the globe.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public double Lng { get; set; }

/// <summary>
/// An enumeration specifying how an AdvancedMarkerElement should behave when it collides with another AdvancedMarkerElement or with the basemap labels on a vector map.
/// Note: AdvancedMarkerElement to AdvancedMarkerElement collision works on both raster and vector maps, however, AdvancedMarkerElement to base map's label collision only works on vector maps.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public CollisionBehavior? CollisionBehavior { get; set; }

/// <summary>
/// If true, the AdvancedMarkerElement can be dragged.
/// Note: AdvancedMarkerElement with altitude is not draggable.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public bool Draggable { get; set; }

/// <summary>
/// This event is fired when the user stops moving the marker.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public EventCallback<LatLngLiteral> OnMove { get; set; }

/// <summary>
/// If true, the AdvancedMarkerElement will be clickable and trigger the gmp-click event, and will be interactive for accessibility purposes (e.g. allowing keyboard navigation via arrow keys).
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public bool Clickable { get; set; }

/// <summary>
/// This event is fired when the marker is clicked.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public EventCallback OnClick { get; set; }

/// <summary>
/// Rollover text. If provided, an accessibility text (e.g. for use with screen readers) will be added to the
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public string? Title { get; set; }

/// <summary>
/// All entities are displayed on the map in order of their zIndex, with higher values displaying in front of entities with lower values.
/// By default, entities are displayed according to their vertical position on screen, with lower entities appearing in front of entities further up the screen.
/// </summary>
[Parameter]
[Parameter, JsonIgnore]
public int? ZIndex { get; set; }

/// <summary>
/// A possible override MapId, if this is unset, the markers will read their MapId from the AdvancedGoogleMap
/// </summary>
[Parameter, JsonIgnore]
public Guid? MapId { get; set; }

/// <summary>
/// Specifies additional custom attributes that will be rendered on the "root" component of the marker.
/// </summary>
/// <value>The attributes.</value>
[Parameter(CaptureUnmatchedValues = true)]
[Parameter(CaptureUnmatchedValues = true), JsonIgnore]
public IReadOnlyDictionary<string, object> Attributes { get; set; } = default!;

public IMarker ToMarker()
{
return new MarkerComponentRef()
{
Guid = Guid
};
}

internal async Task MarkerClicked()
{
await OnClick.InvokeAsync();
Expand All @@ -119,12 +123,21 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
MapRef.MapComponents[Guid] = this;
MapRef.AddMarker(this);
hasRendered = true;
await UpdateOptions();
}
await base.OnAfterRenderAsync(firstRender);
}

/// <summary>
/// Trigger a "update" of the component, by default the component will update automatically when parameters changes.
/// </summary>
public async Task ForceRender()
{
if (!hasRendered) return;
await UpdateOptions();
}

private async Task UpdateOptions()
{
Expand All @@ -136,7 +149,7 @@ private async Task UpdateOptions()
Title = Title ?? "",
GmpClickable = Clickable,
GmpDraggable = Draggable,
MapId = MapRef.MapId,
MapId = MapId ?? MapRef.MapId,
ZIndex = ZIndex
}, MapRef.callbackRef);
}
Expand All @@ -155,6 +168,7 @@ public override async Task SetParametersAsync(ParameterView parameters)
parameters.DidParameterChange(ZIndex) ||
parameters.DidParameterChange(Title) ||
parameters.DidParameterChange(Clickable) ||
parameters.DidParameterChange(MapId) ||
parameters.DidParameterChange(Draggable);

await base.SetParametersAsync(parameters);
Expand All @@ -170,7 +184,7 @@ public async ValueTask DisposeAsync()
if (IsDisposed) return;
IsDisposed = true;
await JS.InvokeVoidAsync("blazorGoogleMaps.objectManager.disposeAdvancedMarkerComponent", Guid);
MapRef.MapComponents.Remove(Guid);
MapRef.RemoveMarker(this);
GC.SuppressFinalize(this);
}

Expand Down
30 changes: 21 additions & 9 deletions GoogleMapsComponents/wwwroot/js/objectManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -897,11 +897,22 @@
};
const handleMarkerClick = (marker, options) => {
if (options.gmpClickable) {
marker.addEventListener("gmp-click", () => {
marker.clickListener = marker.addListener("click", () => {
callbackRef?.invokeMethodAsync('OnMarkerClicked', id);
});
} else {
marker.removeEventListener("gmp-click");
} else if (marker.clickListener) {
google.maps.event.removeListener(marker.clickListener);
delete marker.clickListener;
}
};
const handleMarkerDrag = (marker, options) => {
if (options.gmpDraggable) {
marker.dragListener = marker.addListener('dragend', (event) => {
callbackRef?.invokeMethodAsync('OnMarkerDrag', id, marker.position);
});
} else if (marker.dragListener) {
google.maps.event.removeListener(marker.dragListener);
delete marker.dragListener;
}
};
const existingMarker = mapObjects[id];
Expand All @@ -911,6 +922,7 @@
updateMarkerProperties(existingMarker, options);

if (clickChanged) handleMarkerClick(existingMarker, options);
if (dragChanged) handleMarkerDrag(existingMarker, options)
return;
}
const map = mapObjects[options.mapId];
Expand All @@ -929,15 +941,15 @@
});
advancedMarkerElement.guidString = id;
if (options.gmpClickable) {
advancedMarkerElement.addEventListener("gmp-click", _ => {
advancedMarkerElement.clickListener = advancedMarkerElement.addListener("click", _ => {
callbackRef?.invokeMethodAsync('OnMarkerClicked', id);
})
}
//Always add this event, since it's not removable
advancedMarkerElement.addListener('dragend', (event) => {
if (!advancedMarkerElement.gmpDraggable) return;
callbackRef?.invokeMethodAsync('OnMarkerDrag', id, advancedMarkerElement.position);
});
if (advancedMarkerElement.gmpDraggable) {
advancedMarkerElement.dragListener = advancedMarkerElement.addListener('dragend', (event) => {
callbackRef?.invokeMethodAsync('OnMarkerDrag', id, advancedMarkerElement.position);
});
}

addMapObject(id, advancedMarkerElement);
},
Expand Down

0 comments on commit 0f38f30

Please sign in to comment.