How can I separate items/ make new array of items that have positional values that are close together

Viewed 22

Working Code Example

My Question:

How can I separate the events in my array that are close together? Specifically, .005deg in either lat or longitude. I need to use separate logic for these events because there is only one of these events a user can see as they are on top of each other, so once again I plan on having different logic for handling these events.

Code:

// filter through all events and only return lat and long values that have at least one duplicate
let duplicateEvents = events.filter((event, index, self) => {
  // console.log({ lat: event.event_links.data[0].attributes.linkLabel, long: event.event_links.data[0].attributes.linkUrl }),
  let eventLat = Number(event.event_links.data[0].attributes.linkLabel)
  let eventLong = Number(event.event_links.data[0].attributes.linkUrl)

  // Remove the current event item from the self array
  let selfWithoutCurrentEvent = self.filter((item, i) => i !== index)

  console.log({
    selfWithoutCurrentEvent
  });

  // We must remove the current item form the self array because we don't want to compare the current item with itself
  return selfWithoutCurrentEvent.map((otherEvent) => {

    let otherEventLat = Number(otherEvent.event_links.data[0].attributes.linkLabel)
    let otherEventLong = Number(otherEvent.event_links.data[0].attributes.linkUrl)

    let latDiff = Math.abs(otherEventLat - eventLat);
    let longDiff = Math.abs(otherEventLong - eventLong);

    if ((latDiff <= 0.005) && (longDiff <= 0.005)) {
      return true
    } else {
      console.log({
        eventLat,
        eventLong,
        otherEventLat,
        otherEventLong,
        latDiff,
        longDiff,
        math: (latDiff <= 0.001) && (longDiff <= 0.001),
        event
      })
      return false
    }
    // console.log({ latdif: Math.abs(eventLat - otherEventLat), longdif: Math.abs(eventLong - otherEventLong) })
  })

})

console.log({
  duplicateEvents
})

What I tried to do

I have tried first making a new array that removes the current item from the Array. So that we can test this array for similar coordinates. If I leave the current event it will always be returned because it's coordinates will match with itself. After removing the current item we compare its coordinates with all the other items in the array to see if any other items are within the .005 range. If so return true to the filter... But this isn't working

My Problem:

No matter how I try to filter the array of events I keep getting back every event which is weird because one of them should be removed from the selfWithoutCurrentEvent ARRAY no matter what every time. I think my problem has something to do with how returns are working with my multiple filters

Why I am doing it

I plan on having different logic for displaying the map pin to the map via react. What I will do is instead of having the pop-up display the event information I will first see if their coordinates are within the range of any of the events in that array of events that have other events within the .005 range of them (this is what I am unable to create right now). Then instead of displaying its information in the map pin pop-up, I will list the other events at that location, this will stop events from being hidden behind other map markers.

MapExample

As you can see this pop-up displays information, but if there are 5 other events with the same location they can't see those other events. This is why I need to separate events that are on top of each other (within .005 lat || long of each other). Then when someone hovers on the pin we can display all the covered events links instead of just one event information.

Path to the Lat coordinate: event.event_links.data[0].attributes.linkLabel

Path to the Long coordinate: event.event_links.data[0].attributes.linkUrl

Working Code Example Again

1 Answers

You could have a look at how it's done for @googlemaps/markerclusterer https://github.com/googlemaps/js-markerclusterer/blob/main/src/algorithms/grid.ts#L113

The structure might differ a bit but the algorithm is rather simple (and does not need multiple layers of filters that could introduce bugs):

  • Loop on the events
    • for each event, check if they are "close" to the center of an existing cluster, if so add it to the cluster, else create a new cluster that only contains your event

This way you get a list of clusters of close events (which might contain only one event) and do whatever you want with them. Then you would need to recompute the clusters based on zoom, if the events are in the viewport...

Related