1

I have a Leaflet map with custom markers.

Recently I added Layer Control so that I can make use of a legend to filter the markers.

I've managed to add the legend however it appears to recreate all the markers on top of my custom ones and filters those instead.

I know I'm doing something wrong in the code but can't figure out where.

How can I filter my custom markers using the legend/layer control ?

Here is my jsfiddle

var markersA = [];
var markersB = [];
var markersC = [];

//Loop through the initial array and add to two different arrays based on the specified variable
for (var i = 0; i < data.length; i++) {
  switch (data[i].Category) {
    case 1:
      markersA.push(L.marker([data[i].lat, data[i].lng]));
      break;
    case 2:
      markersB.push(L.marker([data[i].lat, data[i].lng]));
      break;
    case 3:
      markersC.push(L.marker([data[i].lat, data[i].lng]));
      break;
    default:
      break;
  }
}

//add the groups of markers to layerGroups
var groupA = L.layerGroup(markersA);
var groupB = L.layerGroup(markersB);
var groupC = L.layerGroup(markersC);

const myAPIKey = "**";

var tileLayer = {
  'Filter drop off Points:': L.tileLayer('http://{s}.tile.cloudmade.com/{key}/22677/256/{z}/{x}/{y}.png')
};

const layer = 'https://api.maptiler.com/maps/uk-openzoomstack-night/{z}/{x}/{y}.png?key=tbRG4BpdjpPfpJ5rjwZY'

const layer2 = 'https://api.maptiler.com/maps/voyager/{z}/{x}/{y}.png?key=tbRG4BpdjpPfpJ5rjwZY'

var osm = L.tileLayer(layer)

const map = L.map('map', {
  center: data[data.length - 12],
  zoomControl: true,
  zoom: 17,
  layers: [osm, groupA, groupB, groupC]
});

// 'translate(0,' + (-outerRadius + 7) + ')')

var overlayMaps = {
  "<img src= 'https://api.geoapify.com/v1/icon/?type=awesome&color=green&icon=tick&scaleFactor=2&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a'  height=24>Delivered": groupA,
  "<img src= 'https://api.geoapify.com/v1/icon/?type=awesome&color=gold&icon=tick&scaleFactor=2&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a'  height=24>Left": groupB,
  "<img src= 'https://api.geoapify.com/v1/icon/?type=awesome&color=red&icon=tick&scaleFactor=2&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a'  height=24>Returned": groupC
};
L.control.layers(tileLayer, overlayMaps, {
  collapsed: false,
  position: 'topright'
}).addTo(map);




var mygeojson = {
  type: "FeatureCollection",
  features: [],
};
var waypoints = []
var all_points = []
for (i = 0; i < data.length; i++) {
  var lng = data[i].lng;
  var lat = data[i].lat;
  all_points.push([lng, lat]);
  if (data[i].Category != 0) {
    mygeojson.features.push({
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [data[i].lng, data[i].lat]
      },
      "properties": {
        "Icon": data[i].Icon,
        "Status": data[i].Status,
        "Customer": data[i].Customer,
        "Supplier": data[i].Supplier,
        "Item Size": data[i]["Item Size"],
        "Address": data[i].Address,
        "Customer Order": data[i]["Customer Order"],
        "Notes": data[i].Notes,
        "Instruction": data[i].Instruction

      }
    });
    waypoints.push({
      id: data[i].id,
      lat: data[i].lat,
      lng: data[i].lng
    });
  }
}
//  console.log(mygeojson);
//console.log(all_points);
var polyline = L.polyline(lngLatArrayToLatLng(all_points)).addTo(map);

function lngLatArrayToLatLng(lngLatArray) {
  return lngLatArray.map(lngLatToLatLng);
}

function lngLatToLatLng(lngLat) {
  return [lngLat[1], lngLat[0]];
}

function IconStyle(feature, latlng) {
  switch (feature.properties["Status"]) {
    case "Delivered":
      var deliveredIcon = new L.icon({
        iconUrl: `https://api.geoapify.com/v1/icon/?type=awesome&color=green&icon=tick&scaleFactor=2&apiKey=${myAPIKey}`,
        iconSize: [20, 32], // size of the icon
        iconAnchor: [0, 22], // point of the icon which will correspond to marker's location
        popupAnchor: [-3, -26] // point from which the popup should open relative to the iconAnchor    
      });
      return L.marker(latlng, {
        icon: deliveredIcon
      });
    case "Left":
      var leftIcon = new L.icon({
        iconUrl: `https://api.geoapify.com/v1/icon/?type=awesome&color=gold&icon=tick&scaleFactor=2&apiKey=${myAPIKey}`,

        iconSize: [20, 32], // size of the icon
        iconAnchor: [0, 22], // point of the icon which will correspond to marker's location
        popupAnchor: [-3, -26] // point from which the popup should open relative to the iconAnchor    
      });
      return L.marker(latlng, {
        icon: leftIcon
      });
    case "Returned":
      var returnedIcon = new L.icon({
        iconUrl: `https://api.geoapify.com/v1/icon/?type=awesome&color=red&icon=tick&scaleFactor=2&apiKey=${myAPIKey}`,
        iconSize: [20, 32], // size of the icon
        iconAnchor: [0, 22], // point of the icon which will correspond to marker's location
        popupAnchor: [-3, -26] // point from which the popup should open relative to the iconAnchor    
      });
      return L.marker(latlng, {
        icon: returnedIcon
      });
  }
}
5
  • 2
    Coding question on GIS SE site should include relevant existing code, otherwise it's most likely to be closed as not compliant with the site policy. Please edit your question and add relevant existing code. Question has to be complete in itself and include all relevant code, since outside links tend to get lost in time and also that there is no need to visit other sites to get complete picture of what the problem/question is
    – TomazicM
    Jun 14 at 10:52
  • I’m voting to close this question because it's a cross-post of stackoverflow.com/questions/72615656/… Jun 14 at 11:34
  • It helps if you have an explicit question in your Question.
    – Vince
    Jun 14 at 12:07
  • In your code above you are doing nothing with the mygeojson data.
    – TomazicM
    Jun 14 at 19:05
  • mygeojson data is used to create the custom markers and tooltips but not sure how I can add that to the layer control / legend it created
    – Gangrel
    Jun 14 at 19:58

1 Answer 1

1

Since you are adding your markers to groupA, groupB and groupC layers and also to GeoJSON layer that uses the same data from mygeojson GeoJSON object and all these layers are added to the map, it's normal you will get your markers twice.

Solution to select desired markers from GeoJSON layer with layer control would be to break your GeoJSON layer to three different layers, using filter option to select only layers of desired category for each of those layers.

Fro this you would have to add Category property when creating your GeoJSON obkect:

var mygeojson = {
  type: "FeatureCollection",
  features: [],
};
var waypoints = []
var all_points = []
for (i = 0; i < data.length; i++) {
  var lng = data[i].lng;
  var lat = data[i].lat;
  all_points.push([lng, lat]);
  if (data[i].Category != 0) {
    mygeojson.features.push({
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [data[i].lng, data[i].lat]
      },
      "properties": {
        "Category": data[i].Category,
        "Icon": data[i].Icon,
        "Status": data[i].Status,
        "Customer": data[i].Customer,
        "Supplier": data[i].Supplier,
        "Item Size": data[i]["Item Size"],
        "Address": data[i].Address,
        "Customer Order": data[i]["Customer Order"],
        "Notes": data[i].Notes,
        "Instruction": data[i].Instruction

      }
    });
    waypoints.push({
      id: data[i].id,
      lat: data[i].lat,
      lng: data[i].lng
    });
  }
}

Than you can wrap you GeoJSON layer creation into a function, where one of the parameters is category to filter data only for desired category:

function filteredGeojsonLayer(geoJsonData, category) {
  var PoI = L.geoJson(mygeojson, {
    filter: function(feature) {
      return(feature.properties.Category == category);
    },
    pointToLayer: IconStyle,
    onEachFeature: function(feature, layer) {
      if (feature.properties) {
        var div = document.createElement("div");
        div.className = 'popupCustom';
        var content =
          `<div class="info-window-container info-window-grid">
              <div class="grid-item">
                <h4 class="info-window-title">Customer Name:</h4>
                <div  class="info-window-text">${feature.properties.Customer}</div>
              </div>
              <div class="grid-item">
                <h4 class="info-window-title info-window-img-container">Status:
                   <span class="info-window-status-${feature.properties.Status}">${feature.properties.Status} 
                   </span>
                   <img src="${feature.properties.Icon}" class="info-window-marker" alt="${feature.properties.Address}"/>
                </h4>
              </div>
              <div class="grid-item">
                <h4 class="info-window-title">Supplier:</h4>
                <div  class="info-window-text">${feature.properties.Supplier}</div>
              </div>
              <div class="grid-item">
                <h4 class="info-window-title">Item Size:</h4>
                <div  class="info-window-text">${feature.properties["Item Size"]}</div>
              </div>
              <div class="grid-item">
                <h4 class="info-window-title">Address:</h4>
                <div  class="info-window-text">${feature.properties.Address[0]["Line 1"]}</div>
                <div  class="info-window-text">${feature.properties.Address[0]["Line 2"]}</div>
                <div  class="info-window-text">${feature.properties.Address[0]["Town"]}</div>
                <div  class="info-window-text">${feature.properties.Address[0]["Post Code"]}</div>
              </div>
              <div class="grid-item">
                <h4 class="info-window-title">Instruction:</h4>
                <div  class="info-window-text">${feature.properties.Instruction || "N/A"}</div>
              </div>
               <div class="grid-item">
                <h4 class="info-window-title">Customer Order:</h4>
                <div  class="info-window-text">${feature.properties["Customer Order"]}</div>
               </div>
              <div class="grid-item">
                <h4 class="info-window-title">Delivery Notes:</h4>
                <div  class="info-window-text">${feature.properties.Notes || "N/A"}</div>
              </div>

            </div>`;
        layer.bindPopup(content);
      }
    }
  }).addTo(map);
  return(PoI);
}

Then you can create three different GeoJSON layers, corresponding to the three categories, and use those in layer control:

var overlay1 = filteredGeojsonLayer(mygeojson, 1);
var overlay2 = filteredGeojsonLayer(mygeojson, 2);
var overlay3 = filteredGeojsonLayer(mygeojson, 3);

var overlayMaps = {
  "<img src= 'https://api.geoapify.com/v1/icon/?type=awesome&color=green&icon=tick&scaleFactor=2&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a'  height=24>Delivered": overlay1,
  "<img src= 'https://api.geoapify.com/v1/icon/?type=awesome&color=gold&icon=tick&scaleFactor=2&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a'  height=24>Left": overlay2,
  "<img src= 'https://api.geoapify.com/v1/icon/?type=awesome&color=red&icon=tick&scaleFactor=2&apiKey=6dc7fb95a3b246cfa0f3bcef5ce9ed9a'  height=24>Returned": overlay3
};

L.control.layers(tileLayer, overlayMaps, {
  collapsed: false,
  position: 'topright'
}).addTo(map);

See working JSFiddle: https://jsfiddle.net/TomazicM/ct9pj8n1/

1
  • thanks so much!
    – Gangrel
    Jun 16 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.