Skip to content

MarkerList for multi markets manipulation

Valentas edited this page Jul 14, 2020 · 7 revisions

Sample Practical case:

Better place to start is "OnMapAfterInitAsync" event handler

a) Retrieve some entities having "marker role", as bus stop from a own "business service" (or a JSON file, or other things): Stops = gtfsService.Stops[Id] .Values .Where(s => !string.IsNullOrEmpty(s.Code)) .ToList();

Object list need to contains coordinates info and a key to be used to designate univocally a Marker (in that case Stop.Id)

b) Create a new MarkerList using CreateAsync and relative markerOptions (eventually with a title as tooltip for markers, eventually the same or different marker icons):

stopMarkerList = await MarkerList.CreateAsync
(
  gtfsMap.JsRuntime,
  Stops.ToDictionary(s => s.Id, s => new MarkerOptions
  {
    Position = new LatLngLiteral(s.Longitude, s.Latitude),
    Map = map.InteropObject,
    Title = s.Code,
    Icon = "/images/stop.png",
    Visible = false
   })
 );

If the marker number is big, is strongly recommended to start with "Visible = false" -> Markers are already on map, but not visible

c) Define when and what markers show, defining map event event handlers:

await map.InteropObject.AddListener("zoom_changed", MapOnBoundsChanged);
await map.InteropObject.AddListener("dragend", MapOnBoundsChanged);

d) Implements MapOnBoundsChanged similar to:

private async void MapOnBoundsChanged()
{
  //Use a SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); if you need to be sure to have a "critical section" where only one thread at time can enter
  //This is a way to limit the concurrency on markers when user moves "back and forth" many times on map -> however zoom changed and drag end are "good event filter",
  //only when user stops to move the map the "drag end" event fires.
  await semaphore.WaitAsync();

  try
  {
    int zoom = await gtfsMap.InteropObject.GetZoom();

    if (zoom >= 15)
    {
      LatLngBoundsLiteral bounds = await map.InteropObject.GetBounds();
      double minLongitude = Math.Min(bounds.West, bounds.East);
      double maxLongitude = Math.Max(bounds.West, bounds.East);
      double minLatitude = Math.Min(bounds.North, bounds.South);
      double maxLatitude = Math.Max(bounds.North, bounds.South);

      //Only id zoom is bigger than a chosen number (f.i. 15) and
      //only id our markers are inside Map Bounds
      {
        //Filter the objects we want to show on map
        List<GTFSStop> StopsToShow = Stops.Where(s => (s.Latitude >= minLatitude) && (s.Latitude <= maxLatitude))
                                          .Where(s => (s.Longitude >= minLongitude) && (s.Longitude <= maxLongitude))
                                          .ToList();

        //Calc the markers that need to be shown and to be hidden
        List<string> MarkersToShow = StopsToShow.Select(s => s.Id).ToList().Except(VisibleStopMarkers).ToList();
        List<string> MarkersToHide = VisibleStopMarkers.Except(StopsToShow.Select(s => s.Id).ToList()).ToList();

        if (MarkersToShow.Count > 0)
        {
          //Set visibility at true for all needed markers
          *await stopMarkerList.SetVisibles(MarkersToShow.ToDictionary(e => e, e => true));*

          //Add only required event listener (important: only when not yet defined)
          foreach (string key in MarkersToShow)
          {
            *Marker marker = stopMarkerList.Markers[key];*

            if
            (
              (!*marker.EventListeners.ContainsKey("click"))* ||
              (*marker.EventListeners["click"].Count == 0*)
            )
            {
              *await marker.AddListener("click", async () => { await OnMarkerClick(key); });*
            }
          }

//Some tested methods usable when needed
*//Dictionary<string, LatLngLiteral> markerPositions = await stopMarkerList.GetPositions(MarkersToShow); 
//Dictionary<string,bool> markerClickables = awaitstopMarkerList.GetClickables(MarkersToShow); 
//Dictionary<string,string> markerCursors = await stopMarkerList.GetCursors(MarkersToShow);
//Dictionary<string, bool> markerDraggables = await stopMarkerList.GetDraggables(MarkersToShow);
//Dictionary<string,string> markerLabels = await stopMarkerList.GetLabels(MarkersToShow);
//Dictionary<string, string> markerTitles = await stopMarkerList.GetTitles(MarkersToShow);
//Dictionary<string, bool> markerVisibles = await stopMarkerList.GetVisibles(MarkersToShow);
//Dictionary<string, int> markerZIndexes = await stopMarkerList.GetZIndexes(MarkersToShow);*

          //Set visibility to false to markers to be hidden
          if (MarkersToHide.Count > 0)
          {
            *await stopMarkerList.SetVisibles(MarkersToHide.ToDictionary(e=> e, e => false));*
          }

          VisibleStopMarkers = StopsToShow.Select(s => s.Id).ToList();
        }
      }
    }
    else
    {
      //Zoom is too low? Hide all markers (not usable contents on map due to overcrowding when a lot of markers are shown)
      {
        *await stopMarkerList.SetVisibles(VisibleStopMarkers.ToDictionary(e=> e, e => false));*
        //Don't forget to clear the list of visible markers!
        VisibleStopMarkers.Clear();
      }
    }
  }
  finally
  {
    //Don't forget to release the semaphore, otherwise no other threads can be enter in the "critical section"
    semaphore.Release();
  }
}

Clone this wiki locally