TransWikia.com

Change GeoJSON file based on user input

Geographic Information Systems Asked on January 28, 2021

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. 
<br>
Note not all the above information is available for all ZIP codes.
</div>

 
 <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) {
    alert(e.message);
}


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

    info.onAdd = function (map) {
        this._div = L.DomUtil.create('div', 'info');
        this.update();
        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');
    };

    info.addTo(map);


    // 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' :
                            '#FFEDA0';
    }

    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;

        layer.setStyle({
            weight: 5,
            color: '#666',
            dashArray: '',
            fillOpacity: 0.7
        });

        if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
            layer.bringToFront();
        }

        info.update(layer.feature.properties);
    }

    var geojson;

    function resetHighlight(e) {
        geojson.resetStyle(e.target);
        info.update();
    }

    function zoomToFeature(e) {
        map.fitBounds(e.target.getBounds());
    }

    function onEachFeature(feature, layer) {
        layer.on({
            mouseover: highlightFeature,
            mouseout: resetHighlight,
            click: zoomToFeature
        });
    }

    geojson = L.geoJson(statesData, {
            style: style,
        onEachFeature: onEachFeature
    }).addTo(map);






    /*map.on('moveend',function(){
        alert(map.getBounds());
    })
*/


    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';

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

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

    legend.addTo(map);




</script>

One Answer

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
    statesGeojsons[sel].addTo(map);
}

Tips:

  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.)

Correct answer by NettaB on January 28, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP