Leaflet js - Изо всех сил пытается получить маркеры слиться при взгляде на мир - PullRequest
0 голосов
/ 27 апреля 2020

Я работаю над визуализацией, в которой используется картографическая карта mapbox и маркеры листовки js. В настоящее время я пытаюсь объединить маркеры при уменьшении масштаба на уровне страны. Я попытался прочитать мой код до конца, но не смог найти способ решить эту проблему.

Прилагается мой код для моей карты.

 (function() {

  window.petMap = {
    map: '',
    mapCenter: [36.19109202182454, -95.99853515625001],
    tileUrl: 'https://api.mapbox.com/styles/v1/sourcetop/ck3yaryi60z7z1co7p7ttw4kf/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1Ijoic291cmNldG9wIiwiYSI6ImNrM3lhYXMyazA2ZmczZ3FsbDM0aThhYnIifQ.eyPqNH3WmEFy8D1aw2vn6w',
    mapAttribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors',
    bounds: [],
    zoom: 5,
    zoomLevel: 'country',
    callbackUrl: URL.com
    locationCallbackUrl: URL.com

    dmaJsonUrl: URL.com

    markers: {
      profile: {},
      conditions: {}
    },
    dataLevel: 'profile',

    locationMarkes: {},
    dmaMarkers: [],
    dmaPoly: [],

    progress: 0,
    progressTimer: '',

    initMap: function() {
      this.mapZoomClass();
      this.map = L.map('map', {
        center: this.mapCenter,
        zoom: 5,
        zoomControl: false,
        zoomDelta: 2,
        trackResize: true,
        wheelPxPerZoomLevel: 25,
        scrollEnable: true
      });

      L.control.zoom({
        position: 'bottomright'
      }).addTo(this.map);

      L.tileLayer(this.tileUrl, {
    attribution: this.mapAttribution,
    minZoom: 2,
    maxZoom: 13
  }).addTo(this.map);

  this.getBounds();
  this.getZoomLevel();
  this.mapAction();
},

plotMap: function(dataLevel) {
  this.progressBarInit();
  this.dataLevel = dataLevel;
  this.dataLevelFixer();
  this.requestDataFromServer();
},

requestDataParams: function() {
  return {
    bounds: this.bounds,
    zoom: this.zoom,
    level: this.zoomLevel,
    year: petMapFilters.year,
    animal: Object.keys(window.petMapFilters.animal),
    age: Object.keys(window.petMapFilters.age),
    breeds: Object.keys(window.petMapFilters.breeds),
    ailments: Object.keys(window.petMapFilters.ailments)
  };
},

requestDataFromServer: function() {
  $.ajax({
    url : this.callbackUrl,
    data: this.requestDataParams(),
  })
  .done(function(response) {
    petMap.progressBarReset();
    if(petMap.dataLevel == 'conditions') {
      petMap.dataLevel = 'profile';
      petMap.plotMarkers(response);
      petMap.dataLevel = 'conditions';
    }
    petMap.plotMarkers(response);
  })
  .fail(function(jqXHR, textStatus) {
    console.log('Request failed: ' + textStatus);
  });
},

// Plot markers.
plotMarkers: function(response) {
  this.clearmarkerLayer();

  var color = window.petMapFilters.colors[this.dataLevel];
  if(this.zoomLevel != 'state') {
    this.initClusterMarker(color, this.dataLevel);
  } else {
    this.markers[petMap.dataLevel] = L.featureGroup();
  }

  var markerList = [];
  response.forEach(function(data){
    var count = petMap.getResultCount(data);
    if(data.location != null && count) {
      var icon = L.divIcon({
        html: petMap.getMarkerHtml(count, color)
      });
      var marker = L.marker(
        new L.LatLng(data.location[1], data.location[0]),
        {icon: icon, zIndexOffset: 2000}
      );
      marker.count = count;
      if(petMap.zoomLevel == 'state') {
        marker.on('click', function(e) {
          petMap.map.setView(e.latlng, 1);
        });
        petMap.markers[petMap.dataLevel].addLayer(marker);
      } else {
        markerList.push(marker);
      }
    }
  });

  if(this.zoomLevel != 'state') {
    this.markers[this.dataLevel].addLayers(markerList);
  }
  this.map.addLayer(this.markers[this.dataLevel]);
},

// init cluster markers.
initClusterMarker: function(color, type) {
  this.markers[type] = L.markerClusterGroup({
    chunkedLoading: true,
    spiderfyOnMaxZoom: true,
    showCoverageOnHover: false,
    iconCreateFunction: function(cluster) {
      var markers = cluster.getAllChildMarkers();
      var markerCount = 0;
      markers.forEach(function(m){
        markerCount = markerCount + m.count;
      });
      return new L.DivIcon({
        html: petMap.getMarkerHtml(markerCount, color),
        className: 'marker-type-cluster-' + (petMapFilters.colors.profile == color ? 'profile' : 'condition')
      });
    }
  });
},

clearmarkerLayer: function() {
  if(Object.keys(this.markers.profile).length && this.dataLevel == 'profile') {
    this.markers.profile.clearLayers();
  }

  if(Object.keys(this.markers.conditions).length) {
    this.markers.conditions.clearLayers();
  }
},

/**********************************************************/
plotLocations: function() {
  if(Object.keys(petMapFilters.locationSelected).length) {
    for(var i in petMapFilters.locationSelected) {
      if(typeof this.locationMarkes[i] == 'undefined') {
        this.plotLocation(i);
      }
    }
  }
},

removeLocationMarker: function(id) {
  if(typeof this.locationMarkes[id] != 'undefined' && Object.keys(this.locationMarkes[id]).length) {
    this.locationMarkes[id].clearLayers();
    delete this.locationMarkes[id];
  }
},

plotLocation: function(id) {
  this.progressBarInit();
  $.ajax({
    url: this.locationCallbackUrl,
    data: {
      // bounds: this.bounds,
      collection: id
    }
  })
  .done(function(response) {
    petMap.progressBarReset();
    petMap.plotLocationMarkers(id, response);
  })
  .fail(function(jqXHR, textStatus) {
    console.log('Request failed: ' + textStatus);
  });
},

plotLocationMarkers: function(id, response) {
  if(typeof this.locationMarkes[id] != 'undefined' && Object.keys(this.locationMarkes[id]).length) {
    this.locationMarkes[id].clearLayers();
    this.locationMarkes[id] = [];
  }
  this.initLocationClusterMarker(id);

  var markerList = [];
  response.forEach(function(data){
    if(data.location != null) {
      var marker = L.marker(new L.LatLng(data.location.coordinates[1], data.location.coordinates[0]), {icon: petMap.getLocationIcon(id, 'marker'), zIndexOffset: 1000}).bindPopup(petMap.getLocationPopup(data));
      markerList.push(marker);
    }
  });

  this.locationMarkes[id].addLayers(markerList);
},

initLocationClusterMarker: function(id) {
  this.locationMarkes[id] = L.markerClusterGroup({
    chunkedLoading: true,
    spiderfyOnMaxZoom: true,
    showCoverageOnHover: false,
    iconCreateFunction: function(cluster) {
      return petMap.getLocationIcon(id, 'cluster', cluster.getAllChildMarkers().length);
    }
  });

  this.map.addLayer(this.locationMarkes[id]);
},

getLocationIcon: function(id, type, count) {
  var sizeMap = {
    'shop-marker': [16, 19],
    'shop-cluster': [35, 40],
    'clinic-marker': [18, 17],
    'clinic-cluster': [38, 35],
  };
  var dt = id.split(':');
  var icon = dt[0] == 'shop' ? 'shop-' + type + '.svg' : 'hospital-' + type + '.svg';
  var anchor = dt[0] == 'shop' ? [-1, -10] : [0, -8];
  if(type == 'cluster') {
    return new L.DivIcon({
      html: '<div class="location-marker location-type-' + dt[0] + '" tabindex="0">' + count + '</div>',
      className: 'marker-type-cluster-location'
    });
  } else {
    return L.icon({
      iconUrl: 'images/' + icon,
      iconSize: sizeMap[dt[0] + '-' + type],
      popupAnchor: anchor,
      className: 'location-single-marker'
    });
  }
},

getLocationPopup: function(data) {
  var details = [];
  if(typeof data.street != 'undefined') { details.push(data.street); }
  if(typeof data.city != 'undefined') { details.push(data.city); }
  if(typeof data.state != 'undefined') { details.push(data.state); }
  if(typeof data.contact != 'undefined') { details.push(data.contact); }

  details = details.join('<br/>');
  if(details.length) {
    details = '<div class="location">' + details + '</div>';
  }
  return '<div class="hospital-popup"><div class="color-red">' + data.name + '</div>' + details + '</div>';
},

/**********************************************************/
plotDmaData: function(op) {
  if(op == 'add') {
    if(!Object.keys(this.dmaMarkers).length) {
      this.getDmaData();
    } else {
      this.map.addLayer(this.dmaMarkers);
      this.map.addLayer(this.dmaPoly);
    }
  } else {
    if(Object.keys(this.dmaMarkers).length) {
      this.map.removeLayer(this.dmaMarkers);
      this.map.removeLayer(this.dmaPoly);
    }
  }
},

getDmaData: function() {
  $.getJSON(this.dmaJsonUrl, function(response) {
    petMap.plotDmaMarkers(response);
  });
},

plotDmaMarkers: function(response) {
  this.dmaMarkers = L.featureGroup();
  this.dmaPoly = L.geoJson(response, {
    style: {
      opacity: 0,
      fillOpacity: 0
    },
    onEachFeature: function(feature, layer) {
      var latlng = new L.LatLng(feature.properties.latitude, feature.properties.longitude);
      var icon = petMap.getDmaMarkerIcon(feature.properties);
      var marker = L.marker(latlng, {icon: icon, riseOnHover: true, riseOffset: 3000});
      marker.data = feature.properties;
      marker.layer = layer;
      marker.on('click', function(e) {
        petMapDmaPopup.init(e.target.data);
      });
      marker.on('mouseover', function(e) {
        var layer = e.target.layer;
        layer.setStyle({
            weight: 1,
            color: '#8A8D8F',
            dashArray: '',
            fillOpacity: 0.5
        });

        if(!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
          layer.bringToFront();
        }
      });
      marker.on('mouseout', function(e) {
        petMap.dmaPoly.resetStyle(e.target.layer);
      });
      petMap.dmaMarkers.addLayer(marker);
    }
  });

  this.map.addLayer(this.dmaMarkers);
  this.map.addLayer(this.dmaPoly);
},

getDmaMarkerIcon: function(data) {
  var cluster_classes = [
    'dma-marker-icon',
    'leaflet-marker-icon',
    'leaflet-zoom-animated',
    'leaflet-clickable'
  ];

  return L.divIcon({
    html: '<div class="' + cluster_classes.join(' ') + '" tabindex="0">' + data.dma_name + '</div>'
  });
},

/**********************************************************/
mapAction: function() {
  this.map.on('zoomend dragend',function(e) {
    petMap.getBounds();
    petMap.getZoomLevel();
    petMap.progressBarInit();
    petMap.requestDataFromServer();
  });
},

resetMap: function() {
  this.dataLevel = 'profile';
  this.clearmarkerLayer();

  if(Object.keys(this.locationMarkes).length) {
    for(var id in this.locationMarkes) {
      this.locationMarkes[id].clearLayers();
      delete this.locationMarkes[id];
    }
  }

  this.map.removeLayer(this.dmaMarkers);
  this.map.setView(new L.LatLng(this.mapCenter[0], this.mapCenter[1]), 5);
},

getBounds: function() {
  var bounds = this.map.getBounds();
  this.bounds = {
    tr: {
      lat: bounds.getNorthEast().lat,
      lng: bounds.getNorthEast().lng
    },
    bl: {
      lat: bounds.getSouthWest().lat,
      lng: bounds.getSouthWest().lng
    }
  };
},

getZoomLevel: function() {
  this.zoom = this.map.getZoom();
  this.zoomLevel = 'state';
  if(this.zoom > 6) {
    this.zoomLevel = 'city';
  }
  if(this.zoom > 8) {
    this.zoomLevel = 'zip';
  }

  // dma data.
  if(this.zoom > 6) {
    this.plotDmaData('add');
  } else {
    this.plotDmaData('remove');
  }
},

mapZoomClass: function() {
  L.Map.mergeOptions({
    zoomCss: true
  });

  L.Map.ZoomCSS = L.Handler.extend({
    addHooks: function() {
      this._zoomCSS();
      this._map.on('zoomend', this._zoomCSS, this);
    },
    removeHooks: function() {
      this._map.off('zoomend', this._zoomCSS, this);
    },
    _zoomCSS: function(e) {
      var map = this._map,
          zoom = map.getZoom(),
          container = map.getContainer();
      container.className = container.className.replace( /\smap-zoom-[0-9]{1,2}/g, '' ) + ' map-zoom-' + zoom;
    }
  });
  L.Map.addInitHook('addHandler', 'zoomCss', L.Map.ZoomCSS);
},

/**********************************************************/
progressBarInit: function() {
  clearTimeout(petMap.progressTimer);
  $('.progress-bar .progress').css('width', '0%');
  $('.progress-bar').removeClass('hide');
  this.progressBarProress();
},

progressBarProress: function() {
  this.progressTimer = setTimeout(function() {
    petMap.progress += 0.5;
    $('.progress-bar .progress').css('width', petMap.progress + '%');
    if(petMap.progress != 100) {
      petMap.progressBarProress();
    }
  }, 25);
},

progressBarReset: function() {
  $('.progress-bar').addClass('hide');
  $('.progress-bar .progress').css('width', '0%');
  clearTimeout(petMap.progressTimer);
  petMap.progress = 0;
},

/**********************************************************/
formatCount: function(count) {
  if(count > 1000) {
    count = Math.floor(count / 1000) + 'K' + (count % 1000 !== 0 ? '+' : '');
  }
  return count;
},

getMarkerSize: function(count) {
  size = 30;
  if(count > 100) {
    size = 35;
  }
  if(count > 500) {
    size = 40;
  }
  if(count > 1000) {
    size = 45;
  }
  if(count > 5000) {
    size = 50;
  }
  if(count > 10000) {
    size = 55;
  }
  if(count > 20000) {
    size = 60;
  }
  if(count > 30000) {
    size = 65;
  }
  if(count > 50000) {
    size = 70;
  }
  if(count > 70000) {
    size = 75;
  }
  if(count > 90000) {
    size = 80;
  }
  if(count > 120000) {
    size = 85;
  }
  if(count > 140000) {
    size = 90;
  }
  if(count > 160000) {
    size = 95;
  }
  if(count > 180000) {
    size = 100;
  }
  if(count > 200000) {
    size = 105;
  }
  if(count > 220000) {
    size = 110;
  }

  if(count > 240000) {
    size = 115;
  }

  if(count > 260000) {
    size = 120;
  }

  if(count > 280000) {
    size = 125;
  }

  if(count > 300000) {
    size = 130;
  }

  if(count > 320000) {
    size = 135;
  }

  if(count > 340000) {
    size = 140;
  }

  if(count > 360000) {
    size = 145;
  }

  if(count > 380000) {
    size = 150;
  }

  if(count > 400000) {
    size = 155;
  }

  if(count > 500000) {
    size = 160;
  }

  if(count > 600000) {
    size = 165;
  }

  if(count > 700000) {
    size = 170;
  }

  if(count > 800000) {
    size = 175;
  }

  return size;
},

getMarkerHtml: function(count, color) {
  var size = this.getMarkerSize(count);
  var hsize = (size / 2) - 6;
  var font = count < 1000 ? Math.ceil(size / 3) : Math.ceil(size / 4);
  if(count < 100) {
    font = font + 3;
  }

  var cluster_classes = [
    'map-marker',
    'marker-bg-' + (petMapFilters.colors.profile === color ? 'profile' : 'condition')
  ];

  if(this.zoomLevel !== 'zip') {
    size = size * 1.5;
    if(petMapFilters.colors.profile !== color) {
      hsize = size / 2;
    }
  }

  var cluster_styles = [
    'margin-left: -' + hsize + 'px;',
    'margin-top: -' + hsize + 'px;',
    'width: ' + size + 'px;',
    'height: ' + size + 'px;',
    'font-size: ' + font + 'px;'
  ];

  var div_style = [
    'line-height: ' + (size - (size * 0.3)) + 'px;'
  ];

  count = this.formatCount(count);
  return '<div class="' + cluster_classes.join(' ') + '" tabindex="0" style="' + cluster_styles.join(' ') + '"><div style="' + div_style.join(' ') + '">' + count + '</div></div>';
},

getResultCount: function(data) {
  if(this.dataLevel === 'conditions') {
    if(typeof data.total_ailments != 'undefined') {
          return data.total_ailments;
        }
        return 0;
      }

      return data.total;
    },

    dataLevelFixer: function() {
      this.dataLevel = 'profile';
      if(Object.keys(petMapFilters.ailments).length) {
        this.dataLevel = 'conditions';
      }
    }

  };

})(jQuery);

Image of my output

Ответы [ 2 ]

1 голос
/ 28 апреля 2020

Если я правильно понимаю, вы строите 1 MarkerClusterGroup на каждый штат. Но при самом низком уровне масштабирования вы бы хотели, чтобы отображался только один кластер, чтобы он показывал счет для всей страны?

В этом случае, к сожалению, нет встроенного способа для достижения этой цели. Однако простой обходной путь - это просто создать дополнительную группу MarkerClusterGroup, в которую вы также добавите все свои отдельные маркеры и добавите их на карту только при самом низком уровне масштабирования, в то время как вы удаляете все другие MCG состояния. Используйте событие map "zoomend", чтобы прочитать масштаб карты и добавить / удалить соответствующие группы слоев. Если MCG на уровне вашей страны не полностью кластеризована, просто увеличьте параметр maxClusterRadius .

0 голосов
/ 06 мая 2020

Разделы маркеров печати мешали мне инициализировать маркеры из-за исходного уровня масштабирования.

plotMarkers: function(response) {
  this.clearmarkerLayer();

  var color = window.petMapFilters.colors[this.dataLevel];
    this.initClusterMarker(color, this.dataLevel);

Работало нормально.

...