Created
April 19, 2022 17:22
-
-
Save treighton/dd956fd7d337f34fbe9ff0b484a1ed71 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as L from 'leaflet'; | |
import * as EL from 'esri-leaflet'; | |
import {slugify, deSlugify} from '../../shared/slugify'; | |
/** | |
* Init function | |
* | |
* @return Map object | |
*/ | |
const init = () => { | |
if ( !document.querySelector( '#map' ) ) { | |
return; | |
} | |
const locations = getLocations(); | |
const locationMarkers = buildLocationMarkers( locations ); | |
const locationsFeature = L.featureGroup( locationMarkers ); | |
const topo = EL.basemapLayer( 'Topographic', { detectRetina: true } ); | |
const map = buildMap( 'map', [locationsFeature, topo] ); | |
const filters = addFilters( '.filters', locations ); | |
map.fitBounds( locationsFeature.getBounds() ); | |
filters.addEventListener( 'change', ( e ) => { | |
if ( e.target.value ) { | |
const appliedFilters = getAppliedFilters(); | |
let newLocations; | |
if ( 'all' !== appliedFilters.unit && 'all' !== appliedFilters.state ) { | |
newLocations = locations.filter( location => { | |
return appliedFilters.unit === location.dataset.unit && appliedFilters.state === location.dataset.state; | |
} ); | |
} else if( 'all' !== appliedFilters.unit ) { | |
newLocations = locations.filter( location => { | |
return appliedFilters.unit === location.dataset.unit; | |
} ); | |
} else if( 'all' !== appliedFilters.state ) { | |
newLocations = locations.filter( location => { | |
return appliedFilters.state === location.dataset.state; | |
} ); | |
} else { | |
newLocations = locations; | |
} | |
applyFilters( newLocations, locationsFeature ); | |
} | |
} ); | |
return map; | |
}; | |
/** | |
* Build Map | |
* | |
* @returns Map opbject | |
*/ | |
const buildMap = ( mapEl, layers ) => { | |
return L.map( mapEl, { | |
layers: layers, | |
scrollWheelZoom: false, | |
dragging: true | |
} ).setView( | |
[37.0902, -95.7129], | |
4 | |
); | |
}; | |
/** | |
* Get locations from fallback markup | |
* | |
* @return array of location objects | |
*/ | |
const getLocations = () => Array.from( document.querySelectorAll( '.location' ) ); | |
/** | |
* build location markers | |
* | |
* @return array of location markers | |
*/ | |
const buildLocationMarkers = ( locations ) => locations.map( location => { | |
const data = location.dataset; | |
if ( data.lat && data.lng ) { | |
return L.marker( [data.lat, data.lng], { | |
title: data.contact, | |
alt: `${data.contact} of ${data.state} for ${data.unit}` | |
} ).bindPopup( ` | |
<div class="location-details"> | |
${location.innerHTML} | |
</div> | |
` ); | |
} | |
} ); | |
/** | |
* build filters | |
* | |
* @return Filter elements | |
*/ | |
const buildFilters = ( locations ) => { | |
const states = [... new Set( locations.map( location => location.dataset.state ) )]; | |
states.sort(); | |
const units = [... new Set( locations.map( location => location.dataset.unit ) )]; | |
units.sort(); | |
const stateFilter = ` | |
<fieldset class="filter-group"> | |
<legend> | |
Filter by State | |
</legend> | |
<div class="filter-container custom-select"> | |
${ states.length && '<select data-filter="state">'} | |
${ states.length && '<option value="all">Select a State</option>'} | |
${states.map( state => { | |
if ( !state ) { | |
return; | |
} | |
return ( `<option id="f-${state}" value="${state}"/>${state}</option>` ); | |
} ).join( '' )} | |
${ states.length && '</select>'} | |
</div> | |
</fieldset> | |
`; | |
const unitFilter = ` | |
<fieldset class="filter-group"> | |
<legend> | |
Filter by Type | |
</legend> | |
<div class="filter-container custom-select"> | |
${ units.length && '<select data-filter="unit">'} | |
${ units.length && '<option value="all">Select a Type</option>'} | |
${units.map( unit => { | |
if ( !unit ) { | |
return; | |
} | |
return ( `<option id="f-${slugify( unit )}" value="${slugify( unit )}"/>${deSlugify( unit )}</option>` ); | |
} ).join( '' )} | |
${ units.length && '</select>'} | |
</div> | |
</fieldset> | |
`; | |
return [unitFilter, '<span>and/or</span>', stateFilter].join( '' ); | |
}; | |
/** | |
* Add Filters to component | |
* @param {string} el | |
* @param {array} items | |
* | |
* @returns {node} | |
*/ | |
const addFilters = ( el, items ) => { | |
const filterEl = document.querySelector( el ); | |
filterEl.innerHTML = buildFilters ( items ); | |
return filterEl; | |
}; | |
/** | |
* Get applied filtesd | |
* @returns Filters | |
*/ | |
const getAppliedFilters = () => { | |
const filters = Array.from( document.querySelectorAll( '.filters select' ) ); | |
return Object.fromEntries( new Map( filters.map( filter => [filter.dataset.filter, filter.value] ) ) ); | |
}; | |
/** | |
* Apply filters to layers | |
* @param {array} loations | |
*/ | |
const applyFilters = ( locations, locationGroup ) => { | |
const newLocationMarkers = buildLocationMarkers( locations ); | |
locationGroup.clearLayers(); | |
locationGroup.addLayer( L.layerGroup( newLocationMarkers ) ); | |
}; | |
export { init }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment