Loading app/src/components/container/App.jsx +1 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ export default function App() { <ArrowLeftIcon/> </div> <div className={sortBarStyle}> <SearchAndFilterInput /> <SearchAndFilterInput target={targetPlanet}/> {/* instead of styled surrounding div: { showSortBar ? <SearchAndFilterInput /> : null } ^ simpler but might break things if another part of the program is looking for it and it's not there? */} </div> Loading app/src/components/presentational/SearchAndFilterInput.jsx +63 −6 Original line number Diff line number Diff line import React from "react"; import React, {useEffect} from "react"; // Apply and Clear Buttons import ButtonGroup from "@material-ui/core/ButtonGroup"; import Button from "@material-ui/core/Button"; Loading @@ -21,6 +21,10 @@ import InputLabel from '@mui/material/InputLabel'; import FormControl from '@mui/material/FormControl'; import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'; import Slider from '@mui/material/Slider'; import Pagination from '@mui/material/Pagination'; import { getMaxNumberPages, setCurrentPage, getCurrentPage, getNumberMatched } from "../../js/ApiJsonCollection"; /** Loading Loading @@ -80,7 +84,7 @@ const useStyles = makeStyles(theme => ({ * <SearchAndFilterInput /> * */ export default function SearchAndFilterInput() { export default function SearchAndFilterInput(props) { // import stylesheet from above const classes = useStyles(); Loading @@ -99,6 +103,9 @@ export default function SearchAndFilterInput() { const [dateCheckVal, setDateCheckVal] = React.useState(false); const [dateFromVal, setDateFromVal] = React.useState(null); const [dateToVal, setDateToVal] = React.useState(null); const [maxPages, setMaxPages] = React.useState(0); const [maxNumberFootprints, setMaxNumberFootprints] = React.useState(0); const [limitVal, setLimitVal] = React.useState(0); // Clear all values const handleClear = (event) => { Loading @@ -110,6 +117,9 @@ export default function SearchAndFilterInput() { setDateCheckVal(false); setDateFromVal(null); setDateToVal(null); setLimitVal(10); setMaxPages(getMaxNumberPages); setMaxNumberFootprints(getNumberMatched); //// Uncomment to close details on clear // keywordDetails.current.open = false; // dateDetails.current.open = false; Loading Loading @@ -156,6 +166,29 @@ export default function SearchAndFilterInput() { setDateCheckVal(true); } // limit const handleLimitChange = (event, value) => { setLimitVal(value); setTimeout(() => { setMaxPages(getMaxNumberPages); }, 1000); } // resets pagination and limit when switching targets useEffect(() => { setTimeout(() => { setMaxNumberFootprints(getNumberMatched); setLimitVal(10); setMaxPages(getMaxNumberPages); }, 1000); }, [props.target]); // Pagination const handlePageChange = (event, value) => { setCurrentPage(value); }; /* Control IDs for reference: applyButton clearButton Loading @@ -176,7 +209,6 @@ export default function SearchAndFilterInput() { <div className="panelSection panelHeader"> Sort and Filter </div> <div className="panelSection"> <ButtonGroup> <Button id="applyButton" variant="contained" startIcon={<FilterAltIcon />} className={classes.button}> Loading Loading @@ -294,6 +326,31 @@ export default function SearchAndFilterInput() { </div> </details> </div> <div className="panelSectionHeader"> <div className="panelItem"> <div className="panelSectionTitle">Number of Displayed Footprints</div> <Slider id="valueSlider" size="small" valueLabelDisplay="auto" onChange={handleLimitChange} value={limitVal} max={maxNumberFootprints} defaultValue={10} /> </div> </div> <div className="panelSectionHeader"> <div className="panelItem"> <div className="panelSectionTitle">Showing {limitVal} of {maxNumberFootprints} Footprints</div> <Pagination id="pagination" count={maxPages} size="small" onChange={handlePageChange} /> </div> </div> </div> </div> ); Loading app/src/js/ApiJsonCollection.js +59 −1 Original line number Diff line number Diff line var _maxNumberPages = 0; var _currentPage = 1; var _numberMatched = 0; function callAPI() { return fetch( "https://stac.astrogeology.usgs.gov/api/collections" Loading Loading @@ -44,4 +48,58 @@ function getItemCollection(name, queryString) { }); } export { getItemCollection }; No newline at end of file /** * @function setNumberMatched * @description Sets the value of the return number of footprints */ function setNumberMatched(matched) { _numberMatched = matched; let sliderElement = document.getElementById('valueSlider'); let limitVal = sliderElement.lastChild.firstChild.value; if (limitVal != 0 && matched != 0){ setMaxNumberPages(Math.floor(matched/limitVal)); } } /** * @function getNumberMatched * @description Gets the value of the return number of footprints */ function getNumberMatched() { return _numberMatched } /** * @function setMaxNumberPages * @description Sets the value of the max number of pages possible */ function setMaxNumberPages(pages) { _maxNumberPages = pages; } /** * @function getMaxNumberPages * @description Gets the value of the max number of pages possible */ function getMaxNumberPages() { return _maxNumberPages; } /** * @function setCurrentPage * @description Sets the value of the current page */ function setCurrentPage(page) { _currentPage = page; } /** * @function getMaxNumberPages * @description Gets the value of the max number of pages possible */ function getCurrentPage() { return _currentPage; } export { getItemCollection, getMaxNumberPages, setCurrentPage, getCurrentPage, setNumberMatched, getNumberMatched, setMaxNumberPages }; app/src/js/AstroDrawControl.js +53 −8 Original line number Diff line number Diff line import L from "leaflet"; import "leaflet-draw"; import Wkt from "wicket"; import {getCurrentPage} from "./ApiJsonCollection"; /** * @class AstroDrawControl * @aka L.Control.AstroDrawControl Loading Loading @@ -79,6 +81,12 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ ); L.DomEvent.on(L.DomUtil.get("clearButton"), "click", this.clearMap, this); this.valueSlider = L.DomUtil.get("valueSlider") L.DomEvent.on(this.valueSlider, "click", this.applyLimit, this); this.pagination = L.DomUtil.get("pagination") L.DomEvent.on(this.pagination, "click", this.applyPage, this); map.on("draw:created", this.shapesToWKT, this); // map.on("projChange", this.reprojectFeature, this); Loading Loading @@ -109,9 +117,49 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ clearMap: function() { this._map._footprintControl.remove(); this._map._geoLayer.clearLayers(); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } }, applyLimit: function() { this._map._footprintControl.remove(); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } let currentPage = getCurrentPage(); let sliderElement = L.DomUtil.get("valueSlider"); let limitVal = sliderElement.lastChild.firstChild.value; let queryString = "?page=" + currentPage; queryString += "&limit=" + limitVal; this._map.loadFootprintLayer(this._map._target, queryString); }, applyPage: function() { this._map._footprintControl.remove(); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } let currentPage = getCurrentPage(); let sliderElement = L.DomUtil.get("valueSlider"); let limitVal = sliderElement.lastChild.firstChild.value; let queryString = "?page=" + currentPage; queryString += "&limit=" + limitVal; this._map.loadFootprintLayer(this._map._target, queryString); }, /** * @function shapesToFootprint * @description Is called when a user draws a shape using the on map drawing features. Loading Loading @@ -139,9 +187,6 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ bboxCoordArr[1][0], bboxCoordArr[1][1] ]; this._map._footprintControl.remove(); this._map._geoLayer.clearLayers(); this._map.removeControl(this._map._htmllegend); let queryString = "bbox=" + "[" + bboxArr + "]"; return queryString; }, Loading Loading @@ -184,7 +229,6 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ } if (L.DomUtil.get("areaCheckBox").checked == true) { console.log("area"); let bboxValue = this.shapesToFootprint(this.wktTextBox.value); filterOptions.push(bboxValue); } Loading @@ -200,9 +244,10 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ } // re render map this._map._footprintControl.remove(); this._map._geoLayer.clearLayers(); this._map.removeControl(this._map._htmllegend); this._map.loadFootprintLayer(this._map._name, queryString); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } this._map.loadFootprintLayer(this._map._target, queryString); }, /** Loading app/src/js/AstroMap.js +17 −74 Original line number Diff line number Diff line Loading @@ -2,10 +2,8 @@ import L from "leaflet"; import "proj4leaflet"; import AstroProj from "./AstroProj"; import LayerCollection from "./LayerCollection"; import { getItemCollection, url } from "./ApiJsonCollection"; import { getItemCollection, setNumberMatched, setMaxNumberPages, getCurrentPage, setCurrentPage } from "./ApiJsonCollection"; import { MY_JSON_MAPS } from "./layers"; import "leaflet-html-legend"; import React from "react"; /** * @class AstroMap Loading Loading @@ -47,10 +45,8 @@ export default L.Map.AstroMap = L.Map.extend({ }; this._footprintCollection = {}; this._footprintControl = null; this._geoLayer = null; this._name = null; this._geoLayers = []; this._htmllegend = null; this._currentPage = 1; // Set by layer collection or baselayerchange event this._currentLayer = null; Loading Loading @@ -98,7 +94,8 @@ export default L.Map.AstroMap = L.Map.extend({ L.Map.prototype.initialize.call(this, this._mapDiv, this.options); this.loadLayerCollection("cylindrical"); this.loadFootprintLayer(target, "?page=" + this._currentPage); setCurrentPage(1); this.loadFootprintLayer(target, "?page=1"); // Listen to baselayerchange event so that we can set the current layer being // viewed by the map. Loading @@ -125,6 +122,7 @@ export default L.Map.AstroMap = L.Map.extend({ this.layers[name].addTo(this); }, /** * @function AstroMap.prototype.loadFootprintLayer * @description Adds the ApiJsonCollection with the requested name. Loading @@ -133,84 +131,29 @@ export default L.Map.AstroMap = L.Map.extend({ * * @param {String} queryString - Filter for deisered footprints ie: ?page=1 * * @param {Boolean} loadFootprintLegend - Boolean value used to bypass adding * the FootprintLegend */ loadFootprintLayer: function(name, queryString, loadFootprintLegend = true) { loadFootprintLayer: function(name, queryString) { var matched = 0; getItemCollection(name, queryString).then(result => { if (result != undefined) { this._name = name; this._geoLayer = L.geoJSON() this._geoLayers = new Array(result.length); for (let i = 0; i < result.length; i++) { this._geoLayers[i] = L.geoJSON() .on('click', function(e){ console.log(e); }).addTo(this); this._footprintCollection["Footprints"] = this._geoLayer; for (let i = 0; i < result.length; i++) { matched += result[i].numberMatched; for (let j = 0; j < result[i].features.length; j++) { this._geoLayer.addData(result[i].features[j]); this._footprintCollection[result[i].features[j].collection] = this._geoLayers[i]; this._geoLayers[i].addData(result[i].features[j]); } } this._footprintControl = L.control .layers(null, this._footprintCollection) .addTo(this); if (loadFootprintLegend) { this.addFootprintLegend(name); } } }); }, /** * @function AstroMap.prototype.addFootprintLegend * @description Adds legend for each footprint layer * * @param {String} name - Name of the projection * */ addFootprintLegend: function(name) { var self = this; var legend = L.control.htmllegend({ legends: [ { name: "Footprints", layer: this._geoLayer, elements: [ { html: `<div class="pagination"> <a id=footprint_left>«</a> <a id=footprint_pageNumber>${self._currentPage}</a> <a id=footprint_right>»</a> </div>` } ] } ] }); this._htmllegend = legend; this.addControl(legend); $("#footprint_right").click(function() { self._currentPage += 1; self._footprintControl.remove(); self._geoLayer.clearLayers(); self.removeControl(legend); let queryString = "?page=" + self._currentPage; self.loadFootprintLayer(name, queryString); }); $("#footprint_left").click(function() { self._currentPage -= 1; if (this._currentPage > 0) { self._footprintControl.remove(); self._geoLayer.clearLayers(); self.removeControl(legend); let queryString = "?page=" + self._currentPage; self.loadFootprintLayer(name, queryString); } // should add some error message here eventually setNumberMatched(matched); }); }, Loading Loading
app/src/components/container/App.jsx +1 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ export default function App() { <ArrowLeftIcon/> </div> <div className={sortBarStyle}> <SearchAndFilterInput /> <SearchAndFilterInput target={targetPlanet}/> {/* instead of styled surrounding div: { showSortBar ? <SearchAndFilterInput /> : null } ^ simpler but might break things if another part of the program is looking for it and it's not there? */} </div> Loading
app/src/components/presentational/SearchAndFilterInput.jsx +63 −6 Original line number Diff line number Diff line import React from "react"; import React, {useEffect} from "react"; // Apply and Clear Buttons import ButtonGroup from "@material-ui/core/ButtonGroup"; import Button from "@material-ui/core/Button"; Loading @@ -21,6 +21,10 @@ import InputLabel from '@mui/material/InputLabel'; import FormControl from '@mui/material/FormControl'; import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'; import Slider from '@mui/material/Slider'; import Pagination from '@mui/material/Pagination'; import { getMaxNumberPages, setCurrentPage, getCurrentPage, getNumberMatched } from "../../js/ApiJsonCollection"; /** Loading Loading @@ -80,7 +84,7 @@ const useStyles = makeStyles(theme => ({ * <SearchAndFilterInput /> * */ export default function SearchAndFilterInput() { export default function SearchAndFilterInput(props) { // import stylesheet from above const classes = useStyles(); Loading @@ -99,6 +103,9 @@ export default function SearchAndFilterInput() { const [dateCheckVal, setDateCheckVal] = React.useState(false); const [dateFromVal, setDateFromVal] = React.useState(null); const [dateToVal, setDateToVal] = React.useState(null); const [maxPages, setMaxPages] = React.useState(0); const [maxNumberFootprints, setMaxNumberFootprints] = React.useState(0); const [limitVal, setLimitVal] = React.useState(0); // Clear all values const handleClear = (event) => { Loading @@ -110,6 +117,9 @@ export default function SearchAndFilterInput() { setDateCheckVal(false); setDateFromVal(null); setDateToVal(null); setLimitVal(10); setMaxPages(getMaxNumberPages); setMaxNumberFootprints(getNumberMatched); //// Uncomment to close details on clear // keywordDetails.current.open = false; // dateDetails.current.open = false; Loading Loading @@ -156,6 +166,29 @@ export default function SearchAndFilterInput() { setDateCheckVal(true); } // limit const handleLimitChange = (event, value) => { setLimitVal(value); setTimeout(() => { setMaxPages(getMaxNumberPages); }, 1000); } // resets pagination and limit when switching targets useEffect(() => { setTimeout(() => { setMaxNumberFootprints(getNumberMatched); setLimitVal(10); setMaxPages(getMaxNumberPages); }, 1000); }, [props.target]); // Pagination const handlePageChange = (event, value) => { setCurrentPage(value); }; /* Control IDs for reference: applyButton clearButton Loading @@ -176,7 +209,6 @@ export default function SearchAndFilterInput() { <div className="panelSection panelHeader"> Sort and Filter </div> <div className="panelSection"> <ButtonGroup> <Button id="applyButton" variant="contained" startIcon={<FilterAltIcon />} className={classes.button}> Loading Loading @@ -294,6 +326,31 @@ export default function SearchAndFilterInput() { </div> </details> </div> <div className="panelSectionHeader"> <div className="panelItem"> <div className="panelSectionTitle">Number of Displayed Footprints</div> <Slider id="valueSlider" size="small" valueLabelDisplay="auto" onChange={handleLimitChange} value={limitVal} max={maxNumberFootprints} defaultValue={10} /> </div> </div> <div className="panelSectionHeader"> <div className="panelItem"> <div className="panelSectionTitle">Showing {limitVal} of {maxNumberFootprints} Footprints</div> <Pagination id="pagination" count={maxPages} size="small" onChange={handlePageChange} /> </div> </div> </div> </div> ); Loading
app/src/js/ApiJsonCollection.js +59 −1 Original line number Diff line number Diff line var _maxNumberPages = 0; var _currentPage = 1; var _numberMatched = 0; function callAPI() { return fetch( "https://stac.astrogeology.usgs.gov/api/collections" Loading Loading @@ -44,4 +48,58 @@ function getItemCollection(name, queryString) { }); } export { getItemCollection }; No newline at end of file /** * @function setNumberMatched * @description Sets the value of the return number of footprints */ function setNumberMatched(matched) { _numberMatched = matched; let sliderElement = document.getElementById('valueSlider'); let limitVal = sliderElement.lastChild.firstChild.value; if (limitVal != 0 && matched != 0){ setMaxNumberPages(Math.floor(matched/limitVal)); } } /** * @function getNumberMatched * @description Gets the value of the return number of footprints */ function getNumberMatched() { return _numberMatched } /** * @function setMaxNumberPages * @description Sets the value of the max number of pages possible */ function setMaxNumberPages(pages) { _maxNumberPages = pages; } /** * @function getMaxNumberPages * @description Gets the value of the max number of pages possible */ function getMaxNumberPages() { return _maxNumberPages; } /** * @function setCurrentPage * @description Sets the value of the current page */ function setCurrentPage(page) { _currentPage = page; } /** * @function getMaxNumberPages * @description Gets the value of the max number of pages possible */ function getCurrentPage() { return _currentPage; } export { getItemCollection, getMaxNumberPages, setCurrentPage, getCurrentPage, setNumberMatched, getNumberMatched, setMaxNumberPages };
app/src/js/AstroDrawControl.js +53 −8 Original line number Diff line number Diff line import L from "leaflet"; import "leaflet-draw"; import Wkt from "wicket"; import {getCurrentPage} from "./ApiJsonCollection"; /** * @class AstroDrawControl * @aka L.Control.AstroDrawControl Loading Loading @@ -79,6 +81,12 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ ); L.DomEvent.on(L.DomUtil.get("clearButton"), "click", this.clearMap, this); this.valueSlider = L.DomUtil.get("valueSlider") L.DomEvent.on(this.valueSlider, "click", this.applyLimit, this); this.pagination = L.DomUtil.get("pagination") L.DomEvent.on(this.pagination, "click", this.applyPage, this); map.on("draw:created", this.shapesToWKT, this); // map.on("projChange", this.reprojectFeature, this); Loading Loading @@ -109,9 +117,49 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ clearMap: function() { this._map._footprintControl.remove(); this._map._geoLayer.clearLayers(); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } }, applyLimit: function() { this._map._footprintControl.remove(); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } let currentPage = getCurrentPage(); let sliderElement = L.DomUtil.get("valueSlider"); let limitVal = sliderElement.lastChild.firstChild.value; let queryString = "?page=" + currentPage; queryString += "&limit=" + limitVal; this._map.loadFootprintLayer(this._map._target, queryString); }, applyPage: function() { this._map._footprintControl.remove(); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } let currentPage = getCurrentPage(); let sliderElement = L.DomUtil.get("valueSlider"); let limitVal = sliderElement.lastChild.firstChild.value; let queryString = "?page=" + currentPage; queryString += "&limit=" + limitVal; this._map.loadFootprintLayer(this._map._target, queryString); }, /** * @function shapesToFootprint * @description Is called when a user draws a shape using the on map drawing features. Loading Loading @@ -139,9 +187,6 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ bboxCoordArr[1][0], bboxCoordArr[1][1] ]; this._map._footprintControl.remove(); this._map._geoLayer.clearLayers(); this._map.removeControl(this._map._htmllegend); let queryString = "bbox=" + "[" + bboxArr + "]"; return queryString; }, Loading Loading @@ -184,7 +229,6 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ } if (L.DomUtil.get("areaCheckBox").checked == true) { console.log("area"); let bboxValue = this.shapesToFootprint(this.wktTextBox.value); filterOptions.push(bboxValue); } Loading @@ -200,9 +244,10 @@ export default L.Control.AstroDrawControl = L.Control.Draw.extend({ } // re render map this._map._footprintControl.remove(); this._map._geoLayer.clearLayers(); this._map.removeControl(this._map._htmllegend); this._map.loadFootprintLayer(this._map._name, queryString); for(let i = 0; i < this._map._geoLayers.length; i++){ this._map._geoLayers[i].clearLayers(); } this._map.loadFootprintLayer(this._map._target, queryString); }, /** Loading
app/src/js/AstroMap.js +17 −74 Original line number Diff line number Diff line Loading @@ -2,10 +2,8 @@ import L from "leaflet"; import "proj4leaflet"; import AstroProj from "./AstroProj"; import LayerCollection from "./LayerCollection"; import { getItemCollection, url } from "./ApiJsonCollection"; import { getItemCollection, setNumberMatched, setMaxNumberPages, getCurrentPage, setCurrentPage } from "./ApiJsonCollection"; import { MY_JSON_MAPS } from "./layers"; import "leaflet-html-legend"; import React from "react"; /** * @class AstroMap Loading Loading @@ -47,10 +45,8 @@ export default L.Map.AstroMap = L.Map.extend({ }; this._footprintCollection = {}; this._footprintControl = null; this._geoLayer = null; this._name = null; this._geoLayers = []; this._htmllegend = null; this._currentPage = 1; // Set by layer collection or baselayerchange event this._currentLayer = null; Loading Loading @@ -98,7 +94,8 @@ export default L.Map.AstroMap = L.Map.extend({ L.Map.prototype.initialize.call(this, this._mapDiv, this.options); this.loadLayerCollection("cylindrical"); this.loadFootprintLayer(target, "?page=" + this._currentPage); setCurrentPage(1); this.loadFootprintLayer(target, "?page=1"); // Listen to baselayerchange event so that we can set the current layer being // viewed by the map. Loading @@ -125,6 +122,7 @@ export default L.Map.AstroMap = L.Map.extend({ this.layers[name].addTo(this); }, /** * @function AstroMap.prototype.loadFootprintLayer * @description Adds the ApiJsonCollection with the requested name. Loading @@ -133,84 +131,29 @@ export default L.Map.AstroMap = L.Map.extend({ * * @param {String} queryString - Filter for deisered footprints ie: ?page=1 * * @param {Boolean} loadFootprintLegend - Boolean value used to bypass adding * the FootprintLegend */ loadFootprintLayer: function(name, queryString, loadFootprintLegend = true) { loadFootprintLayer: function(name, queryString) { var matched = 0; getItemCollection(name, queryString).then(result => { if (result != undefined) { this._name = name; this._geoLayer = L.geoJSON() this._geoLayers = new Array(result.length); for (let i = 0; i < result.length; i++) { this._geoLayers[i] = L.geoJSON() .on('click', function(e){ console.log(e); }).addTo(this); this._footprintCollection["Footprints"] = this._geoLayer; for (let i = 0; i < result.length; i++) { matched += result[i].numberMatched; for (let j = 0; j < result[i].features.length; j++) { this._geoLayer.addData(result[i].features[j]); this._footprintCollection[result[i].features[j].collection] = this._geoLayers[i]; this._geoLayers[i].addData(result[i].features[j]); } } this._footprintControl = L.control .layers(null, this._footprintCollection) .addTo(this); if (loadFootprintLegend) { this.addFootprintLegend(name); } } }); }, /** * @function AstroMap.prototype.addFootprintLegend * @description Adds legend for each footprint layer * * @param {String} name - Name of the projection * */ addFootprintLegend: function(name) { var self = this; var legend = L.control.htmllegend({ legends: [ { name: "Footprints", layer: this._geoLayer, elements: [ { html: `<div class="pagination"> <a id=footprint_left>«</a> <a id=footprint_pageNumber>${self._currentPage}</a> <a id=footprint_right>»</a> </div>` } ] } ] }); this._htmllegend = legend; this.addControl(legend); $("#footprint_right").click(function() { self._currentPage += 1; self._footprintControl.remove(); self._geoLayer.clearLayers(); self.removeControl(legend); let queryString = "?page=" + self._currentPage; self.loadFootprintLayer(name, queryString); }); $("#footprint_left").click(function() { self._currentPage -= 1; if (this._currentPage > 0) { self._footprintControl.remove(); self._geoLayer.clearLayers(); self.removeControl(legend); let queryString = "?page=" + self._currentPage; self.loadFootprintLayer(name, queryString); } // should add some error message here eventually setNumberMatched(matched); }); }, Loading