Search code examples
javascripthtmlopenlayersgeoserver

How can I overwrite existing map instead of adding a new one below (OpenLayers)?


I am trying to build a web map with a number of layers that can be toggled on and off. Initially the map gets drawn without any issues, but when I try to toggle off any layer, a new map is added below the existing one (instead of replacing it).

When I toggle off a layer, a javascript refresh() function is called. This function needs to rebuild the list of layers to draw and then call again the function that builds the map. I was hoping this would just replace the existing, but instead a new map gets added below.

...
...
<script type="text/javascript" src="ol.js"></script>        

<script defer="defer" type="text/javascript">

    function onLOAD()
    {
        var my_layers = 'layer_1,     \
                         layer_2,     \
                         layer_3,     \
                         ...'
        init(my_layers);
    }


    function init(my_layers){

        //The bounding box of Lund:lund_address_point
        var extent = [13.1267,55.6770,13.2601,55.7597];

        //Initial view
        var view = new ol.View({
                   center: ol.proj.transform([13.192927, 55.708944], 'EPSG:4326', 'EPSG:3857'),
                   zoom: 13
                   });              

        //The source for the layers
        var wmsSource = new ol.source.ImageWMS({
                        url: 'http://localhost:8080/geoserver/Test/wms',
                        params: {
                                 'LAYERS': my_layers
                                },
                        serverType: 'geoserver'
                        });             
                        
        //OpenStreetMap background and my_layers
        var layers = [
                      new ol.layer.Tile({
                          source: new ol.source.OSM()
                          }),
                      new ol.layer.Image({
                         source: wmsSource
                          })
                      ];
        
        //Bind the map object to our "map" div and add some extra functionality
        var map = new ol.Map({
                  layers: layers,
                  controls: ol.control.defaults({
                            attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
                                 collapsible: false
                          })
                  }).extend([
                        //Extra functionality of the map
                        //Control for displaying coordinates
                        new ol.control.MousePosition({
                             coordinateFormat: ol.coordinate.createStringXY(4),
                             projection: 'EPSG:4326',
                             className: 'custom-mouse-position',
                             target: document.getElementById('location'),
                             undefinedHTML: '&nbsp;'
                        }),
                        //Control for displaying a scale line
                        new ol.control.ScaleLine({
                            target: document.getElementById('scale-line')
                        }),
                        //Control for zooming to a defined extent
                        new ol.control.ZoomToExtent({
                            extent: ol.proj.transform(extent, 'EPSG:4326', 'EPSG:3857')
                        })
                  ]),
                  target: 'map',
                  view: view
        });

    }

    
    function refresh(){
      my_layers='';
      if (layer_1.checked) my_layers = my_layers + "layer_1,";
      if (layer_2.checked) my_layers = my_layers + "layer_2,";
      if (layer_3.checked) my_layers = my_layers + "layer_3,";
      ...  
      if (my_layers.length > 1){
        my_layers = my_layers.substring(0,my_layers.length-1);
      }
      init(my_layers);
    }           
    
</script>
</head>     



<body onload="onLOAD()">

<div>
    <br><input type="checkbox" id="layer_1" value="layer_1" checked="checked" onClick="refresh()">Layer_1
    <br><input type="checkbox" id="layer_2" value="layer_2" checked="checked" onClick="refresh()">Layer_2
    <br><input type="checkbox" id="layer_3" value="layer_3" checked="checked" onClick="refresh()">Layer_3
    ...
    ...
</div>

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

<div id="wrapper">
    <div id="location"></div>
    <br>
    <div id="scale-line" class="scale-line"></div>
</div>

...
...

Solution

  • To cleanly remove the old map you need to call map.setTarget(null) on the previous Map object.

    But in your case it might be better to only create a single map and update the layers' visibility. This way the map / view states like loaded tiles, center and zoom are remembered.

    <div>
        <br><input type="checkbox" id="input-osm" value="osm" checked="checked">OSM
        <br><input type="checkbox" id="input-image" value="image" checked="checked">Image
    </div>
    

    Declare the map and layers variables outside the init function so it can be accessed from the refresh function.

    var map, layers;
    

    Store your layers in an object and assign to declared layers variable to be able to reference them by name and initialize them with correct visibility:

    layers = {
        osm: ol.layer.Tile({
            source: new ol.source.OSM(),
            visible: document.getElementById('input-osm').checked,
        }),
        image: new ol.layer.Image({
            source: wmsSource
            visible: document.getElementById('input-image').checked,
        })
    };
    

    Assign map with all layers to previously declared variable:

    map = new ol.Map({
        layers: Object.values(layers),
        ...
    

    On user input layers' visibility should be changed according to the checkbox:

    function refresh(checkbox) {
        layers[checkbox.value].setVisible(checkbox.checked);
    }
    document.getElementById('input-osm').addEventListener('change', refresh);
    document.getElementById('input-image').addEventListener('change', refresh);
    

    Best of luck.