Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layer Switcher and Swipe Tile Sharing Broken with OpenLayers 10.0.0+ #1112

Open
WillieMaddox opened this issue Nov 2, 2024 · 4 comments
Open

Comments

@WillieMaddox
Copy link

I'm working on a project that combines two layer switchers with a swipe control, allowing users to switch map layers independently on the left and right sides. This setup provides flexibility without redundant data usage.

To optimize performance, tile sources are shared between layer switchers. For example, if the left side displays OpenStreetMap (OSM) and the right side is set to Google Maps, switching the right side to OSM won’t trigger additional downloads. The tiles are already cached from the initial download on the left side.

However, since the introduction of the ImageTile base class in OpenLayers version 10.0.0 and later, this tile-sharing functionality no longer works as expected. Before contacting the OpenLayers team, I wanted to ask here if there might be a potential fix or workaround within the ol-ext project.

Below is an index.html and an index.js that should be sufficient to reproduce the issue.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>ol-ext: Swiped Layerswitchers</title>
    <style>
      html, body {
        margin: 0;
        height: 100%;
      }
      .map {
        width: 100%;
        height: 100%;
        background: rgb(229, 227, 223);
      }
      .ol-control.ol-layerswitcher.layerSwitcherLeft {
        left: 0.5em;
        right: auto;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
  </body>
</html>
import 'ol/ol.css';
import 'ol-ext/dist/ol-ext.css'
import Map from 'ol/Map';
import View from 'ol/View';
import { OSM, XYZ } from 'ol/source';
import { Tile as TileLayer } from 'ol/layer';
import LayerGroup from 'ol/layer/Group';
import Swipe from 'ol-ext/control/Swipe';
import LayerSwitcher from 'ol-ext/control/LayerSwitcher';

const sourceOSM = new OSM();
const sourceGoogle = new XYZ({url: 'https://mt{0-3}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}'});

function StaticGroup () {
    return new LayerGroup({
        layers: [
            new TileLayer({
                title: "OSM",
                visible: false,
                baseLayer: true,
                source: sourceOSM,
            }),
            new TileLayer({
                title: 'Google',
                visible: false,
                baseLayer: true,
                source: sourceGoogle,
            }),
        ]
    })
}

let leftgroup = new StaticGroup();
let rightgroup = new StaticGroup();

let map = new Map({
    target: 'map',
    // view: new View({zoom: 16, center: [-12337600, 3783550]}),
    view: new View({ zoom: 5, center: [166326, 5992663] }),
    layers: [leftgroup, rightgroup]
});

let swipe = new Swipe()

function switchleft (layer) {
    let add_layers = [];
    let del_layers = [];
    swipe.layers.forEach( function(l) {
        if (!l.right) {
            add_layers.push(layer);
            del_layers.push(l.layer);
        }
    })
    swipe.removeLayer(del_layers);
    swipe.addLayer(add_layers, false);
}
function switchright (layer) {
    let add_layers = [];
    let del_layers = [];
    swipe.layers.forEach( function(l) {
        if (l.right) {
            add_layers.push(layer);
            del_layers.push(l.layer);
        }
    })
    swipe.removeLayer(del_layers);
    swipe.addLayer(add_layers, true);
}

let layerswitcherleft = new LayerSwitcher({
    reordering: false,
    switcherClass: "layerSwitcherLeft ol-layerswitcher",
    layerGroup: leftgroup,
    onchangeCheck: switchleft
});
map.addControl(layerswitcherleft);

let layerswitcheright = new LayerSwitcher({
    reordering: false,
    switcherClass: "layerSwitcherRight ol-layerswitcher",
    layerGroup: rightgroup,
    onchangeCheck: switchright
});
map.addControl(layerswitcheright);

function initlayerswitcher ({layergroup, is_right, idx = 0} = {}) {
    let layer = layergroup.getLayers().getArray()[idx];
    layer.setVisible(true);
    swipe.addLayer(layer, is_right);
}
initlayerswitcher({layergroup: leftgroup, is_right: false, idx: 0})
initlayerswitcher({layergroup: rightgroup, is_right: true, idx: 1})
map.addControl(swipe);

This package.json works:

{
  "name": "ol-ext: Swiped Layerswitchers",
  "dependencies": {
    "ol": "^9.2.4",
    "ol-ext": "^4.0.24"
  },
}

This one does not:

{
  "name": "ol-ext: Swiped Layerswitchers",
  "dependencies": {
    "ol": "^10.2.1",
    "ol-ext": "^4.0.24"
  },
}
@mike-000
Copy link
Contributor

mike-000 commented Nov 3, 2024

Sources no longer have a cache openlayers/openlayers#16221 which removes the advantage of sharing sources. It affects all source types as XYZ and OSM are not (yet) subclasses of ImageTile.

@Viglino
Copy link
Owner

Viglino commented Nov 3, 2024

No fix or workaround, sorry 😞

@mike-000
Copy link
Contributor

A workaround would be to have a layer switcher option which used layer opacity instead of the visible property to switch the visibility

e.g. in https://openlayers.org/en/latest/examples/bing-maps.html change the code to

for (i = 0, ii = styles.length; i < ii; ++i) {
  layers.push(
    new TileLayer({
      opacity: 0,
      // preload: Infinity,
      source: new BingMaps({
        key: 'Your Bing Maps Key from https://www.bingmapsportal.com/ here',
        imagerySet: styles[i],
        // placeholderTiles: false, // Optional. Prevents showing of BingMaps placeholder tiles
      }),
    }),
  );
}
const map = new Map({
  layers: layers,
  target: 'map',
  view: new View({
    center: [-6655.5402445057125, 6709968.258934638],
    zoom: 13,
  }),
});

const select = document.getElementById('layer-select');
function onChange() {
  const style = select.value;
  for (let i = 0, ii = layers.length; i < ii; ++i) {
    layers[i].setOpacity(styles[i] === style ? 1 : 0);
  }
}

Even without the preload the switch is instant.

@WillieMaddox
Copy link
Author

@mike-000 I am not sure how to implement your workaround in my example above. The swipe control handles which layers are displayed by adding / removing layers based on which layerswitcher is toggled; the left layerswitcher controls which layers are visible on the left side and the right layerswitcher controls which layers are visible on the right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants