Search code examples
openlayersopenlayers-3

OpenLayers Feature Style zIndex inside geometry function


This (silly) picture summarizes the issue I'm having:

enter image description here

These are rendered in a vector layer.

Below these shields is a line string that I render once as-is (i.e. as a line), and on top of it I also render it using a style that has a geometry function defined. In that function, I return a ol.geom.MultiPoint containing the coordinates where I want shields to be added alongside the line.

My above demonstration is silly, I know (i.e. in my real use case, the gap between the shields is way bigger, so I know I won't have any collision).

The thing is, I'm aware that there's normally a way to avoid this kind of behaviour with the zIndex property of the ol.style.Style, i.e. if each feature has its own style defining a different zIndex, then each shield+text would be correctly rendered with text below overlapping shields. But, this can't work with a geometry method, as the same style is used multiple times for the same feature to render it multiple times.

Like I said, since I'll define a big enough gap to avoid collisions anyway I don't really need to figure a way to fix this issue, but I'm curious if there is one, for my future self and other people that would like to know.


Solution

  • Each point on a multipoint can be given its own style. Take this OpenLayers example http://openlayers.org/en/v4.6.5/examples/polygon-styles.html If you replace the styles array with this function each point on the multipoints can be given a different radius and different shade of yellow. It also works for zIndex, as can be seen where the first and last coordinates of the polygons coincide.

    function styles(feature) {
    
      var multipoint = new ol.geom.MultiPoint(feature.getGeometry().getCoordinates()[0]);
    
      var styles = [
    
        new ol.style.Style({
          stroke: new ol.style.Stroke({
            color: 'blue',
            width: 3
          }),
          fill: new ol.style.Fill({
            color: 'rgba(0, 0, 255, 0.1)'
          })
        })
    
      ];
    
      multipoint.getCoordinates().forEach(function(coordinates, index) {
    
        var shade = (index+1)*50;
        var radius = (index+1)*5;
        var zIndex = 10-index;
        styles.push(new ol.style.Style({
          zIndex: zIndex,
          image: new ol.style.Circle({
            radius: radius,
            fill: new ol.style.Fill({
              color: 'rgba(' + shade + ',' + shade + ', 0, 1)'
            })
          }),
          geometry: new ol.geom.Point(coordinates)
    
        }));
    
      });
    
      return styles;
    }