In addition to using const and let, this also upgrades our linter config and removes lint (mostly whitespace).
663 lines
19 KiB
JavaScript
663 lines
19 KiB
JavaScript
import Feature from '../../../src/ol/Feature.js';
|
|
import Map from '../../../src/ol/Map.js';
|
|
import MapEvent from '../../../src/ol/MapEvent.js';
|
|
import Overlay from '../../../src/ol/Overlay.js';
|
|
import View from '../../../src/ol/View.js';
|
|
import LineString from '../../../src/ol/geom/LineString.js';
|
|
import _ol_has_ from '../../../src/ol/has.js';
|
|
import {defaults as defaultInteractions} from '../../../src/ol/interaction.js';
|
|
import DoubleClickZoom from '../../../src/ol/interaction/DoubleClickZoom.js';
|
|
import Interaction from '../../../src/ol/interaction/Interaction.js';
|
|
import MouseWheelZoom from '../../../src/ol/interaction/MouseWheelZoom.js';
|
|
import PinchZoom from '../../../src/ol/interaction/PinchZoom.js';
|
|
import TileLayer from '../../../src/ol/layer/Tile.js';
|
|
import VectorLayer from '../../../src/ol/layer/Vector.js';
|
|
import IntermediateCanvasRenderer from '../../../src/ol/renderer/canvas/IntermediateCanvas.js';
|
|
import VectorSource from '../../../src/ol/source/Vector.js';
|
|
import XYZ from '../../../src/ol/source/XYZ.js';
|
|
|
|
describe('ol.Map', function() {
|
|
|
|
describe('constructor', function() {
|
|
it('creates a new map', function() {
|
|
const map = new Map({});
|
|
expect(map).to.be.a(Map);
|
|
});
|
|
|
|
it('creates a set of default interactions', function() {
|
|
const map = new Map({});
|
|
const interactions = map.getInteractions();
|
|
const length = interactions.getLength();
|
|
expect(length).to.be.greaterThan(0);
|
|
|
|
for (let i = 0; i < length; ++i) {
|
|
expect(interactions.item(i).getMap()).to.be(map);
|
|
}
|
|
});
|
|
|
|
it('creates the viewport', function() {
|
|
const map = new Map({});
|
|
const viewport = map.getViewport();
|
|
const className = 'ol-viewport' + (_ol_has_.TOUCH ? ' ol-touch' : '');
|
|
expect(viewport.className).to.be(className);
|
|
});
|
|
|
|
it('creates the overlay containers', function() {
|
|
const map = new Map({});
|
|
const container = map.getOverlayContainer();
|
|
expect(container.className).to.be('ol-overlaycontainer');
|
|
|
|
const containerStop = map.getOverlayContainerStopEvent();
|
|
expect(containerStop.className).to.be('ol-overlaycontainer-stopevent');
|
|
});
|
|
|
|
});
|
|
|
|
describe('#addLayer()', function() {
|
|
it('adds a layer to the map', function() {
|
|
const map = new Map({});
|
|
const layer = new TileLayer();
|
|
map.addLayer(layer);
|
|
|
|
expect(map.getLayers().item(0)).to.be(layer);
|
|
});
|
|
|
|
it('throws if a layer is added twice', function() {
|
|
const map = new Map({});
|
|
const layer = new TileLayer();
|
|
map.addLayer(layer);
|
|
|
|
const call = function() {
|
|
map.addLayer(layer);
|
|
};
|
|
expect(call).to.throwException();
|
|
});
|
|
});
|
|
|
|
describe('#addInteraction()', function() {
|
|
it('adds an interaction to the map', function() {
|
|
const map = new Map({});
|
|
const interaction = new Interaction({});
|
|
|
|
const before = map.getInteractions().getLength();
|
|
map.addInteraction(interaction);
|
|
const after = map.getInteractions().getLength();
|
|
expect(after).to.be(before + 1);
|
|
expect(interaction.getMap()).to.be(map);
|
|
});
|
|
});
|
|
|
|
describe('#removeInteraction()', function() {
|
|
it('removes an interaction from the map', function() {
|
|
const map = new Map({});
|
|
const interaction = new Interaction({});
|
|
|
|
const before = map.getInteractions().getLength();
|
|
map.addInteraction(interaction);
|
|
|
|
map.removeInteraction(interaction);
|
|
expect(map.getInteractions().getLength()).to.be(before);
|
|
|
|
expect(interaction.getMap()).to.be(null);
|
|
});
|
|
});
|
|
|
|
describe('movestart/moveend event', function() {
|
|
|
|
let target, view, map;
|
|
|
|
beforeEach(function() {
|
|
target = document.createElement('div');
|
|
|
|
const style = target.style;
|
|
style.position = 'absolute';
|
|
style.left = '-1000px';
|
|
style.top = '-1000px';
|
|
style.width = '360px';
|
|
style.height = '180px';
|
|
document.body.appendChild(target);
|
|
|
|
view = new View({
|
|
projection: 'EPSG:4326'
|
|
});
|
|
map = new Map({
|
|
target: target,
|
|
view: view,
|
|
layers: [
|
|
new TileLayer({
|
|
source: new XYZ({
|
|
url: '#{x}/{y}/{z}'
|
|
})
|
|
})
|
|
]
|
|
});
|
|
});
|
|
|
|
afterEach(function() {
|
|
map.dispose();
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('are fired only once after view changes', function(done) {
|
|
const center = [10, 20];
|
|
const zoom = 3;
|
|
let startCalls = 0;
|
|
let endCalls = 0;
|
|
map.on('movestart', function() {
|
|
++startCalls;
|
|
expect(startCalls).to.be(1);
|
|
});
|
|
map.on('moveend', function() {
|
|
++endCalls;
|
|
expect(endCalls).to.be(1);
|
|
expect(view.getCenter()).to.eql(center);
|
|
expect(view.getZoom()).to.be(zoom);
|
|
window.setTimeout(done, 1000);
|
|
});
|
|
|
|
view.setCenter(center);
|
|
view.setZoom(zoom);
|
|
});
|
|
|
|
it('are fired in sequence', function(done) {
|
|
view.setCenter([0, 0]);
|
|
view.setResolution(0.703125);
|
|
map.renderSync();
|
|
const center = [10, 20];
|
|
const zoom = 3;
|
|
const calls = [];
|
|
map.on('movestart', function(e) {
|
|
calls.push('start');
|
|
expect(calls).to.eql(['start']);
|
|
expect(e.frameState.viewState.center).to.eql([0, 0]);
|
|
expect(e.frameState.viewState.resolution).to.be(0.703125);
|
|
});
|
|
map.on('moveend', function() {
|
|
calls.push('end');
|
|
expect(calls).to.eql(['start', 'end']);
|
|
expect(view.getCenter()).to.eql(center);
|
|
expect(view.getZoom()).to.be(zoom);
|
|
done();
|
|
});
|
|
|
|
view.setCenter(center);
|
|
view.setZoom(zoom);
|
|
});
|
|
|
|
});
|
|
|
|
describe('#getFeaturesAtPixel', function() {
|
|
|
|
let target, map;
|
|
beforeEach(function() {
|
|
target = document.createElement('div');
|
|
target.style.width = target.style.height = '100px';
|
|
document.body.appendChild(target);
|
|
map = new Map({
|
|
target: target,
|
|
layers: [new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [new Feature(new LineString([[-50, 0], [50, 0]]))]
|
|
})
|
|
})],
|
|
view: new View({
|
|
center: [0, 0],
|
|
zoom: 17
|
|
})
|
|
});
|
|
map.renderSync();
|
|
});
|
|
afterEach(function() {
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('returns null if no feature was found', function() {
|
|
const features = map.getFeaturesAtPixel([0, 0]);
|
|
expect(features).to.be(null);
|
|
});
|
|
|
|
it('returns an array of found features', function() {
|
|
const features = map.getFeaturesAtPixel([50, 50]);
|
|
expect(features).to.be.an(Array);
|
|
expect(features[0]).to.be.an(Feature);
|
|
});
|
|
|
|
it('returns an array of found features with declutter: true', function() {
|
|
const layer = map.getLayers().item(0);
|
|
map.removeLayer(layer);
|
|
const otherLayer = new VectorLayer({
|
|
declutter: true,
|
|
source: layer.getSource()
|
|
});
|
|
map.addLayer(otherLayer);
|
|
map.renderSync();
|
|
const features = map.getFeaturesAtPixel([50, 50]);
|
|
expect(features).to.be.an(Array);
|
|
expect(features[0]).to.be.a(Feature);
|
|
});
|
|
|
|
it('respects options', function() {
|
|
const otherLayer = new VectorLayer({
|
|
source: new VectorSource
|
|
});
|
|
map.addLayer(otherLayer);
|
|
const features = map.getFeaturesAtPixel([50, 50], {
|
|
layerFilter: function(layer) {
|
|
return layer == otherLayer;
|
|
}
|
|
});
|
|
expect(features).to.be(null);
|
|
});
|
|
|
|
});
|
|
|
|
describe('#forEachLayerAtPixel()', function() {
|
|
|
|
let target, map, original, log;
|
|
|
|
beforeEach(function(done) {
|
|
log = [];
|
|
original = IntermediateCanvasRenderer.prototype.forEachLayerAtCoordinate;
|
|
IntermediateCanvasRenderer.prototype.forEachLayerAtCoordinate = function(coordinate) {
|
|
log.push(coordinate.slice());
|
|
};
|
|
|
|
target = document.createElement('div');
|
|
const style = target.style;
|
|
style.position = 'absolute';
|
|
style.left = '-1000px';
|
|
style.top = '-1000px';
|
|
style.width = '360px';
|
|
style.height = '180px';
|
|
document.body.appendChild(target);
|
|
|
|
map = new Map({
|
|
target: target,
|
|
view: new View({
|
|
center: [0, 0],
|
|
zoom: 1
|
|
}),
|
|
layers: [
|
|
new TileLayer({
|
|
source: new XYZ()
|
|
}),
|
|
new TileLayer({
|
|
source: new XYZ()
|
|
}),
|
|
new TileLayer({
|
|
source: new XYZ()
|
|
})
|
|
]
|
|
});
|
|
|
|
map.once('postrender', function() {
|
|
done();
|
|
});
|
|
});
|
|
|
|
afterEach(function() {
|
|
IntermediateCanvasRenderer.prototype.forEachLayerAtCoordinate = original;
|
|
map.dispose();
|
|
document.body.removeChild(target);
|
|
log = null;
|
|
});
|
|
|
|
it('calls each layer renderer with the same coordinate', function() {
|
|
const pixel = [10, 20];
|
|
map.forEachLayerAtPixel(pixel, function() {});
|
|
expect(log.length).to.equal(3);
|
|
expect(log[0].length).to.equal(2);
|
|
expect(log[0]).to.eql(log[1]);
|
|
expect(log[1]).to.eql(log[2]);
|
|
});
|
|
|
|
});
|
|
|
|
describe('#render()', function() {
|
|
|
|
let target, map;
|
|
|
|
beforeEach(function() {
|
|
target = document.createElement('div');
|
|
const style = target.style;
|
|
style.position = 'absolute';
|
|
style.left = '-1000px';
|
|
style.top = '-1000px';
|
|
style.width = '360px';
|
|
style.height = '180px';
|
|
document.body.appendChild(target);
|
|
map = new Map({
|
|
target: target,
|
|
view: new View({
|
|
projection: 'EPSG:4326',
|
|
center: [0, 0],
|
|
resolution: 1
|
|
})
|
|
});
|
|
});
|
|
|
|
afterEach(function() {
|
|
map.dispose();
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('is called when the view.changed() is called', function() {
|
|
const view = map.getView();
|
|
|
|
const spy = sinon.spy(map, 'render');
|
|
view.changed();
|
|
expect(spy.callCount).to.be(1);
|
|
});
|
|
|
|
it('is not called on view changes after the view has been removed', function() {
|
|
const view = map.getView();
|
|
map.setView(null);
|
|
|
|
const spy = sinon.spy(map, 'render');
|
|
view.changed();
|
|
expect(spy.callCount).to.be(0);
|
|
});
|
|
|
|
it('calls renderFrame_ and results in an postrender event', function(done) {
|
|
|
|
const spy = sinon.spy(map, 'renderFrame_');
|
|
map.render();
|
|
map.once('postrender', function(event) {
|
|
expect(event).to.be.a(MapEvent);
|
|
expect(typeof spy.firstCall.args[0]).to.be('number');
|
|
spy.restore();
|
|
const frameState = event.frameState;
|
|
expect(frameState).not.to.be(null);
|
|
done();
|
|
});
|
|
|
|
});
|
|
|
|
it('uses the same render frame for subsequent calls', function(done) {
|
|
map.render();
|
|
const id1 = map.animationDelayKey_;
|
|
let id2 = null;
|
|
map.once('postrender', function() {
|
|
expect(id2).to.be(id1);
|
|
done();
|
|
});
|
|
map.render();
|
|
id2 = map.animationDelayKey_;
|
|
});
|
|
|
|
it('creates a new render frame after renderSync()', function(done) {
|
|
let id2 = null;
|
|
map.render();
|
|
const id1 = map.animationDelayKey_;
|
|
map.once('postrender', function() {
|
|
expect(id2).to.not.be(id1);
|
|
done();
|
|
});
|
|
map.renderSync();
|
|
id2 = map.animationDelayKey_;
|
|
});
|
|
|
|
it('results in an postrender event (for zero height map)', function(done) {
|
|
target.style.height = '0px';
|
|
map.updateSize();
|
|
|
|
map.render();
|
|
map.once('postrender', function(event) {
|
|
expect(event).to.be.a(MapEvent);
|
|
const frameState = event.frameState;
|
|
expect(frameState).to.be(null);
|
|
done();
|
|
});
|
|
|
|
});
|
|
|
|
it('results in an postrender event (for zero width map)', function(done) {
|
|
target.style.width = '0px';
|
|
map.updateSize();
|
|
|
|
map.render();
|
|
map.once('postrender', function(event) {
|
|
expect(event).to.be.a(MapEvent);
|
|
const frameState = event.frameState;
|
|
expect(frameState).to.be(null);
|
|
done();
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
describe('dispose', function() {
|
|
let map;
|
|
|
|
beforeEach(function() {
|
|
map = new Map({
|
|
target: document.createElement('div')
|
|
});
|
|
});
|
|
|
|
it('removes the viewport from its parent', function() {
|
|
map.dispose();
|
|
expect(map.getViewport().parentNode).to.be(null);
|
|
});
|
|
|
|
it('removes window listeners', function() {
|
|
map.dispose();
|
|
expect(map.handleResize_).to.be(undefined);
|
|
});
|
|
});
|
|
|
|
describe('#setTarget', function() {
|
|
let map;
|
|
|
|
beforeEach(function() {
|
|
map = new Map({
|
|
target: document.createElement('div')
|
|
});
|
|
expect(map.handleResize_).to.be.ok();
|
|
});
|
|
|
|
describe('call setTarget with null', function() {
|
|
it('unregisters the viewport resize listener', function() {
|
|
map.setTarget(null);
|
|
expect(map.handleResize_).to.be(undefined);
|
|
});
|
|
});
|
|
|
|
describe('call setTarget with an element', function() {
|
|
it('registers a viewport resize listener', function() {
|
|
map.setTarget(null);
|
|
map.setTarget(document.createElement('div'));
|
|
expect(map.handleResize_).to.be.ok();
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe('create interactions', function() {
|
|
|
|
let options;
|
|
|
|
beforeEach(function() {
|
|
options = {
|
|
altShiftDragRotate: false,
|
|
doubleClickZoom: false,
|
|
keyboard: false,
|
|
mouseWheelZoom: false,
|
|
shiftDragZoom: false,
|
|
dragPan: false,
|
|
pinchRotate: false,
|
|
pinchZoom: false
|
|
};
|
|
});
|
|
|
|
describe('create mousewheel interaction', function() {
|
|
it('creates mousewheel interaction', function() {
|
|
options.mouseWheelZoom = true;
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.getLength()).to.eql(1);
|
|
expect(interactions.item(0)).to.be.a(MouseWheelZoom);
|
|
expect(interactions.item(0).constrainResolution_).to.eql(false);
|
|
expect(interactions.item(0).useAnchor_).to.eql(true);
|
|
interactions.item(0).setMouseAnchor(false);
|
|
expect(interactions.item(0).useAnchor_).to.eql(false);
|
|
});
|
|
});
|
|
|
|
describe('create pinchZoom interaction', function() {
|
|
it('creates pinchZoom interaction', function() {
|
|
options.pinchZoom = true;
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.getLength()).to.eql(1);
|
|
expect(interactions.item(0)).to.be.a(PinchZoom);
|
|
expect(interactions.item(0).constrainResolution_).to.eql(false);
|
|
});
|
|
});
|
|
|
|
describe('set constrainResolution option', function() {
|
|
it('set constrainResolution option', function() {
|
|
options.pinchZoom = true;
|
|
options.mouseWheelZoom = true;
|
|
options.constrainResolution = true;
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.getLength()).to.eql(2);
|
|
expect(interactions.item(0)).to.be.a(PinchZoom);
|
|
expect(interactions.item(0).constrainResolution_).to.eql(true);
|
|
expect(interactions.item(1)).to.be.a(MouseWheelZoom);
|
|
expect(interactions.item(1).constrainResolution_).to.eql(true);
|
|
});
|
|
});
|
|
|
|
describe('create double click interaction', function() {
|
|
|
|
beforeEach(function() {
|
|
options.doubleClickZoom = true;
|
|
});
|
|
|
|
describe('default zoomDelta', function() {
|
|
it('create double click interaction with default delta', function() {
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.getLength()).to.eql(1);
|
|
expect(interactions.item(0)).to.be.a(DoubleClickZoom);
|
|
expect(interactions.item(0).delta_).to.eql(1);
|
|
});
|
|
});
|
|
|
|
describe('set zoomDelta', function() {
|
|
it('create double click interaction with set delta', function() {
|
|
options.zoomDelta = 7;
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.getLength()).to.eql(1);
|
|
expect(interactions.item(0)).to.be.a(DoubleClickZoom);
|
|
expect(interactions.item(0).delta_).to.eql(7);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#getEventPixel', function() {
|
|
|
|
let target;
|
|
|
|
beforeEach(function() {
|
|
target = document.createElement('div');
|
|
target.style.position = 'absolute';
|
|
target.style.top = '10px';
|
|
target.style.left = '20px';
|
|
target.style.width = '800px';
|
|
target.style.height = '400px';
|
|
|
|
document.body.appendChild(target);
|
|
});
|
|
afterEach(function() {
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('works with touchend events', function() {
|
|
|
|
const map = new Map({
|
|
target: target
|
|
});
|
|
|
|
const browserEvent = {
|
|
type: 'touchend',
|
|
target: target,
|
|
changedTouches: [{
|
|
clientX: 100,
|
|
clientY: 200
|
|
}]
|
|
};
|
|
const position = map.getEventPixel(browserEvent);
|
|
// 80 = clientX - target.style.left
|
|
expect(position[0]).to.eql(80);
|
|
// 190 = clientY - target.style.top
|
|
expect(position[1]).to.eql(190);
|
|
});
|
|
});
|
|
|
|
describe('#getOverlayById()', function() {
|
|
let target, map, overlay, overlay_target;
|
|
|
|
beforeEach(function() {
|
|
target = document.createElement('div');
|
|
const style = target.style;
|
|
style.position = 'absolute';
|
|
style.left = '-1000px';
|
|
style.top = '-1000px';
|
|
style.width = '360px';
|
|
style.height = '180px';
|
|
document.body.appendChild(target);
|
|
map = new Map({
|
|
target: target,
|
|
view: new View({
|
|
projection: 'EPSG:4326',
|
|
center: [0, 0],
|
|
resolution: 1
|
|
})
|
|
});
|
|
overlay_target = document.createElement('div');
|
|
});
|
|
|
|
afterEach(function() {
|
|
map.removeOverlay(overlay);
|
|
map.dispose();
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('returns an overlay by id', function() {
|
|
overlay = new Overlay({
|
|
id: 'foo',
|
|
element: overlay_target,
|
|
position: [0, 0]
|
|
});
|
|
map.addOverlay(overlay);
|
|
expect(map.getOverlayById('foo')).to.be(overlay);
|
|
});
|
|
|
|
it('returns null when no overlay is found', function() {
|
|
overlay = new Overlay({
|
|
id: 'foo',
|
|
element: overlay_target,
|
|
position: [0, 0]
|
|
});
|
|
map.addOverlay(overlay);
|
|
expect(map.getOverlayById('bar')).to.be(null);
|
|
});
|
|
|
|
it('returns null after removing overlay', function() {
|
|
overlay = new Overlay({
|
|
id: 'foo',
|
|
element: overlay_target,
|
|
position: [0, 0]
|
|
});
|
|
map.addOverlay(overlay);
|
|
expect(map.getOverlayById('foo')).to.be(overlay);
|
|
map.removeOverlay(overlay);
|
|
expect(map.getOverlayById('foo')).to.be(null);
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|