Skip to content

Instantly share code, notes, and snippets.

@treighton
Created April 19, 2022 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save treighton/dd956fd7d337f34fbe9ff0b484a1ed71 to your computer and use it in GitHub Desktop.
Save treighton/dd956fd7d337f34fbe9ff0b484a1ed71 to your computer and use it in GitHub Desktop.
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