rungwiroon / BlazorGoogleMaps

Blazor interop for GoogleMap library
MIT License
323 stars 104 forks source link

Get list of makers within a cluster a user clicks on #233

Closed PhilJenson closed 1 year ago

PhilJenson commented 1 year ago

I would like to display an info window when a user clicks on a clustered marker, displaying information on the markers within that specific cluster.

How can I get a list of markers which are contained within the specific cluster the user clicks on? The click event returns a reference to MouseEvent which contains no useful information. Ultimately I need a reference back to our data object used to create the marker.

Added: This is within a Web Assembly project.

valentasm1 commented 1 year ago

You should try find example here. If exist there we could try implement by ourselfs too https://googlemaps.github.io/js-markerclusterer/

PhilJenson commented 1 year ago

Found a solution. Just create a class which returns a list of markers and use this within the AddListener return type. If you create your own Options class for the markers, then you can also return additional information such as the DataID below.

 var cluster = await MarkerClustering.CreateAsync(map.JsRuntime, map.InteropObject, markers, options);
await cluster.AddListener<GoogleClusterClickEvent>("click", OnClusterLClicked)
public class GoogleClusterClickEvent: MouseEvent {
    public List<GoogleMarker> Markers {get;set;}
    public LatLngLiteral _Position { get; set; }
}

public class GoogleMarker {
    public long DataID { get; set; }
    public LatLngLiteral Position { get; set; }
}

public class GoogleMarkerOptions : MarkerOptions {
    public string   ClusterFillColor    { get; set; } = "White";
    public string   ClusterTextColor    { get; set; } = "Black";
    public double   ClusterOpacity      { get; set; } = 0.9;
    public string?  ClusterTitle        { get; set; }
    public int      ClusterZIndex       { get; set; }
    public long     DataID           { get; set; }
}

Note: GoogleMarkerOptions should not be used on the cluster but the options on the markers being added to the cluster.

valentasm1 commented 1 year ago

I think i could add this to library. Will do in coming day. Thank you for research.

PhilJenson commented 1 year ago

I am getting mixed results. When debugging with Visual Studio within Edge it works, just slow. But when I run on a live sever an uncaught exception is being thrown which prevents the click handler from being called.

Uncaught (in promise) Error: Newtonsoft.Json.JsonReaderException: The reader's MaxDepth of 64 has been exceeded. Path '[0].marker.__gm.set.j.201.gm_accessors_.icon.oj.gm_accessors_.mode.oj.W.gm_bindings_.controlSize.13.oj.__gm.gm_accessors_.isMapInitialized.oj.gm_accessors_.tilt.oj.gm_bindings_.tilt.158.oj.Ba.j.qc.1090.j[0].h.markers[2].__gm.Vl.Ub.3195.Dc.Ub.j.3344.Ck.Ub.3343.Dc.Ub.j.3255.Ck.Ub.3254.Dc.Ub.j.3201.Ck.C.__e3_.click.474', line 1, position 99985.
   at Newtonsoft.Json.JsonReader.Push(JsonContainerType value)
   at Newtonsoft.Json.JsonReader.SetToken(JsonToken newToken, Object value, Boolean updateIndex)
   at Newtonsoft.Json.JsonReader.SetToken(JsonToken newToken)
   at Newtonsoft.Json.JsonTextReader.ParseValue()
   at Newtonsoft.Json.JsonTextReader.Read()
   at Newtonsoft.Json.Linq.JContainer.ReadContentFrom(JsonReader r, JsonLoadSettings settings)
   at Newtonsoft.Json.Linq.JContainer.ReadTokenFrom(JsonReader reader, JsonLoadSettings options)
   at Newtonsoft.Json.Linq.JArray.Load(JsonReader reader, JsonLoadSettings settings)
   at Newtonsoft.Json.Linq.JArray.Parse(String json, JsonLoadSettings settings)
   at Newtonsoft.Json.Linq.JArray.Parse(String json)
   at GoogleMapsComponents.JsCallableAction.Invoke(String args, String guid)
   at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.InvokeSynchronously(JSRuntime , DotNetInvocationInfo& , IDotNetObjectReference , String )
   at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.BeginInvokeDotNet(JSRuntime , DotNetInvocationInfo , String )

It seems like the whole javascript cluster object is being serialized into a string, I guess to marshal to .net code, and then failing to deserialize due to the above error. If so the real issue is probably in serializing the whole cluster object in the first instance, as it seems to have a lot of properties which are not actually required for the click event.

A bit of a dirty hack, but could the javascript code within objectManger tryParseJson(item) routine check if it is a cluster and return a GoogleMarker object similar to my previous post, based on the information within the cluster?

PhilJenson commented 1 year ago

I don't know the best way to do this but adding the following to the function window.blazorGoogleMaps.tryParseJson(item), solves the issue

          if (args.length == 1 && typeof args[0].marker !== "undefined") {
              var n = args[0].marker;
              args[0].marker = null;
              await item.invokeMethodAsync("Invoke", JSON.stringify(args, getCircularReplacer()), guid);
              args[0].marker = n;
          }
          else {
              await item.invokeMethodAsync("Invoke", JSON.stringify(args, getCircularReplacer()), guid);
          }
valentasm1 commented 1 year ago

Added to latest release https://www.nuget.org/packages/BlazorGoogleMaps/2.4.4