Search code examples
javascriptleafletjcrop

Why jquery-jcrop is destroying my Leaflet map when I use the destroy() function?


I've created a very simple functional example with jcrop that creates a square on an image:

$('#container').Jcrop({
    onSelect: function(c){
        alert(JSON.stringify(c));
        this.destroy()
    }
})
<meta charset="UTF-8">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.15/css/jquery.Jcrop.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.15/js/jquery.Jcrop.js"></script>

<img src="https://d3o1694hluedf9.cloudfront.net/market-750.jpg" id="container">

In this example, the function this.destroy() works as I expect, it destroys the shadow layer that jcrop creates on my image. So far, everything is fine. However, when I try to do the same thing with leaflet, it doesn't work at all. Here is what I've tried:

var mymap = L.map('container', {
    center:[-23.553670644165493, -46.648217439651496],
    zoom:18,
    maxZoom:19,
    zoomControl:false,
    attributionControl:false
});         
var lyrOSRHOT = L.tileLayer.provider('OpenStreetMap.HOT');
mymap.addLayer(lyrOSRHOT);

$('#container').Jcrop({
    onSelect: function(c){
        alert(JSON.stringify(c));
        this.destroy()
    }   
})
#container{
    height: 100%;
    position: absolute;
    z-index: 0;
}
<meta charset="UTF-8">

<!-- Leaflet -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet-src.min.js" integrity="sha512-XQr+/1RXvYozXiwrumwtu3lqQmVwZ8nkLUrC/mc3HBHw4Imh++RXjwtLQFuOz3i65j9CSfKt50x6w/uUY2ovOQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.12.0/leaflet-providers.min.js" integrity="sha512-LixflAm9c0/qONbz9F1Ept+QJ6QBpb7wUlPuyv1EHloTVgwSK8j3yMV3elnElGQcv7Y5QTFlF/FqyeE/N4LnKQ==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" />

<!-- jQUERY JCROP-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.15/css/jquery.Jcrop.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.15/js/jquery.Jcrop.js"></script>

<div id="container" style="height:100vh; width: 100vw"></div>

I followed the same logic from my first sample, but after selecting a part of the map, the function destroy() is also destroying the Leaflet map (that doesn't happen when it's an image). Does anyone know what could be happening? Could it be a conflict that jcrop has with Leaflet and what I'm trying to do will not be possible without modifying the libraries?


Solution

  • I ended up solving it with a workaround that creates a different div element that uses the same space that the Leaflet map is using... The solution is the following:

    var mymap = L.map('container', {
        center:[-23.553670644165493, -46.648217439651496],
        zoom:18,
        maxZoom:19,
        zoomControl:false,
        attributionControl:false,
        renderer: L.canvas()
    });         
    var lyrOSRHOT = L.tileLayer.provider('OpenStreetMap.HOT');
    mymap.addLayer(lyrOSRHOT);
    
    const id = "aux-container"
    createFakeMap(id)
    $('#'+id).Jcrop({
        onSelect: function(c){
            alert(JSON.stringify(c));
            this.destroy()
        }   
    }) 
    
    // auxiliary function
    function createFakeMap(id){
        const div = document.body.appendChild(document.createElement('div'));
        document.body.appendChild(div);
        div.setAttribute("id", id);
        div.style.height = '100vh';
        div.style.width = '100vw';
    }
    <meta charset="UTF-8">
    
    <!-- Leaflet -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet-src.min.js" integrity="sha512-XQr+/1RXvYozXiwrumwtu3lqQmVwZ8nkLUrC/mc3HBHw4Imh++RXjwtLQFuOz3i65j9CSfKt50x6w/uUY2ovOQ==" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.12.0/leaflet-providers.min.js" integrity="sha512-LixflAm9c0/qONbz9F1Ept+QJ6QBpb7wUlPuyv1EHloTVgwSK8j3yMV3elnElGQcv7Y5QTFlF/FqyeE/N4LnKQ==" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" />
    
    <!-- jQUERY JCROP-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.15/css/jquery.Jcrop.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.15/js/jquery.Jcrop.js"></script>
    
    <div id="container" style="height:100vh; width: 100vw; position: absolute; z-index:1"></div>

    I've created the div element using Javascript instead of HTML because the destroy function is going to destroy this element all the times that I execute it. With Javascript, I can create it again dynamically when I need it, while not destroying my map and its state.