1

I am creating a Leaflet map from GeoJSON data. I want to make some Leaflet markers to be a different shape based on if the geoJSON has images (this is indicated under feature.properties, along with some other HTML for a pop-up). The default shape is an L.circleMarker and I want the relevant markers to turn into rectangles. Unfortunately L.circleMarker does not have a default option to change the shape.

I tried this plugin https://github.com/masajid390/BeautifyMarker but it was really buggy for my purposes. The code just seemed to be applying CSS to markers anyway. See this issue: https://github.com/masajid390/BeautifyMarker/issues/20 where it was suggested to style markers into rectangles with iconStyle : 'border-radius:0!important'. Returning to ordinary Leaflet, if I could get at the CSS for an individual circle I could easily change it by setting the CSS:

  .rectangle_marker {
    border-radius: 0
  }

One approach would be to add a class to the relevant markers, and then style them. I am already applying some conditional styling as follows, directly setting the L.circleMarker's options:

function style(feature) {
  options =  drawOptions(feature.properties);
  // mark items that have images
  if (feature.properties.First) {
    options.radius = 11
    options.width = 3
  }
  
  // mark filter options with different colors
  if (feature.properties.Filter) {
    if (feature.properties.Filter.toUpperCase() === "BEFORE") {
      options.fillColor = "#29A7B3"
    } else if (feature.properties.Filter.toUpperCase() === "DURING") {
      options.fillColor = "#DC4A35"
    } else if (feature.properties.Filter.toUpperCase() === "AFTER") {
      options.fillColor = "#215E57"
    }
  }
  return options
}

(in turn, drawOptions looks like this:)

  function drawOptions(props) {
    return {
      radius: 7,
      color: "black",
      width: 1,
      opacity: 1,
      fillColor: "#784889",
      fillOpacity: 1
    }
  }

I tried this way: How to use the addClass method in leaflet maker?, but it doesn't work because L.circleMarker doesn't have a built in option like className to set a class. How to add a marker with a specific class to a layer or layergroup? would not work for the same reason.

Tried the following code to indirectly add a class based on How do you add a class to a Leaflet marker?:

function pointToLayer(feature, latlng) {
  const marker = L.circleMarker(latlng, drawOptions(feature.properties));
  if (check_images(feature.properties)) {
    marker._path.classList.add("rectangle_marker")
  }
  return marker
}

But it doesn't work, because the marker has no attribute _path before being added to the map.

Since I am adding the entire layer to the map, I could conceivably pull out the relevant markers in between creating the geoJSON and adding them to the map, but I'm not sure how:

  window.geojson = L.geoJSON(json, {
    onEachFeature: onEachFeature,
    pointToLayer: pointToLayer,
    style: style
  });
 //What would go here?

  window.geojson.addTo(window.map);

Is there any other approach I could take to get some of my L.circleMarkers to appear as squares?

William Dewey
  • 13
  • 1
  • 3

1 Answers1

0

I gave up and used divIcons instead. You can add classNames and add css instead.

function markerOptions(props) {
  //default options
  const options =  {
    iconSize: [15, 15],
    //mark the center of the icon
    iconAnchor: [7, 7],

  }
  // if location has images, make marker a rectangle
  if (check_images(props)) {
    options.className = "marker-images"
  }
  
  // mark filter options with different colors
  if (props.Filter) {
    if (props.Filter.toUpperCase() === "BEFORE") {
      options.className += " options-before"
    } else if (props.Filter.toUpperCase() === "DURING") {
      options.className += " options-during"
    } else if (props.Filter.toUpperCase() === "AFTER") {
      options.className += " options-after"
    }
  }
  //enlarge first location
  if (props.First) {
    options.className += " first"
    options.iconSize = [21, 21]
    options.iconAnchor = [10, 10]
  }
  
  return options
}
function pointToLayer(feature, latlng) {
  return L.marker(latlng, { icon: L.divIcon(markerOptions(feature.properties)) });
}

Then in your css file you can change the border, border-radius, background-color, and other options that are not built in to L.divIcon.

William Dewey
  • 13
  • 1
  • 3