4
votes

I have an issue in where I need to change the map layer ( the displayed map tiles) in my web application.

I have this in my HTML

<div id="map"></div>

<select onchange="changeMap()">
                <option value="BingSat">Bing Sat</option>
                <option value="BingRoad">Bing Road</option>
                <option value="OSM">OSM</option>
                <option value="MapquestSat">Mapquest Sat</option>
                <option value="MapQuestRoad">MapQuest Road</option>
</select> 

and this is what I have in my JavaScript so far

$(document).ready(function() {    
  map = new ol.Map({
    logo:'false',
    target: 'map',
    layers: [
        new ol.layer.Group({
            'title': 'Base maps',
            layers: [
                new ol.layer.Tile({
                    title: 'Water color',
                    type: 'base',
                    visible: false,
                    source: new ol.source.Stamen({
                        layer: 'watercolor'
                    })
                }),
                new ol.layer.Tile({
                    title: 'OSM',
                    type: 'base',
                    visible: true,
                    source: new ol.source.OSM()
                }),
                new ol.layer.Tile({
                    title: 'MapQuest Satellite',
                    type: 'base',
                    visible: false,
                    source: new ol.source.MapQuest({layer: 'sat'})
                }),

                 new ol.layer.Tile({
                    title: 'MapQuest OSM',
                    type: 'base',
                    visible: false,
                    source: new ol.source.MapQuest({layer: 'osm'})
                 }),
                  new ol.layer.Tile({
                      title: 'Bing Maps aerial',
                      type: 'base',
                      visible: false,
                      source: new ol.source.BingMaps({
                          imagerySet: 'AerialWithLabels',
                          key: '123'
                      })
                  }),
                     new ol.layer.Tile({
                         title: 'Bing Maps road',
                         type: 'base',
                         visible: false,
                         source: new ol.source.BingMaps({
                             imagerySet: 'Road',
                             key: '123'
                         })
                     })
            ]
        }),
    ],

    view: new ol.View({
        center: ol.proj.transform([17.813988, 43.342019], 'EPSG:4326', 'EPSG:3857'),
        zoom: 3
    })
});

}

function changeMap() {
  //grab the selected ID
 //change the map according to the selected ID

}

What would I need to do in order to change the displayed map? I have looked into https://github.com/walkermatt/ol3-layerswitcherdescription]1 but I cannot incorporate it entirely into my project because I need the dropdown list inside a toggable sidebar. I tried editing his code so it would add the generated HTML inside my sidebar but it did not work.

Is there a simpler way of changing the displayed map?

3

3 Answers

4
votes

You need different layer groups. I do it this way:

var layersOSM = new ol.layer.Group({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM()
        })
    ]
});

var layersMQ = new ol.layer.Group({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.MapQuest({layer: 'osm'})
        })
    ]
});

function setMapType(newType) {
    if(newType == 'OSM') {
        map.setLayerGroup(layersOSM);
    } else if (newType == 'MAPQUEST_OSM') {
        map.setLayerGroup(layersMQ);
    }
}

where setMapTypeis a function that I call with the necessary string attribute when I want to change the style. mapis my ol.Map variable.

You might arrange the layer groups in an array, and access them by name as you did already with the layers instead of the if/else construct I used. But I have only 2 different layer groups.

0
votes

not directly an answer, but might be helpful for you or others:

to change the layer by using the name of the visible layer use:

var group = map.getLayerGroup();
var layers = group.getLayers();
var element = layers.item(0);
var name = element.get('name');

Here a JSfiddle to see what I mean.

0
votes

I'm working on something similar using Bootstrap. This isn't "simpler", but it should be along the lines of what you're looking for.

So first in the HTML, I have this within my right sidebar for the basemaps:

...

<div class="panel panel-default">
    <div class="panel-heading">
        <h4 class="panel-title">
        <a data-toggle="collapse" href="#basemap-choice">
            <i class="fa fa-list-alt"></i>
            Basemaps
        </a>

        </h4>
    </div>
    <div id="basemap-choice" class="panel-collapse collapse in">
        <div class="panel-body" id="basemaps">

        </div>
        <div id="baseopacity">
            <label>Opacity</label>
            <input id="baseopslider" type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="100"/>

        </div>                
    </div>
</div>

Under the div where id=basemaps is where I dynamically add my basemap radio buttons.

I declared my basemaps in a similar fashion yours with type: 'base'. Once I've completed the initializing the map and layers, I call a javascript function to add the layers to the sidebar panel and also bind a radio button change event so the basemap changes to what's selected:

function initBaseLayersList() {
    // get all the map layers
    var layers = map.getLayers().getArray();
    // array to hold the basemap layers
    var baseLayers = new Array();

    // loop through the layers and save
    // the ones with type = 'base'
    for (var i=0; i<layers.length; i++) {
        var lyrprop = layers[i].getProperties();
        if(lyrprop.type =='base') {   
            baseLayers.push(layers[i]);
        }
    }
    /* now that the basemap layers are separated, create appropriate HTML
       for each layer's radio button which will be appended to the sidebar panel
       body div */
    $.each(baseLayers, function(index) {
        var basecontent = '';
        var lyrprop = this.getProperties();
        basecontent += '<div class="input-group" id="radio-basemap-'+index+'">';
        // first basemap in the list is selected, others are not
        if(index==0) {
            basecontent += '<span class="input-group-addon"><input type="radio" name="radio-basemap" checked="checked">'+lyrprop.title+'</span>';
        }
        else {
            basecontent += '<span class="input-group-addon"><input type="radio" name="radio-basemap">'+lyrprop.title+'</span>'; 
        }
        basecontent += '</div>';

        $('#basemaps').append($(basecontent));

    });
    /* lastly, bind the radio button group to the change event making the 
       selected basemap visible and hiding the one deselected
    */

    $('#basemaps').bind( "change", function(event) {
        var newbase = $('input[name=radio-basemap]:checked');
        var btntext = newbase[0].nextSibling.nodeValue;

        for (var i=0; i<baseLayers.length;i++) {
            var lyrprop = baseLayers[i].getProperties();
            if (lyrprop.title == btntext) {

                baseLayers[i].setVisible(true);

                var baseslider = $('#baseopslider').slider();
                var baseopacity =  baseslider.slider('getValue')/100; 
                baseLayers[i].setOpacity(baseopacity);
            }
            else {
                baseLayers[i].setVisible(false);
            }
        }

    });
}

As my code indicates, I also have a Bootstrap compatible slider which can adjust the basemap opacity.

If you can use what I've written, you should be able to modify it for a dropdown list in the sidebar vs using radio buttons. As I had developed a page previously using jQuery mobile with radio buttons for basemap selection, I just adapted that code for Bootstrap and OpenLayers 3. Just for info, OL3 version is 3.14.1, Bootstrap is 3.3.6, jQuery is 1.11.3.