I am very new to web development and creating maps using Leaflet. Currently I developed a website that has an interactive map based off this tutorial. The map eventually loads and works but it is very very slow. I would like to speed up this map loading and I was thinking I would break up the US map into 50 states and have an input where people would select a state and only that specific states data would load. I was thinking I would break up the US GeoJSON file into 50 files and have each one called based on a user input. I know how to break up the file already but can someone point me in the direction of how to use an input to load a specific GeoJSON file?

Edit The reason why I want to separate by state is because the unit of analysis is on the ZIP code level. Having an analysis this granular makes the entire U.S map ~200mb. Using the plugin in the comments would work if I wanted to highlight just the state border. My GeoJSON file is on the ZIP code level so using get.Bounds will get the bounds of each ZIP and not the state. Having the User pick the state data will hopefully help with the speed.

Here is the map code:

<div class="content-section middle toppad" > 
<h3>Interactive Maps</h3>
The interactive heatmap displays median property value at the ZIP code level. The legend on the bottom right is median property value (in the thousands of dollars). The map is meant to help pick an area that is right for you to invest in. Data are provided from Zillow. If you hover over a ZIP code, median sale price, median monthly rent, naming; removed appreciation; questionifiedmedian property value, and one-year change in property value will be displayed in the upper right-hand corner of the map. 
Note not all the above information is available for all ZIP codes.

 <div id="llmap" class = "content-section middle toppad" ></div>

<script type="text/javascript" src="{{url_for('static', filename='us-states.js')}}"></script>

<script type="text/javascript">

    var TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
    var MB_ATTR = 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors';
    map = L.map('llmap', {});
    L.tileLayer(TILE_URL, {attribution: MB_ATTR}).addTo(map);
    map.locate({setView: true, maxZoom: 9});
    function onLocationError(e) {

    // control that shows state info on hover
    var info = L.control();

    info.onAdd = function (map) {
        this._div = L.DomUtil.create('div', 'info');
        return this._div;

    info.update = function (props) {
        this._div.innerHTML = '<h6>Market Info by ZIP Code</h6>' +  (props ?
            '<b>' +  'ZIP: ' + props.ZIP + '</b><br />' + 
            'Median Home Property Value, May 2020: ' + props.valmay2020  + '<br />' +
            'Median Home Sale Price, March 2020: ' + props.salemarch2020 + '<br />' +
            'Median Rent, April 2020: ' + props.rentapr2020 + ', City Level Only' + '<br / >' +
            '1yr. House Value Change: ' + props.chg1yrpropval +'%' + '<br />' 
            : 'Hover over a ZIP Code');


    // get color depending on population density value
    function getColor(d) {
        return d >  400000 ? '#800026' :
                d > 300000  ? '#BD0026' :
                d > 200000  ? '#E31A1C' :
                d > 150000  ? '#FC4E2A' :
                d > 100000   ? '#FD8D3C' :
                d > 50000   ? '#FEB24C' :
                d > 25000   ? '#FED976' :

    function style(feature) {
        return {
            weight: 2,
            opacity: 1,
            color: 'white',
            dashArray: '3',
            fillOpacity: 0.7,
            fillColor: getColor(feature.properties.valmay2020)

    function highlightFeature(e) {
        var layer = e.target;

            weight: 5,
            color: '#666',
            dashArray: '',
            fillOpacity: 0.7

        if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {


    var geojson;

    function resetHighlight(e) {

    function zoomToFeature(e) {

    function onEachFeature(feature, layer) {
            mouseover: highlightFeature,
            mouseout: resetHighlight,
            click: zoomToFeature

    geojson = L.geoJson(statesData, {
            style: style,
        onEachFeature: onEachFeature


    map.attributionControl.addAttribution('Housing and Rental data &copy; Zillow');

    var legend = L.control({position: 'bottomright'});

    legend.onAdd = function (map) {

        var div = L.DomUtil.create('div', 'info legend'),
            grades = [0, 25000, 50000, 100000, 150000, 200000, 300000, 400000],
            labels = [],
            from, to;

        for (var i = 0; i < grades.length; i++) {
            from = grades[i];
            to = grades[i + 1];
            froml = grades[i]/1000 + 'k';
            tol = grades[i +1]/1000 + 'k';

                '<i style="background:' + getColor(from + 1) + '"></i> ' +
                froml + (to ? '&ndash;' + tol : '+'));

        div.innerHTML = labels.join('<br>');
        return div;


  • Have a look at this Leaflet plugin: github.com/ahalota/Leaflet.CountrySelect. List of countries is not fiexed, you can replace it with a list of US states. – TomazicM Aug 2 '20 at 19:43
  • @TomazicM thank you, I will check it out, if I can get it to work I will post the solution here – Mike Aug 2 '20 at 21:07
  • @TomazicM that was a helpful plugin but I think I left out an important detail. I see that function uses get.bounds and then highlights the country border. That is helpful but my level of analysis is at the more granular level than state. So I would like to grab state and then highlight the boundaries at a smaller level (ZIP codes). – Mike Aug 3 '20 at 13:20
  • It's not quite clear what exactly you want to do/achieve. What do you mean by "grab a state"? To me it seems that's exactly what mentioned plugin offers. You just have to use select.on('change' ... event processing function to display desired state's ZIP features in a GeoJSON layer. – TomazicM Aug 5 '20 at 5:28

If I understand the question correctly, you want to have a mechanism to select between 50 states files and create the relevant featuregroup upon selection and add it to the map.
If this is the case, I suggest using an object to connect between the selection and the files names. Example:

const states = {      
    AL: "Alabama.geojson",      
    AK: "Alaska .geojson",

When you have such an object, you can use a simplified USA states geojson for the initial map load (suggestion). After that you can implement an AJAX call to the relevant file on the user's map click/selection.

let statesGeojsons = statesGeojsons  || {}; 
function selectState(e) {
    // Example for using a state code property
    let sel = 'AK' || e.layer.feature.properties.stateCode; //
    let filename = states[sel];        
    let tempGeojsonLayer = new L.GeoJSON.AJAX(filename);
    statesGeojsons[sel] = tempGeojsonLayer; 
    // Hide the states featuregroup
    // Add the new featuregroup


  1. Use an array to quickly hide non-relevant states' layers (and easy reload)
  2. Depends on your needs, you might wanna hide the states featuregroup when there's an active state selection
  3. Use the Leaflet AJAX plugin for dynamic featuregroup creation.

(You can also skip the "states featuregroup" and create another selector with HTML input/select etc.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.