Skip to content

Commit

Permalink
Improve layer menu (#409)
Browse files Browse the repository at this point in the history
* Refactor layers menu to not remove active layers on map move

* Fix layer group title not showing when its layers are visible

* Remove bounds that is no longer relevant

* Limit requesting data to layer extents

* Add cypress intellisense support and update package-lock file

* Add tests to check layer filtering

* Remove references to layerData.json

* Fixed failing tests
  • Loading branch information
crisner authored Feb 23, 2020
1 parent 3a98df5 commit 43a11e3
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 107 deletions.
6 changes: 3 additions & 3 deletions cypress/integration/eonetFiresLayer.spec.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
describe('Eonet fires layer', function() {
it('adds markers on click', function() {
cy.openWindow('/example/index.html#lat=43.00&lon=-83.00&zoom=3&layers=Standard')
cy.wait(5000)
cy.wait(200)
cy.window().then((win) => {
cy.fixture('eonetFiresLayer').then((data) => {
cy.stub(win.EonetFiresLayer, 'requestData', function() {
win.EonetFiresLayer.parseData(data);
})
})

cy.get('#menu-EONET_Fires label').click({ force: true })
cy.get('#menu-eonetFiresLayer label').click({ force: true })
cy.get('.leaflet-marker-pane').children().should('have.length', 4)
})
})
Expand Down Expand Up @@ -38,7 +38,7 @@ describe('Eonet fires layer', function() {
})

it('removes markers from the map and the layer name from the hash when clicked again', function() {
cy.get('#menu-EONET_Fires label').click({ force: true })
cy.get('#menu-eonetFiresLayer label').click({ force: true })
cy.hash().should('eq', '#lat=43.00&lon=-82.97&zoom=3&layers=Standard')
cy.get('.leaflet-marker-pane').children().should('have.length', 0)
cy.get('.leaflet-overlay-pane svg g').children().should('have.length', 0)
Expand Down
4 changes: 2 additions & 2 deletions cypress/integration/fractrackerMobile.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('FractrackerMobile layer', function() {
})
})

cy.get('#menu-FracTracker_mobile label').click({ force: true })
cy.get('#menu-fracTrackerMobile label').click({ force: true })
cy.get('.leaflet-overlay-pane svg g').children().should('have.length', 2)
})
})
Expand Down Expand Up @@ -50,7 +50,7 @@ describe('FractrackerMobile layer', function() {
})

it('removes markers from the map and the layer name from the hash when clicked again', function() {
cy.get('#menu-FracTracker_mobile label').click({ force: true })
cy.get('#menu-fracTrackerMobile label').click({ force: true })
cy.hash().should('eq', '#lat=41.624&lon=-91.626&zoom=5&layers=Standard')
cy.get('.leaflet-marker-pane').children().should('have.length', 0)
cy.get('.leaflet-overlay-pane svg g').children().should('have.length', 0)
Expand Down
73 changes: 73 additions & 0 deletions cypress/integration/layersMenu.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
describe('Layers menu filters and displays layers on map', function() {
it('filters layers at map initialization', function() {
cy.openWindow('/example/index.html#lat=43.00&lon=-83.00&zoom=3&layers=Standard')
cy.wait(200)
cy.get('.leaflet-control-layers').trigger('mouseover')
cy.get('.layer-info-container').should('have.css', 'display', 'block').then((layers) => {
const layersArray = Array.prototype.slice.call(layers)
expect(layersArray.filter(layer => layer.style.display === 'block').length).to.equal(9)
})
cy.get('.leaflet-control-layers').trigger('mouseout')
})

it('adds an alert displaying the number of new layers on map movement', function() {
cy.window().its('map').invoke('setView',[38.565, -100.767], 5)
cy.wait(200)
cy.get('.leaflet-control-layers-toggle .rounded-circle')
.should('have.css', 'display', 'flex')
.invoke('text').should('eq', '13')
})

it('adds layers to the menu on map movement', function() {
cy.get('.leaflet-control-layers').trigger('mouseover')
cy.get('.layer-info-container').should('have.css', 'display', 'block').then((layers) => {
const layersArray = Array.prototype.slice.call(layers)
expect(layersArray.filter(layer => layer.style.display === 'block').length).to.equal(14)
})
})

it('removes alert after layer menu is expanded', function() {
cy.get('.leaflet-control-layers').trigger('mouseout')
cy.get('.leaflet-control-layers-toggle .rounded-circle')
.should('have.css', 'display', 'none')
.invoke('text').should('eq', '')
})

it('removes layers from the menu on map movement', function() {
cy.window().its('map').invoke('setView',[43.00, -83.00], 3)
cy.wait(300)
cy.get('.leaflet-control-layers').trigger('mouseover')
cy.get('.layer-info-container').should('have.css', 'display', 'block').then((layers) => {
const layersArray = Array.prototype.slice.call(layers)
expect(layersArray.filter(layer => layer.style.display === 'block').length).to.equal(9)
})
})

it('retains an active layer when map view does not intersect with its extents', function() {
cy.window().its('map').invoke('setView',[38.565, -100.767], 5)
cy.wait(300)
cy.get('.leaflet-control-layers').trigger('mouseover')
cy.get('#groupName-justiceMap a[data-toggle="collapse"]').click()
cy.get('div#justiceMap.layers-sub-list.collapse.show').children('div')
.last('label').click()
.find('input[type="checkbox"]').should('be.checked')
cy.window().its('map').invoke('setView',[43.00, -83.00], 3)
cy.wait(300)
cy.get('#groupName-justiceMap').should('have.css', 'display', 'block')
cy.get('div#justiceMap.layers-sub-list.collapse.show').children('div')
.last('label').should('have.css', 'display', 'block')
cy.get('div#justiceMap.layers-sub-list.collapse.show').children('div')
.first('label').should('have.css', 'display', 'none')
})

it('filters out the layer on map move after it is unchecked', function() {
cy.get('div#justiceMap.layers-sub-list.collapse.show').children('div')
.last('label').click()
.find('input[type="checkbox"]').should('not.be.checked')
cy.window().its('map').invoke('setView',[43.00, -85.00], 3)
cy.wait(300)
cy.get('#groupName-justiceMap').should('have.css', 'display', 'none')
cy.get('div#justiceMap.layers-sub-list.collapse.show').children('div')
.last('label').should('have.css', 'display', 'none')
})
})
104 changes: 82 additions & 22 deletions dist/LeafletEnvironmentalLayers.js
Original file line number Diff line number Diff line change
Expand Up @@ -26413,8 +26413,13 @@ L.GeoJSON.FracTrackerMobile = L.GeoJSON.extend(
},

onAdd: function(map) {
map.on('moveend', this.requestData, this);
var info = require('./info.json');
this._map = map;
map.on('moveend', function() {
if(this._map && this._map.getZoom() > info.fracTrackerMobile.extents.minZoom - 1) {
this.requestData();
}
}, this);
this.requestData();
},

Expand Down Expand Up @@ -26505,7 +26510,7 @@ L.geoJSON.fracTrackerMobile = function(options) {
return new L.GeoJSON.FracTrackerMobile(options);
};

},{}],12:[function(require,module,exports){
},{"./info.json":13}],12:[function(require,module,exports){
L.LayerGroup.IndigenousLayers = L.LayerGroup.extend(

{
Expand All @@ -26524,8 +26529,13 @@ L.LayerGroup.IndigenousLayers = L.LayerGroup.extend(
},

onAdd: function(map) {
map.on('moveend', this.requestData, this);
var info = require('./info.json');
this._map = map;
map.on('moveend', function() {
if(this._map && this._map.getZoom() > info.indigenousLands.extents.minZoom - 1) {
this.requestData();
}
}, this);
this.requestData();
},

Expand Down Expand Up @@ -26642,7 +26652,7 @@ L.layerGroup.indigenousLayers = function(name, options) {
return new L.LayerGroup.IndigenousLayers(name, options);
};

},{}],13:[function(require,module,exports){
},{"./info.json":13}],13:[function(require,module,exports){
module.exports={
"aqicnLayer": {
"name": "Air Quality Index",
Expand Down Expand Up @@ -27000,9 +27010,25 @@ L.LayerGroup.LayerCode = L.LayerGroup.extend(
},

onAdd: function(map) {
map.on('moveend', this.requestData, this);
var info = require('./info.json');
this._map = map;
this.requestData();
switch(this.layer) {
case this.layer:
if (this.layer === 'fractracker' || this.layer === 'skytruth' ||
this.layer === 'odorreport' || this.layer === 'mapknitter') {
map.on('moveend', function() {
if(this._map && this._map.getZoom() > info[this.layer].extents.minZoom - 1) {
this.requestData();
}
}, this);
}
default:
if (this.layer === 'luftdaten' || this.layer === 'openaq' ||
this.layer === 'opensense' || this.layer === 'purpleairmarker') {
map.on('moveend', this.requestData, this);
}
this.requestData();
}
},

onRemove: function(map) {
Expand Down Expand Up @@ -29578,8 +29604,13 @@ L.LayerGroup.ToxicReleaseLayer = L.LayerGroup.extend(
},

onAdd: function(map) {
map.on('moveend', this.requestData, this);
var info = require('./info.json');
this._map = map;
map.on('moveend', function() {
if(this._map && this._map.getZoom() > info.toxicReleaseLayer.extents.minZoom - 1) {
this.requestData();
}
}, this);
this.requestData();
},

Expand Down Expand Up @@ -30236,6 +30267,8 @@ L.Control.LayersBrowser = L.Control.Layers.extend({
baseLayersCount += !obj.overlay ? 1 : 0;
}

this._showGroupTitle(); // Show group title when atleast one of its layers is active

map.on('moveend', function() {
if(this.options.newLayers.length > 0) {
this._layersLink.style.marginLeft = '2.9em';
Expand All @@ -30246,6 +30279,8 @@ L.Control.LayersBrowser = L.Control.Layers.extend({
this._alertBadge.style.display = 'none';
this._alertBadge.innerHTML = '';
}

this._showGroupTitle(); // Show group title when atleast one of its layers is active
}, this);

// Hide base layers section if there's only one layer.
Expand Down Expand Up @@ -30395,6 +30430,7 @@ L.Control.LayersBrowser = L.Control.Layers.extend({
groupName.innerHTML = elements.name;

var titleHolder = document.createElement('div');
titleHolder.id = 'groupName-' + obj.group;
titleHolder.className = 'clearfix layer-info-container';
titleHolder.appendChild(layerGroup);
layerGroup.appendChild(chevron);
Expand All @@ -30406,7 +30442,9 @@ L.Control.LayersBrowser = L.Control.Layers.extend({

var separator = this._createSeparator();

this._hideOutOfBounds(obj, [titleHolder, separator]);
if(this._grpTitleVisible && !this._grpTitleVisible[obj.group]) { // Hide group title only if none of its layers are active
this._hideOutOfBounds(obj, [titleHolder, separator]);
}

var container = obj.overlay ? this._overlaysList : this._baseLayersList;
container.appendChild(titleHolder);
Expand Down Expand Up @@ -30523,9 +30561,16 @@ L.Control.LayersBrowser = L.Control.Layers.extend({
});
},

_hideElements: function(obj, data, layerName, elements, removeLayer) {
/**
*
* @param {Object} obj - layer object
* @param {Object} data - layer information from info.json
* @param {string} layerName
* @param {Object[]} elements - Reference to DOM elements
* @param {boolean} isNotGlobal - true if the layer passed in is not a globally available layer
*/
_hideElements: function(obj, data, layerName, elements, isNotGlobal) {
var map = this._map;
var removeFrmMap = removeLayer;
var currentBounds = map.getBounds();
var currentZoom = map.getZoom();
var bounds;
Expand All @@ -30534,35 +30579,50 @@ L.Control.LayersBrowser = L.Control.Layers.extend({
bounds = data.extents && data.extents.bounds && L.latLngBounds(data.extents.bounds);
zoom = data.extents && data.extents.minZoom && data.extents.minZoom;
for(var i in elements) {
if((bounds && !bounds.intersects(currentBounds) && map.hasLayer(layerName) && removeFrmMap) ||
( zoom && (currentZoom < zoom) && map.hasLayer(layerName) && removeFrmMap)) {
elements[i].style.display = 'none';
// Remove layer from map if active
map.removeLayer(layerName);
} else if((bounds && !bounds.intersects(currentBounds)) || (zoom && (currentZoom < zoom))) {
if((bounds && !bounds.intersects(currentBounds) && !map.hasLayer(layerName)) ||
( zoom && (currentZoom < zoom) && !map.hasLayer(layerName))) {
elements[i].style.display = 'none';
this._existingLayers(obj, false, removeFrmMap);
this._existingLayers(obj, false, isNotGlobal);
} else if(obj.group) {
this._grpTitleVisible = this._grpTitleVisible || {};
this._grpTitleVisible[obj.group] = true; // Keep track of group titles to be visible when its layers are active
elements[i].style.display = 'block';
this._existingLayers(obj, true, isNotGlobal);
} else {
elements[i].style.display = 'block';
this._existingLayers(obj, true, removeFrmMap);
this._existingLayers(obj, true, isNotGlobal);
}
};
};
},

_existingLayers: function(obj, doesExist, isInitialized) {
if(doesExist && isInitialized && !this.options.existingLayers[obj.name]) { // Check if there is a new layer in current bounds
_showGroupTitle: function() {
for(var i in this._grpTitleVisible) {
if(this._grpTitleVisible[i]) {
var groupName = 'groupName-' + i;
var grpHolder = document.getElementById(groupName);
var grpSelector = grpHolder && grpHolder.nextElementSibling;
if(grpHolder) {
grpHolder.style.display = 'block';
grpSelector.style.display = 'block';
}
}
}
this._grpTitleVisible = {}; // Reset list of group titles that need to be visible
},

_existingLayers: function(obj, doesExist, isNotGlobal) {
if(doesExist && isNotGlobal && !this.options.existingLayers[obj.name]) { // Check if there is a new layer in current bounds
this.options.newLayers = [...this.options.newLayers, obj.name];
this.options.existingLayers[obj.name] = true;
} else if(doesExist) {
this.options.existingLayers[obj.name] = true; // layer exists upon inititalization
} else if(isInitialized && this.options.existingLayers[obj.name]) { // Remove from new layers if the layer no longer exists within current bounds
} else if(isNotGlobal && this.options.existingLayers[obj.name]) { // Remove from new layers if the layer no longer exists within current bounds
this.options.newLayers = this.options.newLayers.filter(layer => layer !== obj.name);
this.options.existingLayers[obj.name] = false;
} else {
this.options.existingLayers[obj.name] = false; // layer does not exist upon inititalization
}

},

_getLayerData: function(obj) {
Expand Down
6 changes: 6 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"include": [
"./node_modules/cypress",
"cypress/**/*.js"
]
}
Loading

0 comments on commit 43a11e3

Please sign in to comment.