Выберите несколько фильтров, отображать только те маркеры, которые имеют общие характеристики - PullRequest
0 голосов
/ 01 мая 2020

У меня есть листовка с картой, уже работающая. В настоящее время у меня есть несколько фильтров-флажков (почти 40 на двух картах): пользователь может выбрать несколько маркеров одновременно. Фильтры представляют «специальности», и когда я нажимаю на фильтр, он показывает мне больницы, в которых есть эта специальность. Таким образом, на карте у меня могут быть кластеры, которые показывают больницу с несколькими специальностями, и отдельные маркеры, которые показывают разные больницы с одной специальностью.

  • Если пользователь нажимает на фильтр A, он отображает, например, 5 маркеров с функцией A.
  • Если пользователь нажимает на фильтр B, он отображает 5 маркеров с функцией B.
  • А когда пользователь одновременно нажимает на фильтры A и B, он отображает A + B, поэтому 10 маркеров, с отдельными маркерами и кластерными маркерами.

Что я пытаюсь сделать:

Каждый отдельный чекбокс должен отображаться соответствующие маркеры, НО, как только я отмечаю несколько флажков одновременно, я хочу отображать только маркеры (больница), где я могу найти соответствующие функции. Например, если я нажму на фильтры A и B вместе, я хотел бы видеть только больницы, в которых есть специальности A и B, и скрыть маркер только с одной функцией.

Поскольку я уже закодировал все свои функции, Я хочу избежать перестройки новых функций Geo JSON. Я пытался, но он дублирует маркеры.

Я ищу al oop вот так (конечно, это не работает):

$('#filters input').on('click', function(){// if click on checkbox
    var ID = $(this).attr("id");//I can get the checkbox IDs here, which correspond to the feature name

if ($('#filters input:checked').length >=2 ){ // as soon as there are more than one checkbox checked    
    var checkboxes = $("#filters input:checked");
        for (var i = 0; i < checkboxes.length; i++) {//for all checked checkboxes
            if(feature[i].geometry.coordinates == feature[i].geometry.coordinates){//if the markers have same coordinates
                return layer.feature.properties.Examen; // show me those markers
            }else{
                return false;// hide other markers
            }        
     }
}
})

Я думаю, что у меня уже есть все необходимое информация со следующим кодом, но я не знаю, как объединить это, чтобы получить то, что мне нужно ...

Вот пример одной функции:

{
                "type": "Feature",
                "properties": {
                    "Examen": "iduronate",
                    "Prelevement": "DBS ou Buvard 1 tâche de sang (+ 1 contrôle) ou Sang total EDTA 5 ml (Leucocytes)",
                    "Envoi": "Envoi rapide à température ambiante",
                    "Laboratoire": "Secteur des Enzymopathies UM-BEP-DBTP-IBP",
                    "Chu": "CHU de Grenoble-Alpes",
                    "Adresse": "CS 10217",
                    "Cp": "38043 Grenoble Cedex 9",
                    "Professeur": "Dr Vergnaud Sabrina",
                    "Tel": "Tel : 04 76 76 54 83 ou 04 76 76 59 05",
                    "Fax": "Fax : 04 76 76 56 08",
                    "Mail": "svergnaud@chu-grenoble.fr",

                    "Url": "http://biologie.chu-grenoble.fr/",
                    "Mode": "Buvard"
                },
                "geometry": {

                    "type": "Point",
                    "coordinates": [5.7423258, 45.2015191]
                }
            }

Чтобы добавить это маркеры "iduronate": я нажимаю на флажок с идентификатором "iduronate". Если снять флажок, он скрывает мои маркеры.

$("#iduronate").click(function() {
        if (this.checked) {

            iduronate.addTo(clusterade);
        } else {
            clusterade.removeLayer(iduronate);

        }
    });

Добавление маркера на карту, отображение пользовательского значка и отображение данных

var iduronate = L.geoJson(examenData, {
        filter: function(feature, layer) {
            return feature.properties.Examen == "iduronate";
        },
        onEachFeature: onEachFeature2,
        pointToLayer: function(feature, latlng) {

            return L.marker(latlng, {
                icon: iduronateIcon
            })
        }
    })

И наконец пример моего фильтра

<div>
   <input type="checkbox" class="gaucher" id="iduronate" name="EnzymeDef_mps1[]">
   <label for="iduronate">Iduronate sulfatase </label>
<div>

I извините, я пытался опубликовать свой код здесь, но это слишком долго для "тела" .. Поэтому я сделал codepen , чтобы показать его вживую. Спасибо за вашу помощь !!

1 Ответ

2 голосов
/ 05 мая 2020

Давайте предположим упрощенную версию вашего набора данных, например, Geo JSON FeatureCollection, содержащую точки для клиник / отделений в больницах, где две (или более) клиники, относящиеся к одной и той же больнице, занимают одну и ту же позицию:

let clinics = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "clinic": "cardio", "phone": "11 22 33 44 55" },
      "geometry": {
         "type": "Point", "coordinates": [5.74, 45.20]
      }
    },
    {
      "type": "Feature",
      "properties": { "clinic": "trauma", "phone": "66 77 88 99 00" },
      "geometry": {
         "type": "Point", "coordinates": [5.74, 45.20]
      }
    },
    {
      "type": "Feature",
      "properties": { "clinic": "neuro", "phone": "77 66 55 44 33" },
      "geometry": {
         "type": "Point", "coordinates": [6.12, 43.88]
      }
    } 
  ]
};

Мой подход заключается в том, чтобы вручную l oop через указанный Geo JSON FeatureCollection, индексировать точечные объекты на основе их координат и объединять их свойства в массив, например:

let clinicsByPosition = {};

for (let clinic of clinics.features) {
  // Let the index be the string representation of the coordinates array;
  // this is probably inefficient, but will suffice.
  // Note there are no sanity checks performed here (e.g. checking geometry type)
  let idx = clinic.geometry.coordinates.toString();

  // Does clinicsByPosition already have something in that index?
  if (clinicsByPosition[idx] === undefined) {
    // Create a new feature in that index
    // Initialize the properties of that new feature to an array with
    // one element, the properties of the clinic, and same geometry
    // than the clinic.
    clinicsByPosition[idx] = { 
      type: "Feature", 
      geometry: clinic.geometry, 
      properties: [clinic.properties]
    }
  } else {
    // Add the properties of the clinic to the already existing indexed
    // feature
    clinicsByPosition[idx].properties.push(clinic.properties);
  }
}

// Second pass: convert the "clinicsByPosition" data structure 
// into a GeoJSON FeatureCollection
let hospitals = {
  type:'FeatureCollection',
  features: []
}

for (let indexedClinicSet of Object.values(clinicsByPosition)) {
  hospitals.features.push(indexedClinicSet)
}

После этого преобразования агрегированный набор данных будет выглядеть следующим образом:

let hospitals = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [5.74, 45.2] },
      properties: [
        { clinic: "cardio", phone: "11 22 33 44 55" },
        { clinic: "trauma", phone: "66 77 88 99 00" },
      ],
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [6.12, 43.88] },
      properties: [{ clinic: "neuro", phone: "77 66 55 44 33" }],
    },
  ],
};

Давайте поместим это в Leaflet с несколькими всплывающими подсказками:

var hospitals = L.geoJson(hospitalsData,{
    onEachFeature: function(feat, marker) {
        // For this example, let the contents of the popup of a hospital marker
        // to be a concatenation of the data for all clinics in that hospital
        marker.bindPopup(feat.properties.map(function(clinicData){
            return clinicData.clinic + " - tlf " + clinicData.phone
        }).join("<br>"))
    }
}).addTo(map);

A рабочий пример с что выглядит не так уж и плохо:

popup of an aggregated data point

Теперь должно быть ясно, что в каждом наборе клиник есть только одна функция по тем же координатам.

Теперь фильтрацию можно выполнять (ИМХО) разумным способом. L oop через маркеры больницы в экземпляре L.GeoJSON и l oop через свойства каждого связанного объекта, чтобы увидеть, выполняется ли условие видимости для любого его компонентов, например:

function recalculateHospitalVisibility(){
    var cardioVisible = document.getElementById('cardio').checked;
    var traumaVisible = document.getElementById('trauma').checked;
    var neuroVisible = document.getElementById('neuro').checked;

    hospitals.eachLayer(function (marker) {
        // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
        if (
            marker.feature.properties.some(function (clinic) {
                return (
                    (clinic.clinic === "cardio" && cardioVisible) ||
                    (clinic.clinic === "trauma" && traumaVisible) ||
                    (clinic.clinic === "neuro" && neuroVisible)
                );
            })
        ) {
            marker.addTo(map);
        } else {
            marker.remove();
        }
    });
}

Рабочий пример здесь . Даже если код может выглядеть немного запутанным, пример данных упрощен (так что мой немедицинский мозг может работать с ним лучше), использование итераторов и структур данных немного тяжело, и возможна оптимизация, это должно помочь вам на трассе.

...