Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a fixed rectangle layer on top of basemap with Leaflet

I have managed to add a layer on top of the base map and it looks like this: I have made this rectangle by direct style modifying with jQuery - width, height and overflow:hidden. I am not sure it's a correct way to do this, please advise if there are better ways.

What I need to do is when I pan the map by mouse dragging, I want the top rectangle layer stay in the same place but content to be changed respectively so that this rectangle would look like a mask on top of the basemap. As I see, panning in Leaflet is being applied by

-webkit-transform: translate3d(185px, 178px, 0) (I am in Chrome) So setting top: 0 and left: 0 doesn't help and the rectangle moves with the map on panning like it's sticked to the map.

I am sure somebody dealt with the same task so please advise me.

UPDATE: I have added a fiddle that illustrates my problem better:

Rectangle top layer

like image 993
Sergei Basharov Avatar asked Oct 05 '22 20:10

Sergei Basharov


1 Answers

Suggestion #1

You could create a clip mask and change its rect in the opposite direction of your panning..

Something like http://jsfiddle.net/gaby/dgWZk/23/

var overlay = {
    top: 50,
    left: 50,
    width: 200,
    height: 200
}

map.on('move', repositionMask) ;

map.fire('move');


function repositionMask() {
    var po = map.getPixelOrigin(),
        pb = map.getPixelBounds(),
        offset = map.getPixelOrigin().subtract(map.getPixelBounds().min);

    $(layer02._container).css({
        clip: 'rect(' + (overlay.top - offset.y) + 'px,' + (overlay.left + overlay.width - offset.x) + 'px,' + (overlay.top + overlay.height - offset.y) + 'px,' + (overlay.left - offset.x) + 'px)'
    });
}

A problem is that the leaflet methods do not expose the animation variables when panning with inertia, and so we cannot mimic that yet.. so i have disabled the inertia of the map..

Also an issue when zooming in/out is that during the animation the mask zooms in/out as well (but gets fixed once the animation is completed, or you can set zoomAnimation:false as well)


Suggestion #2

An alternate solution is to create a second map and overlay/synchronize it

something like http://jsfiddle.net/gaby/dgWZk/24/

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

with

#container {
    position:relative;
    height:500px;
}
#map {
    height: 500px;
    position:absolute;
    top:0;
    left:0;
    right:0;
    bottom:0;
}
#overlay {
    width: 200px;
    height: 200px;
    position:absolute;
    top:50%;
    left:50%;
    margin-left:-200px;
    margin-top:-200px;
    outline:1px solid green;
    pointer-events:none;
}

and

var map = new L.map('map',{
    inertia:false
}).setView([51.505, -0.09], 13);
var overlay = new L.map('overlay', {
    zoomControl: false,
    inertia: false,
    keyboard: false,
    dragging: false,
    scrollWheelZoom: false,
    attributionControl:false,
    zoomAnimation:false
}).setView([51.505, -0.09], 13);
var layer01 = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);


var layer02 = L.tileLayer('http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg').addTo(overlay);


map.on('move', function () {
    var offset = overlay._getNewTopLeftPoint(map.getCenter()).subtract(overlay._getTopLeftPoint()).subtract([100,100]);
    overlay.fire('movestart');
    overlay._rawPanBy(offset);
    overlay.fire('move');
    overlay.fire('moveend');
}).on('zoomend', function () {
    overlay.setView(map.getCenter(), map.getZoom(), true);
    map.fire('move');
});

$(window).resize(function () {
    overlay.setView(map.getCenter(), map.getZoom());
    map.fire('move');
});
map.fire('move');
like image 166
Gabriele Petrioli Avatar answered Oct 10 '22 02:10

Gabriele Petrioli