5

I have a GeoJSON object with ~1000 polygons and a number of numeric attributes on each polygon. I want to be able to style the polygons based on these attributes using dynamically calculated class breaks. I already have a method for calculating the class breaks.

I can create style functions for the polygon layer if I know the class breaks ahead of time, eg:

var bg_style = function(feature, resolution){
    var medinc = feature.get('medinc');
    if (medinc<36000) {
        fillColor='#ffffcc';
    }
    else if (medinc>=36000 && medinc<62000){
        fillColor='#c2e699';
    }
    else if (medinc>=62000 && medinc<92000){
        fillColor='#78c679';
    }
    else if (medinc>=92000 && medinc<140000){
        fillColor='#31a354';
    }
    else if (medinc>=140000){
        fillColor='#006837';
    }
    style = new ol.style.Style({
    fill: new ol.style.Fill({
      color: fillColor
    }),
    stroke: new ol.style.Stroke({
      color: [0,0,0,1],
      width: 0.5
    })
  });
    return style;
};

but if I don't know the class breaks ahead of time (they depend on the data), I'm at a bit of a loss as to how to use the dynamically calculated breaks in the style function.

It seems like if I want to use variables for the class max/mins & color hex codes, they're out of scope since the style function is not taking any arguments beyond (feature, resolution). I could possibly attach them to the data as additional attributes, but this seems sleazy and creates a few thousand pieces of redundant information.

Basically what I want to do is replace the min/max and hex color for each range in the code snippet above with the class breaks generated at run time. Also no guarantee the number of classes is fixed. Any suggestions???

1
  • I'm starting to lean towards attaching fillColor as a property of the data object at run time. But it feels like there should be a more elegant way. Commented Jun 29, 2017 at 9:26

3 Answers 3

2

Here's an outline of one solution:

  1. Load your data into a vector layer
  2. Iterate over the features in that layer to determine your breaks
  3. Update the style function for your layer, taking advantage of javascript's bind() function to set a context for the style function

Here's a link to bind(). This method will let you make the class breaks available to the style function without making it a global variable.

1
  • @John Bryant did you ever figure out using this bind() approach? Long time ago now!
    – staf
    Commented Jan 11, 2022 at 12:50
1

You can construct the break values in a global array. It should be a 2D array having three values per row: min value, max value and color code. You can add rows (class break) as you want. Then, in the function, you loop over this array and assign the found color.

//Declare as global
var breaks_color = [
  [0, 36000,'#ffffcc'],
  [36000 , 62000,'#c2e699'],
  [62000 , 92000,'#78c679'],
  [140000,999999999,'#006837']
];



var bg_style = function(feature, resolution){
    var medinc = feature.get('medinc');

    //Iterate through the class break array
    for(var i = 0; i < breaks_color.length; i++) {
        if (medinc>=breaks_color[i][0] && medinc<breaks_color[i][1]){
            fillColor=breaks_color[i][2]
        }
    }

    style = new ol.style.Style({
    fill: new ol.style.Fill({
      color: fillColor
    }),
    stroke: new ol.style.Stroke({
      color: [0,0,0,1],
      width: 0.5
    })
  });
    return style;
};
1

You could have a look at the geostats library, which certainly appears to support the most useful classifications (equal interval, quantiles, jenks and others) and will calculate an array of break points.

It should be fairly easy to extract the feature values and match them using that array, in a way similar to the answer from @JGH. I've not tried this myself though.

1
  • Thanks, I am in fact using the geostats library (very nice!) for calculating the class breaks. The problem is more around creating a style based on these breaks at run time. Commented Jul 9, 2017 at 23:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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