0

I'm in trouble with Leaflet nowadays beacuse of my poor Javascript/Jquery knowledge :)

I want to change my Leaflet ImageLayer url by uploading a photo to server. I searched a lot to upload image file to WCF service and I did it. But I cannot give my ImageLayer that URL.

<div>
    <button id="btnBrowse" class="button primary on-right" onclick="openFileOption();">Browse</button>
</div>
<div class="custom-file">
    <input type="file" id="file" style="display:none" onchange="uploadPhoto();" />
</div>
<div id="base" style="display:none"></div>

<div id="map" style="width: 100%; height: 400px"></div>  

Above my HTML file content. And I 'm loading my map once in LoadMap() function. Then changing it's URL in ChangeMap() function.

<script>
    var mapLoadCount = 0;
    var map;
    var overlay;
    var bounds;

    function LoadMap() {
        mapLoadCount = mapLoadCount + 1;
        if (mapLoadCount == 1) {
            map = L.map('map', {
                minZoom: 1,
                maxZoom: 5,
                center: [0, 0],
                zoom: 3,
                crs: L.CRS.Simple
            }).setView([50.4333, 30.5167], 3);

            var w = 1526,
            h = 626,
            url = '';

            var southWest = map.unproject([0, h], map.getMaxZoom() - 1);
            var northEast = map.unproject([w, 0], map.getMaxZoom() - 1);
            bounds = new L.LatLngBounds(southWest, northEast);

            overlay = L.imageOverlay(url, bounds);
            overlay.addTo(map);

            map.setMaxBounds(bounds);
        }
    }

    function onMapClick(e) {
        var newPosition = e.latlng;

        if (imageBounds.contains(newPosition)) {
            var newMarker = L.marker(newPosition).addTo(map);
        }

    }

    function ChangeMap(_url) {

        LoadMap();

        overlay.setUrl(_url)
        var popup = L.popup();

        var imageBounds = bounds;

        function onMapClick(e) {
            var newPosition = e.latlng;

            if (imageBounds.contains(newPosition)) {
                var newMarker = L.marker(newPosition).addTo(map);
            }
        }

        newMarkerGroup = new L.LayerGroup();
        map.on('click', onMapClick);

        map.on('drag', function () {
            map.panInsideBounds(bounds, { animate: false });
        });
    }
</script>

In code below I'm reading image file and load it to server then calling ChangeMap() function with url of my image on server.

<script type="text/javascript">
    function readImage(input) {
        if (input.files && input.files[0]) {
            var FR = new FileReader();
            FR.onload = function (e) {
                $('#base').text(e.target.result);
            };
            FR.readAsDataURL(input.files[0]);
        }
    }

    function openFileOption() {
        document.getElementById("file").click();
    }

    function uploadPhoto() {

        var path = document.getElementById("file").value;
        var fileExtension = path.substring(path.lastIndexOf(".") + 1, path.length);

        var file = document.getElementById("file");

        readImage(file);

        var check = function () {
            if ($('#base').text() != "") {
                var base64 = $('#base').text();
                UploadToServer(base64); 
            }
            else {
                setTimeout(check, 1000); // check again in a second
            }
        }
        check();

        if (result == "true") 
        {
          ChangeMap("..\\" + imageUrl);
        }
    }

    var result;
    var dataArr;
    var imageUrl;

    function UploadToServer(base64) {

        var url = $(location).attr('href');
        var baseURL = url.substring(0, url.indexOf('/', 8));
        var path = document.getElementById('file').value;
        var fileName = path.substring(path.lastIndexOf("\\") + 1, path.length);
        fileName = fileName.substring(0, fileName.lastIndexOf("."));
        var fileExtension = path.substring(path.lastIndexOf(".") + 1, path.length);
        var jData = {};
        jData.base64 = base64;
        jData.fileName = fileName;
        jData.fileExtension = fileExtension;
        var Path = 'http://localhost/ImageUploaderService/FileUploader.svc/UploadPhotoToServer';
        var imagePath = "localhost\\ImageUploaderService\\";
        $.ajax({
            type: "POST",
            url: Path,
            data: JSON.stringify(jData),
            dataType: 'json',
            async: false,
            contentType: "application/json",
            beforeSend: function () {

            },
            complete: function () {

            },
            success: function (data) {
                if (data.indexOf('|')!= -1)
                {
                    dataArr = data.split('|');
                    result = dataArr[0];
                    imageUrl = dataArr[1];
                }
                if (result != "true") {
                    alert('Error while loading image to server. ' + data);
                }
            },
            error: function (responseData, textStatus, errorThrown) {

                alert('Error while loading image to server. ' + responseData + textStatus + errorThrown);
            }
        });
    }
</script>

My actual problem is about loading an image after first time. When I load an image for the first time my code is loading image to server and getting the path of image and loading it to my map. But in second time doesn't change my image of Leaflet imagelayer. After that when I load third time it loads second image to map. In fourth it loads third image and so on.

I'm in doubt about FileReader.onload event. Because when I debug my code I saw my code is going onload event of FileReader after I call ChangeMap() function. I cannot understand what is happening in my code :)

EDIT : Here is a working version of my code > http://jsfiddle.net/v905xhre/

1 Answers1

0

You seem to be confused about asynchronous processes. Your UploadToServer function creates an AJAX (firt "A" is for Asynchronous) request, and assigns data to your result and imageUrl variables only once that request successfully completes.

Once the AJAX is sent to your server (but did not complete yet), your script continues executing, so the next lines will test for result. On first upload, it is undefined. On 2nd upload, it is true because it is never reset to false, and your image URL will be changed to what is currently in imageUrl, i.e. the URL of the first upload, because 2nd upload is still processing on server. And so on.

    check(); // calls UploadToServer

    if (result == "true") // executes while the AJAX is sent
    {
      ChangeMap("..\\" + imageUrl);
    }

You could very simply move the call to ChangeMap into the success callback of your AJAX request.

Edit: as for how to properly use asynchronous / AJAX processes, you can also refer to How to return the response from an asynchronous call?

ghybs
  • 47,565
  • 6
  • 74
  • 99
  • Thanks for your reply first @ghybs . But your suggestion not changed anything. I loaded my fake scenerio with a fake REST API call here http://jsfiddle.net/v905xhre/ . You could see how my code is loading previous image after first time. –  Nov 03 '15 at 22:12
  • Thank you for the jsfiddle! It looks like you did the same mistake for your `check` function. Since it is outside of `readImage` callback, you had to implement a polling system to wait for the image to be populated. But you do not clear the image once read the first time, so the next time it will be populated already by the previous image, and you display that one while the new one has not been written yet. Simply move your `check` into the success callback of `readImage`. Demo: http://jsfiddle.net/v905xhre/1/. Once you will be used to asynchronous tasks and callbacks, that will be obvious. – ghybs Nov 04 '15 at 17:30
  • Thanks a lot for your detailed explanation @ghybs :) Today before you write this comment I read about asynchronous call from your link above. So I tried to change my code with callbacks and learned some usefull information about this subject. So this is my code before seeing your correction http://jsfiddle.net/ku4zmb4c/ . I learned a lot things about callbacks in javascript because of you. Thanks again. –  Nov 04 '15 at 20:07
  • I am glad I could help, and I am proud you took this opportunity to increase your knowledge! Keep up the good work! :-) – ghybs Nov 04 '15 at 20:36