On a React app that displays maps, I made a side-by-side comparator using the leaflet-side-by-side plugin (I followed the answer to this thread) that works fine on its own.
However, some of the maps aren't free and I want to restrict access to them (and prevent requests for these tiles). For now, I've made it so that the tiles won't display unless you enter the right password. So basically, I need to update the locked TileLayer after it has been rendered. When I use react-leaflet, I just use setUrl to update the TileLayer when the password matches :
const LockedLayer = ({ lockedUrl, attribution }) => {
const pwd = Config.PWD;
const [inputPwd, setInputPwd] = useState(null);
const tileLayerRef = useRef(null);
useEffect(() => {
if (pwd === inputPwd) {
tileLayerRef.current.setUrl(lockedUrl);
}
});
return <TileLayer attribution={attribution} url="" ref={tileLayerRef} />;
};
which works perfectly fine.
But for leaflet-side-by-side, I need to use native Leaflet, which doesn't behave the same. The same code applied to a TileLayer created by L.tileLayer has no effect, even though the URL is correctly updated, the map will not update its content despite the layer changing (because it is inside of a hook, I assume). Like I mentioned, I copy-pasted the code from a thread before adding my own layers, which looks like:
import "leaflet-side-by-side";
...
const Map = () => {
useEffect(() => {
const map = L.map("map").setView([51.505, -0.09], 13);
const osmLayer = L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", { attribution: 'OSM' }).addTo(map);
const lockedLayer = LeafletLockedLayer(
"PROTECTED_URL", { attribution: 'credits'}
).addTo(map);
L.control.sideBySide(lockedLayer, osmLayer).addTo(map);
}, []);
return <div id="map" />;
};
const LeafletLockedLayer = ({ lockedUrl, attribution }) => {
const pwd = Config.PWD;
const [inputPwd, setInputPwd] = useState(null);
const tileLayer = L.tileLayer("", { attribution: attribution });
useEffect(() => {
if (pwd === inputPwd) {
tileLayer.setUrl(lockedUrl);
}
});
return tileLayer;
};
So far I've unsuccessfully tried:
What I'm looking for is either a way to update and redraw the layers in leaflet-side-by-side, another way to restrict access to some layers, or an alternative to the plugin that would allow me to use react-leaflet.
Thanks in advance for any idea!
After trying out different configurations, I think the only way to get the layer to fire its requests again post-update is to create it alongside the map in useEffect
. The LeafletLockedLayer
I wrote cannot be used inside useEffect
(since it uses hooks), but a simple way to get around that is to replace its own useEffect
by a makeshift one with setTimeout
/setInterval
. Although I'd rather not use those, I don't have time to look for a better solution, and the time it takes to read the password is shorter than loading the tiles anyway.
Here's a working LeafletLockedLayer
than can be created inside the same useEffect
as the map like it is meant to:
const LeafletLockedLayer = ({ lockedUrl, attribution }) => {
const storedPwd = Config.layersPwd;
let pwd = null;
const tileLayer = L.tileLayer("", { attribution: attribution });
const interval = setInterval(() => updateLayer(), 100);
const updateLayer = () => {
if (pwd === storedPwd) {
tileLayer.setUrl(lockedUrl);
clearInterval(interval);
}
};
return tileLayer;
};