传单:防止标记被拖到地图容器之外

leaflet : Prevent marker to be dragged outside the map container

请考虑以下代码http://jsfiddle.net/franckl/311bcbc8/

var southWest = L.latLng(-90, -180),
    northEast = L.latLng(90, 180);
var bounds = L.latLngBounds(southWest, northEast);

var map = L.map('map', {
    minZoom: 2,
    zoomControl: false,
    attributionControl: false,
    maxBounds: bounds
});

// Using cartoDB basemap
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
    minZoom: 2,
    subdomains: 'abcd',
    detectRetina: true,
    attribution: ''
}).addTo(map);

map.fitBounds(bounds);

var newMarker0 = L.marker(map.getCenter(), {
    icon: new L.Icon.Default(),
    zIndexOffset: 10000,
    draggable: true
});

newMarker0.addTo(map);

html

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

css

body {
    margin:0;
    padding:0;
}
#map {
    position:absolute;
    top:0;
    bottom:0;
    width:300px;
}

#mycontainer {
    top: 10px;
    width: 600px;
    height: 250px;
    position: relative;
}

如果向右拖动标记,它会离开地图的可见区域。 如何防止用户将标记拖到地图外?

谢谢!

回答我自己的问题以防对任何人有帮助。 我们检测地图容器大小,并通过将其 lat/lng 坐标转换为容器点 (map.containerPointToLatLng(markerContainerPosition))

来检查标记是否超出可见区域

作为奖励,此代码在用户移动地图时将标记留在相对于地图容器的相同位置。它确保标记永远不会超出可见区域(即使在缩放时)

var southWest = L.latLng(-90, -180),
    northEast = L.latLng(90, 180);
var bounds = L.latLngBounds(southWest, northEast);

var map = L.map('map', {
    minZoom: 2,
    zoomControl: false,
    attributionControl: false,
    maxBounds: bounds
});

// Using cartoDB basemap
L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
    minZoom: 2,
    subdomains: 'abcd',
    detectRetina: true,
    attribution: ''
}).addTo(map);

map.fitBounds(bounds);

var newMarker0 = L.marker(map.getCenter(), {
    icon: new L.Icon.Default(),
    zIndexOffset: 10000,
    draggable: true
});

newMarker0.addTo(map);

var mapSize = map.getSize();
var markerContainerPosition = map.latLngToContainerPoint(newMarker0.getLatLng());

function mapMove() {
    newMarker0.setLatLng(map.containerPointToLatLng(markerContainerPosition));
}

function markerDrag(e) {
    var mTempContainerPos = map.latLngToContainerPoint(newMarker0.getLatLng());
    var newPos;

    if (mTempContainerPos.x < 20) {
        if (mTempContainerPos.y < 45) {
            newPos = L.point(20, 45);
        } else if (mTempContainerPos.y > (mapSize.y - 20)) {
            newPos = L.point(20, mapSize.y - 20);
        } else {
            newPos = L.point(20, mTempContainerPos.y);
        }
    } else if (mTempContainerPos.x > mapSize.x - 20) {
        if (mTempContainerPos.y < 45) {
            newPos = L.point(mapSize.x - 20, 45);
        } else if (mTempContainerPos.y > (mapSize.y - 20)) {
            newPos = L.point(mapSize.x - 20, mapSize.y - 20);
        } else {
            newPos = L.point(mapSize.x - 20, mTempContainerPos.y);
        }
    } else {
        if (mTempContainerPos.y < 45) {
            newPos = L.point(mTempContainerPos.x, 45);
        } else if (mTempContainerPos.y > (mapSize.y - 20)) {
            newPos = L.point(mTempContainerPos.x, mapSize.y - 20);
        }
    }

    if (newPos) {
        markerContainerPosition = newPos;
        newMarker0.setLatLng(map.containerPointToLatLng(newPos));
    } else {
        markerContainerPosition = mTempContainerPos;
    }
}

map.on('move', mapMove);
newMarker0.on('drag', markerDrag); 

一个代码稍微更通用的解决方案,适合拖动标记而不是地图,但是 @Franckl 的派生:

onMarkerDrag: function (event) {

    // keep dragged marker within map bounds

    var containerPoint = this.map.latLngToContainerPoint(event.target.getLatLng()),
        clampX = null,
        clampY = null,
        MARKER_MARGIN = 10;

    if (containerPoint.x - MARKER_MARGIN < 0) {
        clampX = MARKER_MARGIN;
    } else if (containerPoint.x + MARKER_MARGIN > this.mapContainerBounds.width) {
        clampX = this.mapContainerBounds.width - MARKER_MARGIN;
    }

    if (containerPoint.y - MARKER_MARGIN < 0) {
        clampY = MARKER_MARGIN;
    } else if (containerPoint.y + MARKER_MARGIN > this.mapContainerBounds.height) {
        clampY = this.mapContainerBounds.height - MARKER_MARGIN;
    }

    if (clampX !== null || clampY !== null) {
        if (clampX !== null) { containerPoint.x = clampX; }
        if (clampY !== null) { containerPoint.y = clampY; }
        marker.setLatLng(this.map.containerPointToLatLng(containerPoint));
    }

},

我在地图初始化时导出 this.mapContainerBounds 一次,而不是每次触发拖动处理程序时(我的地图不会改变大小),如下所示:

this.mapContainerBounds = mapDOMNode.getBoundingClientRect();