Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot set a style for clicked features in vector layer

Tags:

openlayers-3

So in my Openlayers 3 I set a default style , that renders features the first time the layer loads

function styleFunction(feature, resolution) {
    var color = feature.get('color');
    var name = feature.get('name');

    var fill = new ol.style.Fill({
        color: color
    });

    var stroke = new ol.style.Stroke({
        color: "black",
        lineCap: "butt",
        lineJoin: "bevel",
        width:1         
    });

    var text= new ol.style.Text({
        font: '20px Verdana',
        text: name,
        fill: new ol.style.Fill({
            color: [64, 64, 64, 0.5]
        })
    })

    var cStyle = new ol.style.Style({
        fill: fill,
        stroke: stroke,
        text: text
    });

    return [cStyle];
}

When a feature is clicked I want that feature to change its style and the rest to keep the default style above.

This is my attempt to do this

 //add simple click interaction to the map
 var select = new ol.interaction.Select();
 map.addInteraction(select);

//for every clicked feature
 select.on('select', function(e) {
       var name = e.selected[0].get('name');

       //set the clicked style
        var fillClick= new ol.style.Fill({
            color: "black"
         });

        var strokeClick = new ol.style.Stroke({
            color: "white",
            lineCap: "butt",
            lineJoin: "bevel",
            width:3         
        });

        var textClick= new ol.style.Text({
                font: '10px Verdana',
                text: name,
                fill: new ol.style.Fill({
                    color: [64, 64, 64, 1]
                })
            })

        var styleClick = new ol.style.Style({
            stroke: strokeClick,
            fill : fillClick,
            text : textClick
        });



    //set all to default
    for (i in e.selected){
        e.selected[i].setStyle(styleFunction);  
    }

    //reset the first selected to the clicked style
    e.selected[0].setStyle(styleClick);

I dont get any errors on the console, but this wont work. The clicked feature wont return to the default style when I click another one. All the clicked features keep the styleClick.

So, how do I fix this and also, is there a simpler way to do this? I think its a lot of code for this kind of functionality

Thanks

EDIT

I replaced

    for (i in e.selected){
        e.selected[i].setStyle(styleFunction);  
    }

with

    var allfe = sourceVector.getFeatures(); 

    for (i in allfe){
        allfe[i].setStyle(styleFunction);   
    }   

So now all the features will get the style defined in the styleFunction function.

This does not work. I get Uncaught TypeError: feature.get is not a function referring to the first line of the function, var color = feature.get('color'); this one.

I cannot just set a style, I need it to be a function so I can check the geomerty type in the future.

So my two problems,

I dont know how to debug and fix this error

If I have like 500 features, redrawing all of them for every click, will slow the rendering. Is there another solution to this?

Thanks

like image 724
slevin Avatar asked Dec 01 '22 17:12

slevin


1 Answers

Layer and feature style functions are different

When using OpenLayers 3 style functions, you have to note the difference between an ol.FeatureStyleFunction and a ol.style.StyleFunction. They are very similar, since they both should return an array of ol.Styles based on a feature and a resolution. They are, however, not provided with that information in the same way.

When providing a style function to a feature, using it's setStyle method, the function should be an ol.FeatureStyleFunction. An ol.FeatureStyleFunction is called with this referencing the feature, and with the resolution as the only argument.

When providing a style function to a layer, it should be an ol.style.StyleFunction. They are called with two arguments, the feature and the resolution.

This is the cause of your error. You are using an ol.style.StyleFunction as a feature style. Later, when your style function is called, the first argument is the resolution and not the feature that you are expecting.

Solution 1: setStyle(null)

This solution has already been proposed in @jonatas-walker's answer. It works by setting a style on your selected features and removing the style from the unselected ones (instead of setting your style function to the unselected features).

OpenLayers will use the feature's style if it has one, and otherwise use the layer's style. So re-setting the unselected features' style to null will make them use the layer's style function again.

Solution 2: use the style option of your select interaction ol.interaction.Select accepts a style option (an ol.style.StyleFunction), which is used to style the selected features.

Pros: Having one style function for the layer (normal view) and a style function for the select interaction makes the code more readable than mixing feature and layer styles. Also, you don't have to keep track of the events or modify the features.

It could be done similar to this:

var selectedStyleFunction = function(feature, resolution) {
    return [new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: "white",
            lineCap: "butt",
            lineJoin: "bevel",
            width:3         
        }),
        fill : new ol.style.Fill({
            color: "black"
        }),
        text : new ol.style.Text({
            font: '10px Verdana',
            text: feature.get('name'),
            fill: new ol.style.Fill({
                color: [64, 64, 64, 1]
            })
        })
    })];
};
var select = new ol.interaction.Select({
    style: selectedStyleFunction
});
map.addInteraction(select);
like image 147
Alvin Lindstam Avatar answered Dec 23 '22 23:12

Alvin Lindstam