Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Google Maps] Marker Cluster #935

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@
<Demo Type="typeof(GoogleMap_Demo_06_Dynamic_markers)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Dynamic markers with clustering" PageUrl="@pageUrl" Link="dynamic-markers-with-clusters">
<div class="mb-3">
This example shows how to enable clustering, so that nearby markers group together. By using <b>GoogleMapClusterOptions</b>
and by setting <b>ClusteringEnabled</b> to <b>true</b>, and by setting the options to the GoogleMaps component, clustering will be enabled.
</div>
<Demo Type="typeof(GoogleMap_Demo_07_Dynamic_markers_with_clustering)" Tabs="true" />
</Section>

<Section Size="HeadingSize.H2" Name="Dynamic markers with custom clusters" PageUrl="@pageUrl" Link="dynamic-markers-with-custom-clusters">
<div class="mb-3">
This example expands on clustering, showing how to customize the cluster markers to your own design, by using the <b>GoogleMapClusterOptions</b>. The cluster marker can be customized by changing the <b>GoogleMapClusterRenderer
</b>. You can also change the Algorithm's as well as the <b>MaxZoom</b> level. See https://googlemaps.github.io/js-markerclusterer/public/algorithms/ for the showcase of the different algorithms available. You can define a ClusterClick event the same way you would do markers too.
</div>
<Demo Type="typeof(GoogleMap_Demo_08_Dynamic_markers_with_custom_clustering)" Tabs="true"/>
</Section>

@code {
private const string pageUrl = RouteConstants.Demos_GoogleMap_Documentation;
private const string pageTitle = "Blazor Google Map";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
@inherits GoogleMapDemoComponentBase

<div>
<Button Color="ButtonColor.Primary" Size="ButtonSize.Small" @onclick="(async () => await AddWeatherMarkerAsync())">
<Icon Name="IconName.GeoAltFill" /> Add Marker
</Button>
<Button Color="ButtonColor.Danger" Size="ButtonSize.Small" @onclick="(async () => await UpdateWeatherMarkersAsync())">
<Icon Name="IconName.GeoAltFill" /> Update Markers
</Button>
<Button Color="ButtonColor.Warning" Size="ButtonSize.Small" @onclick="(async () => await RefreshMapAsync())">
<Icon Name="IconName.MapFill" /> Refresh Map
</Button>
</div>

<GoogleMap @ref="googleMapRef"
ApiKey="@ApiKey"
Center="new GoogleMapCenter(37.43238031167444, -122.16795397128632)"
Height="400"
Width="100"
Zoom="10"
Markers="markers"
ClusterOptions="clusterOptions"
OnMarkerClick="OnGoogleMapMarkerClick" />

@code {
Random random = new Random(2000000000);
GoogleMap googleMapRef = default!;
GoogleMapClusterOptions clusterOptions = new GoogleMapClusterOptions()
{
ClusteringEnabled = true,
};

[Inject] public ToastService ToastService { get; set; } = default!;

private async ValueTask AddWeatherMarkerAsync() => await googleMapRef.AddMarkerAsync(GetRandomMarker());

private async Task UpdateWeatherMarkersAsync()
{
var markerList = new List<GoogleMapMarker>
{
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
};
await googleMapRef.UpdateMarkersAsync(markerList);
}

private async Task RefreshMapAsync()
{
markers.Add(GetRandomMarker());
markers.Add(GetRandomMarker());

await googleMapRef.RefreshAsync();
}

private void OnGoogleMapMarkerClick(GoogleMapMarker marker)
{
ToastService.Notify(new ToastMessage(ToastType.Success, $"{marker.Title}", $"This is a toast message for a weather forecast. DateTime: {DateTime.Now}"));
}

List<GoogleMapMarker> markers = new()
{
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-drizzle-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.50024109655184, -122.28528451834352),
Title = "Drizzle",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-drizzle-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.44440882321596, -122.2160620727),
Title = "Drizzle",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-lightning-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.39561833718522, -122.21855116258479),
Title = "Lightning rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-lightning-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.423928529779644, -122.1087629822001),
Title = "Lightning rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.40578635332598, -122.15043378466069),
Title = "Rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.36399747905774, -122.10465384268522),
Title = "Rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-heavy-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[3].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[3].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.38343706184458, -122.02340436985183),
Title = "Heavy rain",
}
};

private GoogleMapMarker GetRandomMarker()
{
var lat = Double.Parse($"37.{random.Next()}");
var lng = Double.Parse($"-122.{random.Next()}");
return new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-heavy-fill fs-6 text-white",
UseIconFonts = true,
Background = ColorUtility.CategoricalTwelveColors[9].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor = ColorUtility.CategoricalTwelveColors[9].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(lat, lng),
Title = "Heavy rain",
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
@inherits GoogleMapDemoComponentBase

<div>
<Button Color="ButtonColor.Primary" Size="ButtonSize.Small" @onclick="(async () => await AddWeatherMarkerAsync())">
<Icon Name="IconName.GeoAltFill" /> Add Marker
</Button>
<Button Color="ButtonColor.Danger" Size="ButtonSize.Small" @onclick="(async () => await UpdateWeatherMarkersAsync())">
<Icon Name="IconName.GeoAltFill" /> Update Markers
</Button>
<Button Color="ButtonColor.Warning" Size="ButtonSize.Small" @onclick="(async () => await RefreshMapAsync())">
<Icon Name="IconName.MapFill" /> Refresh Map
</Button>
</div>

<GoogleMap @ref="googleMapRef"
ApiKey="@ApiKey"
Center="new GoogleMapCenter(37.43238031167444, -122.16795397128632)"
Height="400"
Width="100"
Zoom="10"
Markers="markers"
ClusterOptions="clusterOptions"
OnMarkerClick="OnGoogleMapMarkerClick"
OnClusterClick="OnGoogleMapClusterClick"/>

@code {
Random random = new Random(2000000000);
GoogleMap googleMapRef = default!;
GoogleMapClusterOptions clusterOptions = new GoogleMapClusterOptions()
{
ClusteringEnabled = true,
EnableClusterClick = true,
Algorithm = new GoogleMapClusterAlgorithm
{
Type = GoogleMapAlgorithmTypes.SuperClusterAlgorithm.ToString(),
Options = new GoogleMapClusterAlgorithmOptions()
{
MaxZoom = 16,
}
},
Renderer = new GoogleMapClusterRenderer
{
TextColor = "#ff0000",
TextFontSize = "30px",
SvgIcon = @"<svg width='50px' height='50px' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='#000000' stroke-width='1' stroke-linecap='round' stroke-linejoin='miter'><circle cx='12' cy='12' r='10'></circle><circle cx='12' cy='12' r='10' fill='#059cf7' opacity='0.1'></circle></svg>",
}

};

[Inject] public ToastService ToastService { get; set; } = default!;

private void OnGoogleMapClusterClick(GoogleMapClusterClickEvent clusterEvent)
{
var weatherTypes = clusterEvent.Markers
.Select(m => m.Title)
.GroupBy(title => title)
.Select(g => $"{g.Key}: {g.Count()}")
.ToList();

var summary = string.Join(", ", weatherTypes);

ToastService.Notify(new ToastMessage(
ToastType.Info,
$"Cluster clicked: {clusterEvent.Markers.Count()} markers",
$"Weather summary: {summary}\nPosition: ({clusterEvent.Position.Latitude:F6}, {clusterEvent.Position.Longitude:F6})"
));
}

private async ValueTask AddWeatherMarkerAsync() => await googleMapRef.AddMarkerAsync(GetRandomMarker());

private async Task UpdateWeatherMarkersAsync()
{
var markerList = new List<GoogleMapMarker>
{
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
GetRandomMarker(),
};
await googleMapRef.UpdateMarkersAsync(markerList);
}

private async Task RefreshMapAsync()
{
markers.Add(GetRandomMarker());
markers.Add(GetRandomMarker());

await googleMapRef.RefreshAsync();
}

private void OnGoogleMapMarkerClick(GoogleMapMarker marker)
{
ToastService.Notify(new ToastMessage(ToastType.Success, $"{marker.Title}", $"This is a toast message for a weather forecast. DateTime: {DateTime.Now}"));
}

List<GoogleMapMarker> markers = new()
{
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-drizzle-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.50024109655184, -122.28528451834352),
Title = "Drizzle",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-drizzle-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[0].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.44440882321596, -122.2160620727),
Title = "Drizzle",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-lightning-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.39561833718522, -122.21855116258479),
Title = "Lightning rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-lightning-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[2].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.423928529779644, -122.1087629822001),
Title = "Lightning rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.40578635332598, -122.15043378466069),
Title = "Rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[1].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.36399747905774, -122.10465384268522),
Title = "Rain",
},
new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-heavy-fill fs-6 text-white",
UseIconFonts = true,
Background=ColorUtility.CategoricalSixColors[3].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor=ColorUtility.CategoricalSixColors[3].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(37.38343706184458, -122.02340436985183),
Title = "Heavy rain",
}
};

private GoogleMapMarker GetRandomMarker()
{
var lat = Double.Parse($"37.{random.Next()}");
var lng = Double.Parse($"-122.{random.Next()}");
return new GoogleMapMarker()
{
PinElement = new PinElement
{
Glyph = "bi bi-cloud-rain-heavy-fill fs-6 text-white",
UseIconFonts = true,
Background = ColorUtility.CategoricalTwelveColors[9].ToColor().ToRgbaString().ToLowerInvariant(),
BorderColor = ColorUtility.CategoricalTwelveColors[9].ToColor().ToRgbString().ToLowerInvariant()
},
Position = new GoogleMapMarkerPosition(lat, lng),
Title = "Heavy rain",
};
}
}
Loading