diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMapDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMapDocumentation.razor
index ecc5f8e76..529727f89 100644
--- a/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMapDocumentation.razor
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMapDocumentation.razor
@@ -71,6 +71,22 @@
+
+
+ This example shows how to enable clustering, so that nearby markers group together. By using GoogleMapClusterOptions
+ and by setting ClusteringEnabled to true , and by setting the options to the GoogleMaps component, clustering will be enabled.
+
+
+
+
+
+
+ This example expands on clustering, showing how to customize the cluster markers to your own design, by using the GoogleMapClusterOptions . The cluster marker can be customized by changing the GoogleMapClusterRenderer
+ . You can also change the Algorithm's as well as the MaxZoom 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.
+
+
+
+
@code {
private const string pageUrl = RouteConstants.Demos_GoogleMap_Documentation;
private const string pageTitle = "Blazor Google Map";
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMap_Demo_07_Dynamic_markers_with_clustering.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMap_Demo_07_Dynamic_markers_with_clustering.razor
new file mode 100644
index 000000000..b63ab3dfb
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMap_Demo_07_Dynamic_markers_with_clustering.razor
@@ -0,0 +1,169 @@
+@inherits GoogleMapDemoComponentBase
+
+
+ await AddWeatherMarkerAsync())">
+ Add Marker
+
+ await UpdateWeatherMarkersAsync())">
+ Update Markers
+
+ await RefreshMapAsync())">
+ Refresh Map
+
+
+
+
+
+@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
+ {
+ 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 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",
+ };
+ }
+}
\ No newline at end of file
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMap_Demo_08_Dynamic_markers_with_custom_clustering.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMap_Demo_08_Dynamic_markers_with_custom_clustering.razor
new file mode 100644
index 000000000..b329e1382
--- /dev/null
+++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Maps/GoogleMap_Demo_08_Dynamic_markers_with_custom_clustering.razor
@@ -0,0 +1,203 @@
+@inherits GoogleMapDemoComponentBase
+
+
+ await AddWeatherMarkerAsync())">
+ Add Marker
+
+ await UpdateWeatherMarkersAsync())">
+ Update Markers
+
+ await RefreshMapAsync())">
+ Refresh Map
+
+
+
+
+
+@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 = @" ",
+ }
+
+ };
+
+ [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
+ {
+ 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 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",
+ };
+ }
+}
\ No newline at end of file
diff --git a/BlazorBootstrap.Demo.WebAssembly/wwwroot/index.html b/BlazorBootstrap.Demo.WebAssembly/wwwroot/index.html
index dbbab8bcd..23770818c 100644
--- a/BlazorBootstrap.Demo.WebAssembly/wwwroot/index.html
+++ b/BlazorBootstrap.Demo.WebAssembly/wwwroot/index.html
@@ -57,6 +57,8 @@
+
+