UNPKG

ol-layerlist

Version:

Layer switcher control for OpenLayers v3/v4/v5

369 lines (353 loc) 15.3 kB
describe('ol.control.LayerSwitcher', function() { var map, target, switcher; beforeEach(function() { target = document.createElement('div'); document.body.appendChild(target); switcher = new ol.control.LayerSwitcher(); map = new ol.Map({ target: target, layers: [ new ol.layer.Group({ title: 'Base', layers: [ new ol.layer.Tile({ title: 'Foo', type: 'base', source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }), new ol.layer.Tile({ title: 'Too', type: 'base', source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }) ] }), // Combined base group new ol.layer.Group({ title: 'Combined-Base-Group', type: 'base', combine: true, layers: [ new ol.layer.Tile({ source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }), new ol.layer.Tile({ source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }) ] }), // Combined overlay group new ol.layer.Group({ title: 'Combined-Overlay-Group', type: 'overlay', combine: true, layers: [ new ol.layer.Tile({ source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }), new ol.layer.Tile({ source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }) ] }), // Group with no title (group and it's children should be ignored) new ol.layer.Group({ layers: [ new ol.layer.Tile({ title: 'Never shown', source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }), new ol.layer.Tile({ source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }) ] }), new ol.layer.Tile({ title: 'Bar', minResolution: 1000, maxResolution: 5000, source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }), // Layer with no title (should be ignored) new ol.layer.Tile({ source: new ol.source.TileDebug({ projection: 'EPSG:3857', tileGrid: ol.tilegrid.createXYZ({ maxZoom: 22 }) }) }) ], controls: [switcher] }); }); afterEach(function() { document.body.removeChild(target); switcher = null; map = null; target = null; }); describe('DOM creation', function() { it('creates the expected DOM elements', function() { expect(jQuery('.layer-switcher').length).to.be(1); }); }); describe('Show and hide', function() { it('is initially hidden', function() { expect(jQuery('.layer-switcher').hasClass('.shown')).to.be(false); expect(jQuery('.layer-switcher .panel:visible').length).to.be(0); }); it('is shown on button click', function() { jQuery('.layer-switcher button').click(); expect(jQuery('.layer-switcher.shown').length).to.be(1); expect(jQuery('.layer-switcher .panel:visible').length).to.be(1); }); it('is hidden on map click', function() { jQuery('#map').click(); expect(jQuery('.layer-switcher').hasClass('.shown')).to.be(false); expect(jQuery('.layer-switcher .panel:visible').length).to.be(0); }); }); describe('Layer list', function() { it('displays all layers with a title in reverse order', function() { switcher.showPanel(); var titles = jQuery('.layer-switcher label').map(function() { return jQuery(this).text(); }).get(); expect(titles).to.eql(['Bar', 'Combined-Overlay-Group', 'Combined-Base-Group', 'Base', 'Too', 'Foo']); }); it('only displays layers with a title', function() { switcher.showPanel(); var elmTitles = jQuery('.layer-switcher label').map(function() { return jQuery(this).text(); }).get(); var lyrsWithTitle = shownLyrs(map.getLayerGroup()); expect(lyrsWithTitle.length).to.eql(elmTitles.length); }); it('don\'t display layers without a title', function() { switcher.showPanel(); // This is basically to ensure that our test layers include layers without a title var lyrsWithoutTitle = _.filter(allLyrs(map.getLayerGroup()), function(lyr) {return !lyr.get('title')}); expect(lyrsWithoutTitle.length).not.to.equal(0); }); it('displays normal layers as checkbox', function() { switcher.showPanel(); var titles = jQuery('.layer-switcher input[type=checkbox]').siblings('label').map(function() { return jQuery(this).text(); }).get(); expect(titles).to.eql(['Bar', 'Combined-Overlay-Group']); }); it('greys out normal layer title labels when outside of layer resolution', function() { map.getView().setResolution(6000); switcher.showPanel(); var layerResTooHigh = jQuery('.layer-switcher label.disabled').map(function() { return jQuery(this).text(); }).get(); map.getView().setResolution(500); var layerResTooLow = jQuery('.layer-switcher label.disabled').map(function() { return jQuery(this).text(); }).get(); expect([layerResTooHigh, layerResTooLow]).to.eql([['Bar'], ['Bar']]); }); it('displays base layers as radio buttons', function() { switcher.showPanel(); var titles = jQuery('.layer-switcher input[type=radio]').siblings('label').map(function() { return jQuery(this).text(); }).get(); expect(titles).to.eql(['Combined-Base-Group', 'Too', 'Foo']); }); it('should display uncombined groups without an input', function() { switcher.showPanel(); var groups = jQuery('.layer-switcher label:not([for])') var titles = groups.map(function() { return jQuery(this).text(); }).get(); expect(titles).to.eql(['Base']); expect(groups.siblings('input').length).to.be(0); }); it('should display combined groups with an input', function () { switcher.showPanel(); var titles = jQuery('.layer-switcher label[for]').map(function() { return jQuery(this).text(); }).get(); expect(titles).to.contain('Combined-Base-Group'); expect(titles).to.contain('Combined-Overlay-Group'); }); it('should display combined groups without sub layers', function () { switcher.showPanel(); var groups = jQuery('.layer-switcher label[for]') expect(groups.siblings('ul').length).to.be(0); }); }); describe('Overlay layer visibility', function() { it('Toggles overlay layer visibility on click', function() { switcher.showPanel(); var bar = getLayerByTitle('Bar'); bar.setVisible(true); jQuery('.layer-switcher label:contains("Bar")').siblings('input').click(); expect(bar.getVisible()).to.be(false); expect(jQuery('.layer-switcher label:contains("Bar")').siblings('input').get(0).checked).to.be(bar.getVisible()); bar.setVisible(false) jQuery('.layer-switcher label:contains("Bar")').siblings('input').click(); expect(bar.getVisible()).to.be(true); expect(jQuery('.layer-switcher label:contains("Bar")').siblings('input').get(0).checked).to.be(bar.getVisible()); }); }); describe('Base layer visibility', function() { it('Only one base layer is visible after renderPanel', function() { var foo = getLayerByTitle('Foo'); var too = getLayerByTitle('Too'); var cbg = getLayerByTitle('Combined-Base-Group'); var baseLayers = [foo, too, cbg]; // Enable all base layers _.forEach(baseLayers, function (l) { l.setVisible(true); }); switcher.renderPanel(); var visibleBaseLayerCount = _.countBy(baseLayers, function (l){ return l.getVisible(); }); expect(visibleBaseLayerCount.true).to.be(1); }); it('Only top most base layer is visible after renderPanel if more than one is visible', function() { var foo = getLayerByTitle('Foo'); var too = getLayerByTitle('Too'); var cbg = getLayerByTitle('Combined-Base-Group'); var baseLayers = [foo, too, cbg]; // Enable all base layers _.forEach(baseLayers, function (l) { l.setVisible(true); }); switcher.renderPanel(); expect(cbg.getVisible()).to.be(true); }); it('Clicking on unchecked base layer shows it', function() { var too = getLayerByTitle('Too'); too.setVisible(false); switcher.renderPanel(); jQuery('.layer-switcher label:contains("Too")').siblings('input').click(); expect(too.getVisible()).to.be(true); expect(jQuery('.layer-switcher label:contains("Too")').siblings('input').get(0).checked).to.be(true); }); it('Clicking on checked base layer does not change base layer', function() { var foo = getLayerByTitle('Foo'); foo.setVisible(true); switcher.renderPanel(); jQuery('.layer-switcher label:contains("Foo")').siblings('input').click(); expect(foo.getVisible()).to.be(true); expect(jQuery('.layer-switcher label:contains("Foo")').siblings('input').get(0).checked).to.be(true); }); }); describe('Removes cleanly', function() { it('Removes cleanly when ol.Map#removeControl is called', function() { map.removeControl(switcher); }); }); /** * Returns the title of a given layer or null if lyr is falsey */ function lyrTitle(lyr) { return (lyr) ? lyr.get('title') : null; } /** * Returns the Layer instance that has the given title */ function getLayerByTitle(title) { var layer = null; ol.control.LayerSwitcher.forEachRecursive(map, function(lyr) { if (lyr.get('title') && lyr.get('title') === title) { layer = lyr; return; } }); return layer; } /** * Return a flattened Array of all layers regardless including those not * shown by the LayerSwitcher */ function allLyrs(lyrs) { return flatten(lyrs, function (lyr) { return (lyr.getLayers) ? lyr.getLayers().getArray() : lyr; }); } /** * Return a flattened Array of only those layers that the LayerSwitcher * should show */ function shownLyrs(lyrs) { // Pass in the Array from the root LayerGroup as it doesn't have a // title but we don't want to filter out all layers lyrs = lyrs.getLayers().getArray(); var flat = flatten(lyrs, function (lyr) { // Return a Groups layer array only if the group has a title // otherwise just return the group so that it's children will be // skipped return (lyr.getLayers && lyr.get('title')) ? lyr.getLayers().getArray() : lyr; }); // Only return layers with a title return _.filter(flat, lyrTitle); } /** * Flattens a given nested collection using the provided function getArray * to get an Array of the collections children. */ function flatten(srcCollection, getArray) { getArray = getArray || function (item) {return item}; var src = getArray(srcCollection), dest = []; for (var i = 0, item; i < src.length; i++) { item = src[i]; dest = dest.concat(item); if (_.isArray(getArray(item))) { dest = dest.concat(flatten(item, getArray)); } } return dest; } });