Berkay Beyaz

Berkay Beyaz


February 2017
M T W T F S S
« Dec    
 12345
6789101112
13141516171819
20212223242526
2728  

Categories


Javascript ile Client-Side Marker Clustering

berkaybeyazberkaybeyaz

Merhabalar bugun cok ilginc bir konu ile karsinizdayim react native ile client side marker clustering normalde bu tur isler icin server-side clustering kullanilir ve sonra api servisleri ile longitude ve latitude bilgileri gonderilerek ona gore response ile marker olusturulurdu.

Client side mantiginda ise butun datasetler toplanir ve sonra bu datalar bir format haline getirilip longitude ve latitude regionlarina gore clusterlanir. Bu bize ekstra performans ve server-side isimizi arttirarak yuksek bir performans sagliyor.

Hersey’den once projemize baslamadan once supercluster‘i tanitacagim bu npm paket’i genel olarak main cluster islemimizi kolaylastiran bir arac kisacasi ve bizim icin kendi icinde memory’yi handle edebiliyor kendi web sitesinde yazdigina gore 400K marker’i 52fps altina dusmeden clusterlara ayirabiliyor

Ornek bir GIF

Tabikide bu gifdeki performans etkileyici ki react nativedede ayni oranda bir performans var. Kisa bir ornek ile Hurriyet Emlak, IBB Trafik ve diger turevi uygulamarda hepimiz karsilasmisizdir ki o flash etikisi ve acilip kapanma olayi hepimizin canini sikmistir. Genel olarak size maddeler halinde supercluster‘in calisma mantigindan bahsedecegim

  1. Ilk once bir region belirlenir
  2. Sonra belirledigimiz configrationlara gore (radius, nodeSize, maxZoom)
  3. Sonra radius’a gore clusterlar hazirlanir ve bunu hazirlamak icin kdbush kullanilir
  4. Sonra clusterlar yaratilir

Not: supercluster GeoJson’i baz alarak cluster islemini gerceklestiriyor bknz.

  1. Ilk once cluster setimizi olusturduk
       _createCluster(data) {
      const index = supercluster({
      radius: 60, // Clusterlarin sikligini ve genisligini belirtiyor
      maxZoom: 15, // Clusterlarin kacinci zoom level'a kadar acilacagina kadar veriyor max: 16
      nodeSize: 128, // Clusterlarin yarattigi agaclari memoryde tutmamiz icin belirlenen bir deger default:64
    });
    index.load(data.features);
    return index;
  1. Datalarimizi GeoJson formatina cevirmemiz lazim bunun icin datalari mapleyecegiz
    _convertPoints(data) {
    const results = {
      type: 'MapCollection',
      features: [],
    };
    data.map((value, key) => {
      array = {
        type: 'Map',
        properties: { // Properties dizisi bizim kendi alanimiz yani markerlari render ederken ihtiyacimiz olacak verileri tutmamizi saglar
          id: value.id,
          name: value.name,
          lat_x: value.lat,
          long_x: value.long,
        },
        geometry: {
          type: 'Point',
          coordinates: [
            value.long,
            value.lat,
          ],
        },
      };
      results.features.push(array);
    });
    return results;
  }
  1. Simdi sira kullanan kisinin ekrandaki bulundugu konuma gore zoomLevel’ini almakta

Aslinda burada yaptigimiz islem biraz karmasik gozuke bilir ama bir temele dayaniyor Math.log(360 / angle ) yapmamiz bizim app veya browserdaki haritanin dunyasinin pixel genisligini bizim bulundugumuz boylam deltasina bolerek bunun logaritmasini aliyor ve buradan donen degeri tekrar n tabaninda logaritma 2 ye bolarak bizi sabit bir degere yakinlastiriyor ve round ilede bu degeri yuvarliyoruz eger daha fazla ogrenmek isterseniz

Stackoverflow
Google Groups

    _getZoomLevel(region = this.state.region) {
      const angle = region.longitudeDelta;
      const level = Math.round(Math.log(360 / angle) / Math.LN2);
      return level;
    }
  1. Simdi sira geldi markerlarimizin kordinatlarimizi olusturmakda

Burada uygulayacagimiz yontem bbox array yani kisaca [westLng, southLat, eastLng, northLat] ama bu verecegimiz lat ve long degerlerini normal belirli bir degerde vermemeliyiz yoksa kendi icinde gruplama yapamamaz

Variables
padding = 0.5
longitude - (longitudeDelta * (0.5 + padding)
latitude - (latitudeDelta * (0.5 + padding)
longitude + (longitudeDelta * (0.5 + padding)
latitude + (latitudeDelta * (0.5 + padding)

Regionlar ayarlandiktan sonra bizim sadece cluster markerlari supercluster’in icinden cekmemiz gerek bunun icinde yine clusterlarin yakinlik dereceleri icin _getZoomLevel’i referans aliyoruz

_createRegions() {
    const padding = 0;
    const markers = this.state.clusters.getClusters([
      this.state.region.longitude - (this.state.region.longitudeDelta * (0.5 + padding)),
      this.state.region.latitude - (this.state.region.latitudeDelta * (0.5 + padding)),
      this.state.region.longitude + (this.state.region.longitudeDelta * (0.5 + padding)),
      this.state.region.latitude + (this.state.region.latitudeDelta * (0.5 + padding)),
    ], this._getZoomLevel());
    return markers.map(marker => this.renderMarkers(marker));
  }

Ve bundan sonra geri kalan sadece sizin markerlari renderlamaniz suan tam performansli bir map clustering yapmis olduk. Bu yontem ile ayni sekilde react native ve react ilede clustering yapabilirsiniz

Diger yazilarda gorusuruz 😄