Adding custom styles to GeoJSON MVLayers

42 views
Skip to first unread message

sdc50

unread,
Jul 26, 2016, 4:02:53 PM7/26/16
to Tethys Platform
I'm adding a GeoJSON layer to a MapView Gizmo, and I would like to add a custom style to the layer. The OpenLayers api has a `style` option in the layer_options for a vector layer, but it requires an ol.style.Style which in turn requires other ol objects as parameters. Is there a way to pass in a dictionary through the layer_options parameter of the MVLayer object so that the corresponding ol objects will be created, or is there some other way I'm supposed to approach this?

Note: I've successfully been able to change the style in the legend, but this has no effect on the styles in the map.

swainn

unread,
Jul 27, 2016, 10:18:02 AM7/27/16
to Tethys Platform
I encountered a similar challenge when implementing MVLayer, so if you look at that code, you can see how I dealt with it. Basically, to create a layer, you need one of the ol.layer (e.g. ol.layer.Vector, ol.layer.Image) classes and an ol.source layer (e.g. ol.source.Vector, ol.source.StaticImage) and they all vary depending on the type of layer you are doing. The MVLayer has an argument called "source" which is just the name of the source class to use. I found a way to instantiate a class from a string on the JavaScript side of things. All the constructors for open layers classes take a JavaScript objects. There is another argument of MVLayer called "options" which just takes a dictionary, which is then converted to a JavaScript object and passed into the constructor of the "source" class specified. The layer class can be derived from the type of source object selected, so that is handled automagically, though there is a "layer_options" argument to MVLayer that takes a dictionary  and passes that into the layer class when it is instantiated. This does what I needed it to do for MVLayer, but it would be better if we could generalize it so that we could instantiate any open layers class, perhaps using a dictionary structure like so:

{
 "ol_class": "ol.layer.Vector",
 "options": { ... }
}

Then we just need to recursively parse through the structure and instantiate any objects with a "ol_class" property.

Joseph Gutenson

unread,
Feb 9, 2017, 4:24:23 PM2/9/17
to Tethys Platform
Hey Nathan,

So with the "layer_options", you can specify a new ol.style.Style for MVLayer method?

Thanks,
Joseph

sdc50

unread,
Feb 10, 2017, 10:02:34 AM2/10/17
to tethysp...@googlegroups.com
Joseph,

It is currently not possible to pass the layer styles to the map gizmo through Python. Nathan was proposing a way to that we could generalize the way that layer_options is handled so that it could handle making open layers objects, but that has not been added yet. As far as I know that only way to change the style of Vector layers is through the JavaScript API. For my app I don't load any layers in with the gizmo. I just pass the layer information (including a color for the style) to the page and have a JavaScript function to load the layers, similar to this:

map = TETHYS_MAP_VIEW.getMap();

var
load_map_layer = function(layer_info) {
var name = layer_info.name;
    var source_url = layer_info.source_url;
    var color = layer_info.color;

   
var layer_options = {'name': name};

   
var geoJSONFormat = new ol.format.GeoJSON();
   
var layer_source = new ol.source.Vector({
        format: geoJSONFormat,
        url
: source_url,
        projection
: 'EPSG:3857',
   
});

    layer_options
.source = layer_source;

     
var fill_color = get_fill_color(color);
     
var fill = new ol.style.Fill({
         color
: fill_color
     
});
     
var stroke = new ol.style.Stroke({
         color
: color,
         width
: 3
     });
     
var styles = [
       
new ol.style.Style({
          image
: new ol.style.Circle({
            fill
: fill,
            stroke
: stroke,
            radius
: 5
          }),
          fill
: fill,
          stroke
: stroke
         
})
     
];

    layer_options
.style = styles;

   
// a vector layer to render the source
    var layer = new ol.layer.Vector(layer_options);

   
// add vector layer to the map
    map.addLayer(layer);
}

map_layer_information
.forEach(load_map_layer);


sdc50

unread,
Feb 10, 2017, 10:13:39 AM2/10/17
to Tethys Platform
It's probably worth noting that the map_layer_information is a list of dictionaries (each dictionary contains the information for one layer), and I pass it to the template through the context as JSON:

context = {'map_layer_information': json.dumps(map_layer_information)}

In my template I use a <script> tag to make the layers available to the javascript:

<script>
 
var map_layer_information = {% autoescape off %}{{ map_layer_information }}{% endautoescape %};
</script>

Note: this script tag must be above where you load in the JavaScript file with the function from above.


alansnow21

unread,
Feb 10, 2017, 3:18:29 PM2/10/17
to Tethys Platform
//Here is an alternative loading method if you already have the data in your JavaScript

var geojson_data; //this is your data in GeoJSON format
var geoJSONFormat = new ol.format.GeoJSON();
var features = geoJSONFormat.readFeatures(geojson_data, {featureProjection: 'EPSG:3857'});
var layer_source = new ol.source.Vector({
                                                            format: geoJSONFormat,
                                                            features: features,
                                                            });

Joseph Gutenson

unread,
Feb 10, 2017, 4:53:12 PM2/10/17
to Tethys Platform
Alan and Scott,

Thanks!  A combination of your suggestions worked.  The hard question is who should be given the best answer designation :-).

-Joseph
Reply all
Reply to author
Forward
0 new messages