OpenLayers Feature Styling – How to Style Feature Depending on Property and Display It

featuresjavascriptopenlayers

I have a feature with multiple elements, every element has its own geometry and an ID.

Is possible to change the style of the feature and display the elements of the feature on the map like it's own ID?
For example, I have three elements, a (id = 1), b (id = 1) and c (id = 2), I want to display them on the map with 1 (for a and b) and 2 (for c).
Is possible to do it?

This is my code and the JSON explains what I mean with multiple id:

var bikeStyle = new ol.style.Style({
        image: new ol.style.Circle({
            radius: 15,
            fill: new ol.style.Fill({color: 'rgba(0, 200, 0, 1)'}),
            stroke: new ol.style.Stroke({color: 'green', width: 1})
        })
    });

var map = new ol.Map({
    target: 'map',
    layers: [

       ...

    ],
    
    view: new ol.View({
        center: ol.proj.fromLonLat([11.341868,44.494949]),
        zoom: 14
    })
});


source = new ol.source.Vector();

bike = new ol.layer.Vector({
    title: 'bikes',
    source: source,
    style: bikeStyle,
})

source.addFeatures(
  new ol.format.GeoJSON().readFeatures(bikes, {
    dataProjection: 'EPSG:4326',
    featureProjection: map.getView().getProjection()
  })
);

Where bike in source a json file like:

{
  "type": "FeatureCollection", 
      "features": [{"id": 1, "type": "Feature", "geometry": {"type": "Point", "coordinates": [x,y]}, "properties": {"id": 1, "resnumb": A}}],
      "features": [{"id": 13, "type": "Feature", "geometry": {"type": "Point", "coordinates": [x,y]}, "properties": {"id": 1, "resnumb": B}}],
      "features": [{"id": 2, "type": "Feature", "geometry": {"type": "Point", "coordinates": [x,y]}, "properties": {"id": 2, "resnumb": C}}]
}

As you can see each element has its own id.

Best Answer

To have dynamic feature style where style changes depending on feature properties, you have to use style function. This function receives feature as the first parameter and should return style, which can be created depending on feature properties.

To avoid creating new styles again and again in the function, so called style cache is usually created, where already created styles are stored for use when needed.

In the code below, new style with random circle colors is created for each different id feature property:

function randomColor() {
  var r = Math.floor(Math.random() * 256);
  var g = Math.floor(Math.random() * 256);
  var b = Math.floor(Math.random() * 256);
  var color = [r, g, b];
  
  return(color);
}

var bikeStyleCache = {};
function createBikeStyle(id) {
  var strokeColor = randomColor();
  var fillColor = strokeColor.slice();
  fillColor[3] = 0.2;
  var bikeStyle = new ol.style.Style({
    image: new ol.style.Circle({
      radius: 15,
      stroke: new ol.style.Stroke({
        color: strokeColor,
        width: 2,
      }),
      fill: new ol.style.Fill({
        color: fillColor
      })
    }),
    text: new ol.style.Text({
      text: id.toString(),
      fill: new ol.style.Fill({
        color: 'black',
      })
    })
  });
  bikeStyleCache[id] = bikeStyle;
}

function getBikeStyle(id) {
  if (!bikeStyleCache[id]) {
    createBikeStyle(id);
  }
  return(bikeStyleCache[id]);
}

function styleFunction(feature, resolution) {
  return(getBikeStyle(feature.get('id')));
}

var source = new ol.source.Vector();
var bike = new ol.layer.Vector({
  title: 'bikes',
  source: source,
  style: styleFunction,
});

And by the way, GeoJSON sample from your question would not work correctly, since you define features attribute again and again, so only last assignment would stay. You have to do it once and features have to be in array:

{
  "type": "FeatureCollection",
  "features": [
    {"id": 1, "type": "Feature", "geometry": {"type": "Point", "coordinates": [10.224194550042373, 41.358221559689788]}, "properties": {"id": 1, "resnumb": 'A'}},
    {"id": 13, "type": "Feature", "geometry": {"type": "Point", "coordinates": [11.960078048414047, 40.779593726899229]}, "properties": {"id": 1, "resnumb": 'B'}},
    {"id": 2, "type": "Feature", "geometry": {"type": "Point", "coordinates": [11.519471533536832, 42.425232517404488]}, "properties": {"id": 2, "resnumb": 'C'}}
  ]
};