Leaflet shapefile plugin doesn’t show the shapefile layer

javascriptleafletleaflet-plugins

I'm trying to use the Leaflet Shapefile plugin (https://github.com/calvinmetcalf/leaflet.shapefile). A demo page also shows the plugin's output (http://calvinmetcalf.github.io/leaflet.shapefile/). I downloaded the js files and organised the HTML shared on the demo page. Then I ran the same page locally on my computer. However, the shapefile layer doesn't become visible whatever I did. Any ideas on what the problem might be? I uploaded the files I'm using to the following link (https://we.tl/t-wpdHCsNDO3). I also attached the HTML file below:

<!doctype html>
<html lang="en">

<head>
    <meta charset='utf-8' />
    
    <title>Preview</title>
    
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />
    <script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
    
    <script src="catiline.js"></script>
    <script src="leaflet.shpfile.js"></script>
    <script src="shp.js"></script>
    
    <link rel="stylesheet" href="gh-pages.css" />
    
    <style>
        html {
            height: 100%
        }

        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #map {
            height: 100%
        }
    </style>
</head>

<body>
    <div class="github-fork-ribbon-wrapper right">
        <div class="github-fork-ribbon">
            <a href="https://github.com/calvinmetcalf/leaflet.shapefile">Fork me on GitHub</a>
        </div>
    </div>
    <div id="map"></div>
    <script>
        var m = L.map('map').setView([42.09618442380296, -71.5045166015625], 8);
        var watercolor = L.tileLayer('http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg', {
            attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> &mdash; Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
        }).addTo(m);

        var shpfile = new L.Shapefile('congress.zip', {
            onEachFeature: function(feature, layer) {
                if (feature.properties) {
                    layer.bindPopup(Object.keys(feature.properties).map(function(k) {
                        return k + ": " + feature.properties[k];
                    }).join("<br />"), {
                        maxHeight: 200
                    });
                }
            }
        });
        shpfile.addTo(m);
        shpfile.once("data:loaded", function() {
            console.log("finished loaded shapefile");
        });
    </script>
</body>

</html>

Best Answer

All modern browsers disable access to local files through AJAX (XMLHttpRequest) protocol for security reasons (see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).

If you don't want to set up local web server and want to use local file system to read your zipped shapefile, this can be done with some trickery, converting content of shapefile to data URL and then bring it in through JS script as JS variable.

To convert shapefile to data URL you can use some online converter like https://dopiaza.org/tools/datauri/index.php. Once you have data URL string, save it to some JS file like shapefile-data.js and assign it to some variable in the file:

var shapefileDataURL = 'data:application/zip;base64,UEsDBBQAAgAIAIN8I0KlIknlmAIAAHwJAAAUAAAAQ09OR1JFU1M ...';

Then you can bring your data in with simple script link:

<script src="data/shapefile-data.js"></script>

File has to be in the same directory as your HTML file or in it's child folder. You can then use it like this:

var shpLayer = new L.Shapefile(shapefileDataURL, ...