Skip to content

Commit

Permalink
Merge pull request #383 from Nickztar/advanced_component
Browse files Browse the repository at this point in the history
Advanced component rendered with Blazor
  • Loading branch information
valentasm1 authored Nov 17, 2024
2 parents d1b7812 + 0f38f30 commit 4c8e944
Show file tree
Hide file tree
Showing 22 changed files with 926 additions and 86 deletions.
123 changes: 123 additions & 0 deletions ClientSideDemo/Pages/AdvancedMarkerComponent.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
@page "/AdvancedMarkerComponent"
@using GoogleMapsComponents
@using GoogleMapsComponents.Maps
@using GoogleMapsComponents.Maps.Coordinates
@using GoogleMapsComponents.Maps.Extension
<AdvancedGoogleMap @ref="@_map1" Id="map1" Options="@_mapOptions" OnMarkersChanged="@OnMarkersChanged">
@foreach (var markerRef in Markers.Where(x => x.Visible))
{
<MarkerComponent
@key="markerRef.Id"
Lat="@markerRef.Lat"
Lng="@markerRef.Lng"
Clickable="@markerRef.Clickable"
Draggable="@markerRef.Draggable"
OnClick="@(() => markerRef.Active = !markerRef.Active)"
OnMove="pos => markerRef.UpdatePosition(pos)"
data-iscool="@true">
<CoolMarker Marker="markerRef" />
</MarkerComponent>
}
</AdvancedGoogleMap>

@foreach (var marker in Markers)
{
<div style="display: flex; gap: 8px;">
<p style="@(marker.Visible ? "" : "text-decoration: line-through")">@marker.Id -> (@marker.Lat x @marker.Lng)</p>
<button @onclick="@(() => marker.Clickable = !marker.Clickable)">Toggle click</button>
<button @onclick="@(() => marker.Draggable = !marker.Draggable)">Toggle drag</button>
<button @onclick="@(() => marker.Visible = !marker.Visible)">Toggle marker</button>
</div>
}

<button @onclick="@InvokeClustering">Invoke map cluster</button>
<button @onclick="@ClearClustering">ClearClustering</button>

@code {
private List<MarkerData> Markers =
[
new MarkerData { Id = 1, Lat = 13.505892, Lng = 100.8162 },
new MarkerData { Id = 2, Lng = 150.363181, Lat = -33.718234 },
new MarkerData { Id = 3, Lng = 150.371124, Lat = -33.727111 },
new MarkerData { Id = 4, Lng = 151.209834, Lat = -33.848588 },
new MarkerData { Id = 5, Lng = 151.216968, Lat = -33.851702 },
new MarkerData { Id = 6, Lng = 150.863657, Lat = -34.671264 },
new MarkerData { Id = 7, Lng = 148.662905, Lat = -35.304724 },
new MarkerData { Id = 8, Lng = 175.699196, Lat = -36.817685 },
new MarkerData { Id = 9, Lng = 175.790222, Lat = -36.828611 },
new MarkerData { Id = 10, Lng = 145.116667, Lat = -37.75 }
];

private AdvancedGoogleMap _map1 = null!;
MarkerClustering? _markerClustering;
private readonly MapOptions _mapOptions = new MapOptions()
{
Zoom = 13,
Center = new LatLngLiteral()
{
Lat = 13.505892,
Lng = 100.8162
},
IsFractionalZoomEnabled = false,
HeadingInteractionEnabled = true,
CameraControl = true,
MapTypeId = MapTypeId.Roadmap,
// ColorScheme = ColorScheme.Dark,
MapId = "e5asd595q2121"
};

async Task InvokeClustering()
{
if (_map1.MapRef is null) return;
if (_markerClustering == null)
{
_markerClustering = await MarkerClustering.CreateAsync(_map1.MapRef.JsRuntime, _map1.InteropObject!, _map1.Markers, new MarkerClustererOptions()
{
ZoomOnClick = true
// RendererObjectName = "customRendererLib.interpolatedRenderer"
});
}
else
{
await _markerClustering.ClearMarkers();
await _markerClustering.AddMarkers(_map1.Markers);
}
}

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

async Task ClearClustering()
{
if (_markerClustering != null)
{
await _markerClustering.ClearMarkers();
await _markerClustering.DisposeAsync();
_markerClustering = null;
}
}

public class MarkerData
{
public int Id { get; set; }
public double Lat { get; set; }
public double Lng { get; set; }
public bool Clickable { get; set; } = true;
public bool Draggable { get; set; }

public bool Visible { get; set; } = true;
public bool Active { get; set; }

public void UpdatePosition(LatLngLiteral position)
{
Lat = position.Lat;
Lng = position.Lng;
}
}
}
30 changes: 30 additions & 0 deletions ClientSideDemo/Shared/CoolMarker.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@using ClientSideDemo.Pages
@if (Marker.Active)
{
<div style="display: flex; padding: 10px; flex-direction: column; gap: 4px; background-color: #b3d7ff; ">
<p>I am now active</p>
<p>You could render literally anything <br/> with just default blazor</p>
<p>This is just a simple example that <br /> shows of marker with label</p>
<p>Current at: @Marker.Lat x @Marker.Lng</p>
</div>
}
else
{
<div style="position: relative;">
<div class="unitLabel" style="position: absolute;right: 0;top: 0;transform: translate(100%, -50%);">
<div class="label label-arrowLeft">
<div class="label-content">
<span class="label-name" style="width: 100%;">@($"Name {Marker.Id}")</span>
<span class="label-icon">
<img alt="error" src="https://cdn-icons-png.flaticon.com/512/1304/1304038.png">
</span>
</div>
</div>
</div>
<svg width="50px" height="50px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 16.0156C19.2447 16.5445 20 17.2392 20 18C20 19.6568 16.4183 21 12 21C7.58172 21 4 19.6568 4 18C4 17.2392 4.75527 16.5445 6 16.0156" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><path d="M17 8.44444C17 11.5372 12 17 12 17C12 17 7 11.5372 7 8.44444C7 5.35165 9.23858 3 12 3C14.7614 3 17 5.35165 17 8.44444Z" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><circle cx="12" cy="8" r="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
</div>
}

@code {
[Parameter] public AdvancedMarkerComponent.MarkerData Marker { get; set; } = default!;
}
6 changes: 5 additions & 1 deletion ClientSideDemo/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@
<span class="oi oi-list-rich" aria-hidden="true"></span> MapRoutes
</NavLink>
</li>

<li class="nav-item px-3">
<NavLink class="nav-link" href="AdvancedMarkerComponent">
<span class="oi oi-list-rich" aria-hidden="true"></span> AdvancedMarkerComponent
</NavLink>
</li>
</ul>
</div>

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
56 changes: 56 additions & 0 deletions ClientSideDemo/wwwroot/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,59 @@ app {
display: block;
}
}

.label {
position: relative;
display: inline-block;
background-color: #fff;
padding: 8px 14px;
line-height: 22px;
min-height: 35px;
}

.label::before {
content: "";
position: absolute;
top: -4px;
left: 0;
right: 0;
margin: 0 auto;
height: 4px;
width: calc(100% - 20px);
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}


.label-content {
display: flex;
justify-items: center;
justify-content: space-between;
min-width: 120px;
font-family: sans-serif;
font-size: 16px;
}

.label-arrowLeft::after {
content: "";
position: absolute;
bottom: 0;
left: -8px;
width: 0;
height: 0;
border-style: solid;
border-width: 8px 8px 0 0;
border-color: transparent #fff transparent transparent;
-webkit-transform: rotate(360deg);
}

.label-arrowLeft {
border-radius: 10px 10px 10px 0;
box-shadow: -2px 6px 20px rgba(0, 0, 0, .45);
}

.label-icon {
display: flex;
height: 20px;
margin-left: 8px;
}
95 changes: 95 additions & 0 deletions GoogleMapsComponents/AdvancedGoogleMap.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
@using GoogleMapsComponents.Maps
@using Microsoft.JSInterop
@implements IAsyncDisposable

<GoogleMap @ref="@MapRef" Id="@Id" Height="@Height" Options="@Options" OnAfterInit="@AfterInit" CssClass="@CssClass" />

@if (MapRef?.InteropObject is not null)
{
<CascadingValue Name="Map" Value="@this" IsFixed="true">
@ChildContent
</CascadingValue>
}

@code {
// Due to us wrapping the normal map, keep this public to still be able to access the interop.
public GoogleMap? MapRef;

// Expose this for simplicity.
public Map? InteropObject => MapRef?.InteropObject;

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

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]
public string? Id { get; set; }

[Parameter]
public MapOptions? Options { get; set; }

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

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

[Parameter]
public string? CssClass { get; set; }

[Parameter]
public string? Height { get; set; }

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

protected override void OnInitialized()
{
callbackRef = DotNetObjectReference.Create(this);
base.OnInitialized();
}

private async Task AfterInit()
{
await OnAfterInit.InvokeAsync();
}

[JSInvokable]
public async Task OnMarkerClicked(Guid markerId)
{
if (MapComponents.TryGetValue(markerId, out var markerComponent))
await markerComponent.MarkerClicked();
}

[JSInvokable]
public async Task OnMarkerDrag(Guid markerId, LatLngLiteral position)
{
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()
{
// Mark components as disposed, since they will be removed by disposing the MapRef.
foreach (var component in MapComponents)
component.Value.IsDisposed = true;
if (MapRef != null) await MapRef.DisposeAsync();
callbackRef?.Dispose();
}

}
37 changes: 5 additions & 32 deletions GoogleMapsComponents/GoogleMap.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@
@using Microsoft.JSInterop

@inherits MapComponent
@implements IDisposable
@inject IJSRuntime JSRuntime

<div @ref="@Element" id="@Id" class="@CssClass" style="@StyleStr"></div>

@code {
#nullable enable
// Load the module and keep a reference to it
// You need to use .AsTask() to convert the ValueTask to Task as it may be awaited multiple times
//private List<IJSObjectReference> moduleImports = new List<IJSObjectReference>();
[Parameter]
public string? Id { get; set; }

Expand Down Expand Up @@ -52,33 +46,12 @@
{
if (firstRender)
{
//var tasks = new List<Task<IJSObjectReference>>();
//tasks.Add(JSRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/BlazorGoogleMaps/js/objectManager.js").AsTask());
//if(!string.IsNullOrWhiteSpace(ApiKey))
// tasks.Add(JSRuntime.InvokeAsync<IJSObjectReference>("import", $"https://maps.googleapis.com/maps/api/js?key={ApiKey}&v=3").AsTask());
//moduleImports.AddRange(await Task.WhenAll(tasks.ToArray()));
await InitAsync(Element, Options);
await OnAfterInit.InvokeAsync();
}

await InitAsync(Element, Options);

//Debug.WriteLine("Init finished");
await OnAfterInit.InvokeAsync();

await base.OnAfterRenderAsync(firstRender);
}

protected override bool ShouldRender()
{
return false;
}

void IDisposable.Dispose()
{
//if(moduleImports != null && moduleImports.Count > 0)
//{
// foreach (var mi in moduleImports)
// await mi.DisposeAsync();
//}
base.Dispose();
}
protected override bool ShouldRender() => false;
}
Loading

0 comments on commit 4c8e944

Please sign in to comment.