A leaflet plugin that has a collection of layers containing environmental data pulled in from different sources. See this demo page for a simple demonstration of the plugin.
- What is LEL
- Installation
- Usage
- Dependencies
- Getting started
- Features
- Layers
- Adding LEL features individually
- Adding layers individually
- Contributing
- Reach out to the maintainers
- About PublicLab
Install using NPM with: npm install leaflet-environmental-layers
See Dependencies below for what you need to include for basic usage and for individual layers.
Instantiate a collection of environmentally related Leaflet layers with the L.LayerGroup.EnvironmentalLayers(options)
function:
L.LayerGroup.EnvironmentalLayers({
// simpleLayerControl: true,
addLayersToMap: true,
include: ['odorreport', 'clouds', 'eonetFiresLayer', 'Unearthing', 'PLpeople'], // display only these layers
// exclude: ['mapknitter', 'clouds'], // layers to exclude (cannot be used at same time as 'include'
// display: ['eonetFiresLayer'], // which layers are actually shown as opposed to just being in the menu
hash: true,
embed: true,
// hostname: 'domain name goes here'
}).addTo(map);
When specifying layers to include or exclude, use their names as listed in the table below.
Option | Type | Default | Description |
---|---|---|---|
baseLayers |
Object | - | Passed in as { 'Standard': baselayer } where 'Standard' is the name given to the layer and baselayer is the variable containing the base tile layer(L.tileLayer() ). It can have more than one base layer. At least one base layer should be added to the map instance. If no baseLayers are provided it is defaulted to a grey-scale base map. |
simpleLayerControl |
Boolean | false | If set to true, it will replace LEL's layer menu with leaflet's default layers control. |
addLayersToMap |
Boolean | false | If set to true, adds all layers in the include option to the map by default. |
include |
Array | Array | If provided, adds the given layers to the layer menu or layers control. If not provided, adds all the layers to the layer menu or layers control. |
exclude |
Array | - | If provided, excludes the given layers from the layer menu or layers control. |
display |
Array | - | If provided, displays the given layers by default on the map. |
hash |
Boolean | false | If true, provides hash support for the map. |
embed |
Boolean | false | If true, adds an embed control that generates code to the map for embedding the map on other sites. |
hostname |
String | 'publiclab.github.io' | Uses the value in place of hostname in the URL generated in the embed code. |
- Install Bootstrap(Required for the layers menu)
- Install @fortawesome/fontawesome-free
- Add the following to the head of the HTML file that would contain the map
<!-- Required for PLpeople layer - must load before dist/LeafletEnvironmentalLayers.js -->
<script src="../node_modules/leaflet-blurred-location/dist/Leaflet.BlurredLocation.js"></script>
<script src="../node_modules/leaflet.blurred-location-display/dist/Leaflet.BlurredLocationDisplay.js"></script>
<!-- Required for all maps -->
<script src="../node_modules\jquery\dist\jquery.min.js"></script>
<script src="../dist/LeafletEnvironmentalLayers.js"></script>
<link href="../node_modules/leaflet/dist/leaflet.css" rel="stylesheet" />
<link href="../dist/LeafletEnvironmentalLayers.css" rel="stylesheet" />
<link href="../node_modules\@fortawesome\fontawesome-free\css\all.min.css" rel="stylesheet" />
<script type="module" src="node_modules/spin.js/spin.js"></script>
<link rel="stylesheet" href="node_modules/spin.js/spin.css">
<!-- Bootstrap - not needed if you use simpleLayerControl:true -->
<script src="../node_modules\bootstrap\dist\js\bootstrap.min.js"></script>
<link rel="stylesheet" href="../node_modules\bootstrap\dist\css\bootstrap.min.css">
<!-- Required for setting hash:true -->
<script src="../lib/leaflet-fullUrlHash.js"></script>
<!-- Required for search control -->
<script src="../node_modules/leaflet-google-places-autocomplete/src/js/leaflet-gplaces-autocomplete.js"></script>
<link rel="stylesheet" href="../node_modules/leaflet-google-places-autocomplete/src/css/leaflet-gplaces-autocomplete.css">
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAOLUQngEmJv0_zcG1xkGq-CXIPpLQY8iQ&libraries=places"></script>
<!-- Required for purpleLayer -->
<script src="../node_modules/heatmap.js/build/heatmap.min.js"></script>
<script src="../node_modules/leaflet-heatmap/leaflet-heatmap.js"></script>
<!-- Required for wisconsin Layer -->
<script src="https://unpkg.com/esri-leaflet@2.2.3/dist/esri-leaflet.js"></script>
<script src="https://unpkg.com/esri-leaflet-renderers@2.0.6"></script>
<!-- Required for windRose Layer -->
<script src="../src/windRoseLayer.js"></script>
<!-- Required for Unearthing Layer -->
<script src="../lib/glify.js"></script>
- Clone this repository to your local environment.
- Run
npm install
to install all the necessary packages required. - Open
examples/index.html
in your browser to look at the preview of the library.
- Install grunt - https://gruntjs.com/installing-grunt.
- Make the changes you are working on in the respective /src files.
- Run
grunt build
to generate files in the /dist directory. - Run
grunt transpile
to transpile es6 code and copy files needed to run the tests to the /dist directory. - Run
grunt jasmine
to run tests on the LEL layers and ensure they pass. - Run
npm run start
to start a local server. - Run
npm run cy:run:chrome
to run e2e and integration tests. - Test your changes on a browser by opening
examples/index.html
.
To run Cypress tests in GitPod, you'll need to do npm install -g cypress
and then use: npm run start:ci & cypress run --browser electron
Click and drag the map to pan it.
Use the button on right-most corner to change the way the background of the map looks.
- Toggle certain layers on and off using the Layers button in the toolbar.
- Layers with near-real-time or real-time data will have the 'NRT/RT' mark on them.
- More information on the layer data will be available when clicking the 'i' button on the layer
- Layers that allow contributions will have a
report
button orcontribute
button. - Layers will be visible on the menu only when the map view intersects with the layer's bounds or zoom levels.
- A badge displays the number of new layers in the map view when the map intersects with new layers
Read more about the layers menu here.
Click on a point or marker on the map to learn more about it.
Click on the button group on the left, below the zoom controls, to change between default markers mode and minimal markers mode. Use minimal markers mode for a smoother experience when using multiple layers with many markers.
Read more about this feature here.
The map page's URL hash updates on map movement and when a layer is added or removed from a map. This helps preserve map state when refreshing or copying the URL to another page.
Click on the button at the bottom on the left side of a map to generate an embed code so that the map page can be embedded in other sites.
The information of each layer can be found here: Layer Information
Layer Name | Color |
---|---|
PLpeople |
N/A |
wisconsin |
N/A |
fracTrackerMobile |
N/A |
purpleLayer |
#8b0000 |
purpleairmarker |
#800080 |
skytruth |
#ff0000 |
fractracker |
#ffff00 |
pfasLayer |
#00ff00 |
toxicReleaseLayer |
#008000 |
odorreport |
#ff00ff |
mapknitter |
#D50039 |
Power |
#ffc0cb |
Telecom |
#0000ff |
Petroleum |
#a52a2a |
Water |
#4B0082 |
income |
#006400 |
americanIndian |
#800000 |
asian |
#ffa500 |
black |
#FFD700 |
multi |
#ffc0cb |
hispanic |
#DCDCDC |
nonWhite |
#808080 |
white |
#a52a2a |
plurality |
#800000 |
clouds |
#80dfff |
cloudsClassic |
#b3f0ff |
precipitation |
#00ff55 |
precipitationClassic |
#00008b |
rain |
#8080ff |
rainClassic |
#1a1aff |
snow |
#80ffe5 |
pressure |
#e62e00 |
pressureContour |
#ff3300 |
temperature |
#ff3300 |
wind |
#00008b |
city |
#b3ffff |
windrose |
#008000 |
Territories |
#000000 |
Languages |
#000000 |
Treaties |
#000000 |
aqicnLayer |
#000000 |
openaq |
#000000 |
luftdaten |
#000000 |
opensense |
N/A |
osmLandfillMineQuarryLayer |
N/A |
eonetFiresLayer |
#78fffa |
Unearthing |
N/A |
In src/legendCreation.js
, add addLayerNameURLPair(layer_var, "img_url");
, where layer_var
is consistent with the variable used in example/index.html
and img_url
is the source of the image to be used as the legend.
// Assuming your map instance is in a variable called map
L.control.embed(options).addTo(map);
The optional options object can be passed in with any of the following properties:
Option | Type | Default | Description |
---|---|---|---|
position | String | 'topleft' | Other possible values include 'topright', 'bottomleft' or 'bottomright' |
hostname | String | 'publiclab.github.io' | Sets hostname for the URL in the embed code |
<script src="../lib/leaflet-fullUrlHash.js"></script>
// Assuming your map instance is in a variable called map
// Assuming an object with all the map layers is in a variable called allMapLayers
var hash = new L.FullHash(map, allMapLayers);
- Bootstrap
- jQuery
- Install Bootstrap(Required for the layers menu)
- Install @fortawesome/fontawesome-free
- Add the following to the head of the HTML file that would contain the map
<!-- jQuery -->
<script src="../node_modules\jquery\dist\jquery.min.js"></script>
<!-- Bootstrap -->
<script src="../node_modules\bootstrap\dist\js\bootstrap.min.js"></script>
<link rel="stylesheet" href="../node_modules\bootstrap\dist\css\bootstrap.min.css">
<!-- Required includes -->
<script src="../dist/LeafletEnvironmentalLayers.js"></script>
<link href="../node_modules/leaflet/dist/leaflet.css" rel="stylesheet" />
<link href="../dist/LeafletEnvironmentalLayers.css" rel="stylesheet" />
<link href="../node_modules\@fortawesome\fontawesome-free\css\all.min.css" rel="stylesheet" />
var baseMaps = {
'Standard': L.tileLayer('TILE_LAYER_URL').addTo(map),
'Dark': L.tileLayer('TILE_LAYER_URL')
};
var overlayMaps = {
'wisconsin': Wisconsin_NM, // Assuming 'Wisconsin_NM' is the variable that holds the wisconsin layer object
'indigenousLands': {
category: 'group', // Let's the control know if this should be rendered as a group
layers: { // Layers making the group
'Territories': IndigenousLandsTerritories, // Assuming 'IndigenousLandsTerritories' is the variable that holds the respective layer object
'Languages': IndigenousLandsLanguages, // Assuming 'IndigenousLandsLanguages' is the variable that holds the respective layer object
'Treaties': IndigenousLandsTreaties, // Assuming 'IndigenousLandsTreaties' is the variable that holds the respective layer object
},
},
};
var leafletControl = new L.control.layersBrowser(baseMaps, overlayMaps);
leafletControl.addTo(map);
L.control.layersBrowser(baseMaps, overlayMaps).addTo(map);
baseMaps
andoverlayMaps
are object literals that have layer names as keys and Layer objects as values. Read more about Leaflet's Control.Layers.baseMaps
will be hidden if only one base map is provided- The layer information displayed for each layer is stored in
info.json
- The layer name(key) in the
overlayMaps
object should match the keys ininfo.json
- The layers are filtered according to the map view
- When there are new layers present in the map view when moving around a badge is displayed near the layer control icon on the top right showing the number of new layers in the view
// Assuming your map instance is in a variable called map
// Assuming your layers menu or layers control instance is in a variable called layersControl
L.control.minimalMode(layersControl).addTo(map);
LEL uses leaflet-google-places-autocomplete for the search control feature.
<script src="https://unpkg.com/esri-leaflet@2.2.3/dist/esri-leaflet.js"></script>
<script src="https://unpkg.com/esri-leaflet-renderers@2.0.6"></script>
var Wisconsin_NM = wisconsinLayer(map) ;
var FracTracker_mobile = L.geoJSON.fracTrackerMobile();
<script src="../node_modules/heatmap.js/build/heatmap.min.js"></script>
<script src="../node_modules/leaflet-heatmap/leaflet-heatmap.js"></script>
<script src="../lib/glify.js"></script>
These must be included in the file before /dist/LeafletEnvironmentalLayers.js:
<script src="../node_modules/leaflet-blurred-location/dist/Leaflet.BlurredLocation.js"></script>
<script src="../node_modules/leaflet.blurred-location-display/dist/Leaflet.BlurredLocationDisplay.js"></script>
var city = L.OWM.current({intervall: 15, minZoom: 3});
<script src="../src/windRoseLayer.js"></script>
var windrose = L.OWM.current({intervall: 15, minZoom: 3, markerFunction: myWindroseMarker, popup: false, clusterSize: 50,imageLoadingBgUrl: 'https://openweathermap.org/img/w0/iwind.png' });
windrose.on('owmlayeradd', windroseAdded, windrose);
var OpenInfraMap_Power = L.tileLayer('https://tiles-{s}.openinframap.org/power/{z}/{x}/{y}.png',{
maxZoom: 18,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a href="http://www.openinframap.org/about.html">About OpenInfraMap</a>'
});
var OpenInfraMap_Petroleum = L.tileLayer('https://tiles-{s}.openinframap.org/petroleum/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a href="http://www.openinframap.org/about.html">About OpenInfraMap</a>'
});
var OpenInfraMap_Telecom = L.tileLayer('https://tiles-{s}.openinframap.org/telecoms/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a href="http://www.openinframap.org/about.html">About OpenInfraMap</a>'
});
var OpenInfraMap_Water = L.tileLayer('https://tiles-{s}.openinframap.org/water/{z}/{x}/{y}.png',{
maxZoom: 18,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a href="http://www.openinframap.org/about.html">About OpenInfraMap</a>'
});
We can source locations from a spreadsheet in a format like this:
Title | Latitude | Longitude | Notes |
---|---|---|---|
First | 29.671282 | -95.17829 | The first marker |
Second | 29.760371 | -95.504828 | The second marker |
Third | 29.917755 | -95.283494 | The third marker |
The layer is constructed like this:
var layer = L.SpreadsheetLayer({
url: 'https://docs.google.com/spreadsheets/d/14BvU3mEqvI8moLp0vANc7jeEvb0mnmYvH4I0GkwVsiU/edit?usp=sharing', // String url of data sheet
lat: 'Latitude', // name of latitude column
lon: 'Longitude', // name of longitude column
columns: ['Title', 'Notes'], // Array of column names to be used
generatePopup: function() {
// function used to create content of popups
},
// imageOptions: // optional, defaults to blank
// sheetNum: // optional, defaults to 0 (first sheet)
});
layer.addTo(map);
Read more here: https://github.com/publiclab/leaflet-environmental-layers/blob/master/src/util/googleSpreadsheetLayer.js
We're going to try spinning this out into its own library; see: #121
Please read CONTRIBUTING.md for details on our code of conduct, the process for submitting pull requests, and steps to add new layers.
Reach out to the maintainers here: https://github.com/orgs/publiclab/teams/maintainers
Public Lab is a community and non-profit democratizing science to address environmental issues that affect people.