1374 lines
40 KiB
JavaScript
1374 lines
40 KiB
JavaScript
import Collection from '../../../../src/ol/Collection.js';
|
|
import Control from '../../../../src/ol/control/Control.js';
|
|
import DoubleClickZoom from '../../../../src/ol/interaction/DoubleClickZoom.js';
|
|
import DragPan from '../../../../src/ol/interaction/DragPan.js';
|
|
import Feature from '../../../../src/ol/Feature.js';
|
|
import GeoJSON from '../../../../src/ol/format/GeoJSON.js';
|
|
import ImageLayer from '../../../../src/ol/layer/Image.js';
|
|
import ImageState from '../../../../src/ol/ImageState.js';
|
|
import ImageStatic from '../../../../src/ol/source/ImageStatic.js';
|
|
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
|
import Layer from '../../../../src/ol/layer/Layer.js';
|
|
import LayerGroup from '../../../../src/ol/layer/Group.js';
|
|
import Map from '../../../../src/ol/Map.js';
|
|
import MapBrowserEvent from '../../../../src/ol/MapBrowserEvent.js';
|
|
import MapEvent from '../../../../src/ol/MapEvent.js';
|
|
import MouseWheelZoom from '../../../../src/ol/interaction/MouseWheelZoom.js';
|
|
import Overlay from '../../../../src/ol/Overlay.js';
|
|
import PinchZoom from '../../../../src/ol/interaction/PinchZoom.js';
|
|
import Property from '../../../../src/ol/layer/Property.js';
|
|
import Select from '../../../../src/ol/interaction/Select.js';
|
|
import TileLayer from '../../../../src/ol/layer/Tile.js';
|
|
import TileLayerRenderer from '../../../../src/ol/renderer/canvas/TileLayer.js';
|
|
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
|
import VectorSource from '../../../../src/ol/source/Vector.js';
|
|
import View from '../../../../src/ol/View.js';
|
|
import WebGLPointsLayer from '../../../../src/ol/layer/WebGLPoints.js';
|
|
import XYZ from '../../../../src/ol/source/XYZ.js';
|
|
import {LineString, Point, Polygon} from '../../../../src/ol/geom.js';
|
|
import {TRUE} from '../../../../src/ol/functions.js';
|
|
import {
|
|
clearUserProjection,
|
|
fromLonLat,
|
|
get as getProjection,
|
|
transform,
|
|
useGeographic,
|
|
} from '../../../../src/ol/proj.js';
|
|
import {createXYZ} from '../../../../src/ol/tilegrid.js';
|
|
import {defaults as defaultInteractions} from '../../../../src/ol/interaction.js';
|
|
import {tile as tileStrategy} from '../../../../src/ol/loadingstrategy.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('accepts a promise for view options', (done) => {
|
|
let resolve;
|
|
|
|
const map = new Map({
|
|
view: new Promise((r) => {
|
|
resolve = r;
|
|
}),
|
|
});
|
|
|
|
expect(map.getView()).to.be.a(View);
|
|
expect(map.getView().isDef()).to.be(false);
|
|
|
|
map.once('change:view', () => {
|
|
const view = map.getView();
|
|
expect(view).to.be.a(View);
|
|
expect(view.isDef()).to.be(true);
|
|
expect(view.getCenter()).to.eql([1, 2]);
|
|
expect(view.getZoom()).to.be(3);
|
|
done();
|
|
});
|
|
|
|
resolve({
|
|
center: [1, 2],
|
|
zoom: 3,
|
|
});
|
|
});
|
|
|
|
it('allows the view to be set with a promise later after construction', (done) => {
|
|
const map = new Map({
|
|
view: new View({zoom: 1, center: [0, 0]}),
|
|
});
|
|
|
|
expect(map.getView()).to.be.a(View);
|
|
expect(map.getView().isDef()).to.be(true);
|
|
|
|
let resolve;
|
|
map.setView(
|
|
new Promise((r) => {
|
|
resolve = r;
|
|
})
|
|
);
|
|
|
|
expect(map.getView()).to.be.a(View);
|
|
expect(map.getView().isDef()).to.be(false);
|
|
|
|
map.once('change:view', () => {
|
|
const view = map.getView();
|
|
expect(view).to.be.a(View);
|
|
expect(view.isDef()).to.be(true);
|
|
expect(view.getCenter()).to.eql([1, 2]);
|
|
expect(view.getZoom()).to.be(3);
|
|
done();
|
|
});
|
|
|
|
resolve({
|
|
center: [1, 2],
|
|
zoom: 3,
|
|
});
|
|
});
|
|
|
|
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' + ('ontouchstart' in window ? ' 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');
|
|
});
|
|
|
|
it('calls setMap for controls added by other controls', function () {
|
|
let subSetMapCalled = false;
|
|
class SubControl extends Control {
|
|
setMap(map) {
|
|
super.setMap(map);
|
|
subSetMapCalled = true;
|
|
}
|
|
}
|
|
class MainControl extends Control {
|
|
setMap(map) {
|
|
super.setMap(map);
|
|
map.addControl(
|
|
new SubControl({
|
|
element: document.createElement('div'),
|
|
})
|
|
);
|
|
}
|
|
}
|
|
new Map({
|
|
target: document.createElement('div'),
|
|
controls: [
|
|
new MainControl({
|
|
element: document.createElement('div'),
|
|
}),
|
|
],
|
|
});
|
|
expect(subSetMapCalled).to.be(true);
|
|
});
|
|
});
|
|
|
|
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);
|
|
expect(layer.get(Property.MAP)).to.be(map);
|
|
});
|
|
|
|
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('#removeLayer()', function () {
|
|
it('removes a layer from the map', function () {
|
|
const map = new Map({});
|
|
const layer = new TileLayer();
|
|
map.addLayer(layer);
|
|
|
|
expect(layer.get(Property.MAP)).to.be(map);
|
|
map.removeLayer(layer);
|
|
expect(layer.get(Property.MAP)).to.be(null);
|
|
});
|
|
|
|
it('removes a layer group from the map', function () {
|
|
const map = new Map({});
|
|
const layer = new TileLayer();
|
|
const group = new LayerGroup({layers: [layer]});
|
|
map.addLayer(group);
|
|
expect(layer.get(Property.MAP)).to.be(map);
|
|
|
|
map.removeLayer(group);
|
|
expect(layer.get(Property.MAP)).to.be(null);
|
|
});
|
|
});
|
|
|
|
describe('#setLayerGroup()', function () {
|
|
it('sets the layer group', function () {
|
|
const map = new Map({});
|
|
|
|
const layer = new Layer({});
|
|
const group = new LayerGroup({layers: [layer]});
|
|
map.setLayerGroup(group);
|
|
|
|
expect(map.getLayerGroup()).to.be(group);
|
|
expect(layer.get(Property.MAP)).to.be(map);
|
|
});
|
|
|
|
it('removes the map property from old layers', function () {
|
|
const oldLayer = new Layer({});
|
|
const map = new Map({layers: [oldLayer]});
|
|
expect(oldLayer.get(Property.MAP)).to.be(map);
|
|
|
|
const layer = new Layer({});
|
|
const group = new LayerGroup({layers: [layer]});
|
|
map.setLayerGroup(group);
|
|
|
|
expect(layer.get(Property.MAP)).to.be(map);
|
|
expect(oldLayer.get(Property.MAP)).to.be(null);
|
|
});
|
|
});
|
|
|
|
describe('#getAllLayers()', function () {
|
|
it('returns all layers, also from inside groups', function () {
|
|
const map = new Map({});
|
|
const layer = new TileLayer();
|
|
const group = new LayerGroup({layers: [layer]});
|
|
map.addLayer(group);
|
|
|
|
const allLayers = map.getAllLayers();
|
|
expect(allLayers.length).to.be(1);
|
|
expect(allLayers[0]).to.be(layer);
|
|
});
|
|
});
|
|
|
|
describe('#setLayers()', function () {
|
|
it('adds an array of layers to the map', function () {
|
|
const map = new Map({});
|
|
|
|
const layer0 = new TileLayer();
|
|
const layer1 = new TileLayer();
|
|
map.setLayers([layer0, layer1]);
|
|
|
|
const collection = map.getLayers();
|
|
expect(collection.getLength()).to.be(2);
|
|
expect(collection.item(0)).to.be(layer0);
|
|
expect(collection.item(1)).to.be(layer1);
|
|
expect(layer0.get(Property.MAP)).to.be(map);
|
|
expect(layer1.get(Property.MAP)).to.be(map);
|
|
});
|
|
|
|
it('clears any existing layers', function () {
|
|
const oldLayer = new TileLayer();
|
|
const map = new Map({layers: [oldLayer]});
|
|
expect(oldLayer.get(Property.MAP)).to.be(map);
|
|
|
|
const newLayer1 = new TileLayer();
|
|
const newLayer2 = new TileLayer();
|
|
map.setLayers([newLayer1, newLayer2]);
|
|
expect(newLayer1.get(Property.MAP)).to.be(map);
|
|
expect(newLayer2.get(Property.MAP)).to.be(map);
|
|
expect(oldLayer.get(Property.MAP)).to.be(null);
|
|
|
|
expect(map.getLayers().getLength()).to.be(2);
|
|
});
|
|
|
|
it('also works with collections', function () {
|
|
const map = new Map({});
|
|
|
|
const layer0 = new TileLayer();
|
|
const layer1 = new TileLayer();
|
|
map.setLayers(new Collection([layer0, layer1]));
|
|
|
|
const collection = map.getLayers();
|
|
expect(collection.getLength()).to.be(2);
|
|
expect(collection.item(0)).to.be(layer0);
|
|
expect(collection.item(1)).to.be(layer1);
|
|
});
|
|
});
|
|
|
|
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('rendercomplete event', function () {
|
|
let map;
|
|
beforeEach(function () {
|
|
const target = document.createElement('div');
|
|
target.style.width = '100px';
|
|
target.style.height = '100px';
|
|
document.body.appendChild(target);
|
|
map = new Map({
|
|
target: target,
|
|
layers: [
|
|
new TileLayer({
|
|
opacity: 0.5,
|
|
source: new XYZ({
|
|
url: 'spec/ol/data/osm-{z}-{x}-{y}.png',
|
|
}),
|
|
}),
|
|
new ImageLayer({
|
|
source: new ImageStatic({
|
|
url: 'spec/ol/data/osm-0-0-0.png',
|
|
imageExtent: getProjection('EPSG:3857').getExtent(),
|
|
projection: 'EPSG:3857',
|
|
}),
|
|
}),
|
|
new VectorLayer({
|
|
source: new VectorSource({
|
|
url: 'spec/ol/data/point.json',
|
|
format: new GeoJSON(),
|
|
}),
|
|
}),
|
|
new VectorLayer({
|
|
source: new VectorSource({
|
|
url: 'spec/ol/data/point.json',
|
|
format: new GeoJSON(),
|
|
strategy: tileStrategy(createXYZ()),
|
|
}),
|
|
}),
|
|
new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [new Feature(new Point([0, 0]))],
|
|
}),
|
|
}),
|
|
new VectorLayer({
|
|
source: new VectorSource({
|
|
loader: function (extent, resolution, projection) {
|
|
this.addFeature(new Feature(new Point([0, 0])));
|
|
},
|
|
}),
|
|
}),
|
|
new WebGLPointsLayer({
|
|
source: new VectorSource({
|
|
features: [new Feature(new Point([0, 0]))],
|
|
}),
|
|
style: {
|
|
symbol: {
|
|
color: 'red',
|
|
symbolType: 'circle',
|
|
},
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
});
|
|
|
|
afterEach(function () {
|
|
document.body.removeChild(map.getTargetElement());
|
|
map.setTarget(null);
|
|
map.dispose();
|
|
map.getLayers().forEach((layer) => layer.dispose());
|
|
});
|
|
|
|
it('triggers when all tiles and sources are loaded and faded in', function (done) {
|
|
const layers = map.getLayers().getArray();
|
|
expect(layers[6].getRenderer().ready).to.be(false);
|
|
map.once('rendercomplete', function () {
|
|
expect(map.tileQueue_.getTilesLoading()).to.be(0);
|
|
expect(layers[1].getSource().image_.getState()).to.be(
|
|
ImageState.LOADED
|
|
);
|
|
expect(layers[2].getSource().getFeatures().length).to.be(1);
|
|
expect(layers[6].getRenderer().ready).to.be(true);
|
|
done();
|
|
});
|
|
map.setView(
|
|
new View({
|
|
center: [0, 0],
|
|
zoom: 0,
|
|
})
|
|
);
|
|
});
|
|
it('ignores invisible layers', function (done) {
|
|
map.getLayers().forEach(function (layer, i) {
|
|
layer.setVisible(i === 4);
|
|
});
|
|
map.setView(
|
|
new View({
|
|
center: [0, 0],
|
|
zoom: 0,
|
|
})
|
|
);
|
|
map.once('rendercomplete', () => done());
|
|
});
|
|
});
|
|
|
|
describe('#getFeaturesAtPixel', function () {
|
|
let target, map, layer;
|
|
beforeEach(function () {
|
|
target = document.createElement('div');
|
|
target.style.width = '100px';
|
|
target.style.height = '100px';
|
|
document.body.appendChild(target);
|
|
layer = new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [
|
|
new Feature(
|
|
new LineString([
|
|
[-50, 0],
|
|
[50, 0],
|
|
])
|
|
),
|
|
],
|
|
}),
|
|
});
|
|
map = new Map({
|
|
target: target,
|
|
layers: [layer],
|
|
view: new View({
|
|
center: [0, 0],
|
|
zoom: 17,
|
|
}),
|
|
});
|
|
map.renderSync();
|
|
});
|
|
afterEach(function () {
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('returns an empty array if no feature was found', function () {
|
|
const features = map.getFeaturesAtPixel([0, 0]);
|
|
expect(features).to.be.an(Array);
|
|
expect(features).to.be.empty();
|
|
});
|
|
|
|
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);
|
|
map.renderSync();
|
|
const features = map.getFeaturesAtPixel([50, 50], {
|
|
layerFilter: function (layer) {
|
|
return layer === otherLayer;
|
|
},
|
|
});
|
|
expect(features).to.be.an(Array);
|
|
expect(features).to.be.empty();
|
|
});
|
|
|
|
it('finds off-world geometries', function () {
|
|
const line1 = new LineString([
|
|
[130, 0],
|
|
[230, 0],
|
|
]);
|
|
line1.transform('EPSG:4326', 'EPSG:3857');
|
|
const line2 = new LineString([
|
|
[-230, 0],
|
|
[-130, 0],
|
|
]);
|
|
line2.transform('EPSG:4326', 'EPSG:3857');
|
|
layer.getSource().addFeature(new Feature(line1));
|
|
layer.getSource().addFeature(new Feature(line2));
|
|
map.getView().setCenter(fromLonLat([180, 0]));
|
|
map.renderSync();
|
|
|
|
let features = map.getFeaturesAtPixel([60, 50]);
|
|
expect(features).to.be.an(Array);
|
|
expect(features.length).to.be(2);
|
|
|
|
features = map.getFeaturesAtPixel([60, 50], {checkWrapped: false});
|
|
expect(features).to.be.an(Array);
|
|
expect(features.length).to.be(1);
|
|
|
|
map.getView().setCenter(fromLonLat([-180, 0]));
|
|
map.renderSync();
|
|
|
|
features = map.getFeaturesAtPixel([40, 50]);
|
|
expect(features).to.be.an(Array);
|
|
expect(features.length).to.be(2);
|
|
|
|
features = map.getFeaturesAtPixel([40, 50], {checkWrapped: false});
|
|
expect(features).to.be.an(Array);
|
|
expect(features.length).to.be(1);
|
|
});
|
|
});
|
|
|
|
describe('#getFeaturesAtPixel - useGeographic', function () {
|
|
let target, map;
|
|
const size = 256;
|
|
beforeEach(function () {
|
|
useGeographic();
|
|
|
|
target = document.createElement('div');
|
|
target.style.width = size + 'px';
|
|
target.style.height = size + 'px';
|
|
document.body.appendChild(target);
|
|
|
|
map = new Map({
|
|
target: target,
|
|
layers: [
|
|
new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [
|
|
new Feature(
|
|
new Polygon([
|
|
[
|
|
[-100, 40],
|
|
[-90, 40],
|
|
[-90, 50],
|
|
[-100, 50],
|
|
[-100, 40],
|
|
],
|
|
])
|
|
),
|
|
],
|
|
}),
|
|
}),
|
|
],
|
|
view: new View({
|
|
center: [0, 0],
|
|
zoom: 0,
|
|
}),
|
|
});
|
|
map.renderSync();
|
|
});
|
|
|
|
afterEach(function () {
|
|
clearUserProjection();
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('returns an empty array if no feature was found', function () {
|
|
const features = map.getFeaturesAtPixel([size / 2, size / 2]);
|
|
expect(features).to.be.an(Array);
|
|
expect(features).to.be.empty();
|
|
});
|
|
|
|
it('returns an array of found features', function () {
|
|
const coordinate = [-95, 45];
|
|
const pixel = map.getPixelFromCoordinate(coordinate);
|
|
const features = map.getFeaturesAtPixel(pixel);
|
|
expect(features).to.be.an(Array);
|
|
expect(features[0]).to.be.a(Feature);
|
|
});
|
|
});
|
|
|
|
describe('#hasFeatureAtPixel - useGeographic', function () {
|
|
let target, map;
|
|
const size = 256;
|
|
beforeEach(function () {
|
|
useGeographic();
|
|
|
|
target = document.createElement('div');
|
|
target.style.width = size + 'px';
|
|
target.style.height = size + 'px';
|
|
document.body.appendChild(target);
|
|
|
|
map = new Map({
|
|
target: target,
|
|
layers: [
|
|
new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [
|
|
new Feature(
|
|
new Polygon([
|
|
[
|
|
[-100, 40],
|
|
[-90, 40],
|
|
[-90, 50],
|
|
[-100, 50],
|
|
[-100, 40],
|
|
],
|
|
])
|
|
),
|
|
],
|
|
}),
|
|
}),
|
|
],
|
|
view: new View({
|
|
center: [0, 0],
|
|
zoom: 0,
|
|
}),
|
|
});
|
|
map.renderSync();
|
|
});
|
|
|
|
afterEach(function () {
|
|
clearUserProjection();
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('returns false if no feature was found', function () {
|
|
const has = map.hasFeatureAtPixel([size / 2, size / 2]);
|
|
expect(has).to.be(false);
|
|
});
|
|
|
|
it('returns true if there are features found', function () {
|
|
const coordinate = [-95, 45];
|
|
const pixel = map.getPixelFromCoordinate(coordinate);
|
|
const has = map.hasFeatureAtPixel(pixel);
|
|
expect(has).to.be(true);
|
|
});
|
|
});
|
|
|
|
describe('#forEachLayerAtPixel()', function () {
|
|
let target, map, original, log;
|
|
|
|
beforeEach(function (done) {
|
|
log = [];
|
|
original = TileLayerRenderer.prototype.getDataAtPixel;
|
|
TileLayerRenderer.prototype.getDataAtPixel = function (pixel) {
|
|
log.push(pixel.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 () {
|
|
TileLayerRenderer.prototype.getDataAtPixel = original;
|
|
map.dispose();
|
|
document.body.removeChild(target);
|
|
log = null;
|
|
});
|
|
|
|
it('calls each layer renderer with the same pixel', 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.targetChangeHandlerKeys_).to.be(null);
|
|
});
|
|
});
|
|
|
|
describe('#setTarget', function () {
|
|
/** @type {Map|undefined} */
|
|
let map;
|
|
|
|
beforeEach(function () {
|
|
map = new Map({
|
|
target: document.createElement('div'),
|
|
});
|
|
expect(map.targetChangeHandlerKeys_).to.be.ok();
|
|
});
|
|
|
|
describe('map with target not attached to dom', function () {
|
|
it('has undefined as size with target not in document', function () {
|
|
expect(map.getSize()).to.be(undefined);
|
|
});
|
|
});
|
|
|
|
describe('call setTarget with null', function () {
|
|
it('unregisters the viewport resize listener', function () {
|
|
map.setTarget(null);
|
|
expect(map.targetChangeHandlerKeys_).to.be(null);
|
|
});
|
|
});
|
|
|
|
describe('call setTarget with an element', function () {
|
|
it('registers a viewport resize listener', function () {
|
|
map.setTarget(null);
|
|
map.setTarget(document.createElement('div'));
|
|
expect(map.targetChangeHandlerKeys_).to.be.ok();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('create interactions', function () {
|
|
let options, event, hasTabIndex, hasFocus, isPrimary;
|
|
|
|
beforeEach(function () {
|
|
options = {
|
|
altShiftDragRotate: false,
|
|
doubleClickZoom: false,
|
|
keyboard: false,
|
|
mouseWheelZoom: false,
|
|
shiftDragZoom: false,
|
|
dragPan: false,
|
|
pinchRotate: false,
|
|
pinchZoom: false,
|
|
};
|
|
hasTabIndex = true;
|
|
hasFocus = true;
|
|
isPrimary = true;
|
|
event = {
|
|
map: {
|
|
getTargetElement: function () {
|
|
return {
|
|
hasAttribute: function (attribute) {
|
|
return hasTabIndex;
|
|
},
|
|
contains: function () {
|
|
return hasFocus;
|
|
},
|
|
};
|
|
},
|
|
getOwnerDocument: function () {
|
|
return {};
|
|
},
|
|
},
|
|
originalEvent: {
|
|
isPrimary: isPrimary,
|
|
button: 0,
|
|
},
|
|
target: {
|
|
getTargetElement: function () {
|
|
return {
|
|
contains: function () {
|
|
return hasFocus;
|
|
},
|
|
};
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
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).useAnchor_).to.eql(true);
|
|
interactions.item(0).setMouseAnchor(false);
|
|
expect(interactions.item(0).useAnchor_).to.eql(false);
|
|
expect(interactions.item(0).condition_).to.be(TRUE);
|
|
});
|
|
it('does not use the default condition when onFocusOnly option is set', function () {
|
|
options.onFocusOnly = true;
|
|
options.mouseWheelZoom = true;
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.item(0).condition_).to.not.be(TRUE);
|
|
hasTabIndex = true;
|
|
hasFocus = true;
|
|
expect(interactions.item(0).condition_(event)).to.be(true);
|
|
hasTabIndex = true;
|
|
hasFocus = false;
|
|
expect(interactions.item(0).condition_(event)).to.be(false);
|
|
hasTabIndex = false;
|
|
expect(interactions.item(0).condition_(event)).to.be(true);
|
|
});
|
|
});
|
|
|
|
describe('create dragpan interaction', function () {
|
|
it('creates dragpan interaction', function () {
|
|
options.dragPan = true;
|
|
const interactions = defaultInteractions(options);
|
|
expect(interactions.getLength()).to.eql(1);
|
|
expect(interactions.item(0)).to.be.a(DragPan);
|
|
expect(interactions.item(0).condition_(event)).to.be(true);
|
|
hasTabIndex = true;
|
|
hasFocus = false;
|
|
expect(interactions.item(0).condition_(event)).to.be(true);
|
|
event.originalEvent.altKey = true;
|
|
expect(interactions.item(0).condition_(event)).to.be(false);
|
|
delete event.originalEvent.altKey;
|
|
event.originalEvent.button = 1;
|
|
expect(interactions.item(0).condition_(event)).to.be(false);
|
|
});
|
|
it('does not use the default condition when onFocusOnly option is set', function () {
|
|
options.onFocusOnly = true;
|
|
options.dragPan = true;
|
|
const interactions = defaultInteractions(options);
|
|
hasTabIndex = true;
|
|
hasFocus = true;
|
|
expect(interactions.item(0).condition_(event)).to.be(true);
|
|
hasTabIndex = true;
|
|
hasFocus = false;
|
|
expect(interactions.item(0).condition_(event)).to.be(false);
|
|
hasTabIndex = false;
|
|
expect(interactions.item(0).condition_(event)).to.be(true);
|
|
});
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|
|
|
|
describe('getCoordinateFromPixel() and getPixelFromCoordinate()', function () {
|
|
let target, view, map;
|
|
const centerGeographic = [2.460938, 48.850258];
|
|
const centerMercator = transform(
|
|
centerGeographic,
|
|
getProjection('EPSG:4326'),
|
|
getProjection('EPSG:3857')
|
|
);
|
|
const screenCenter = [500, 500];
|
|
|
|
beforeEach(function () {
|
|
target = document.createElement('div');
|
|
|
|
const style = target.style;
|
|
style.position = 'absolute';
|
|
style.left = '-1000px';
|
|
style.top = '-1000px';
|
|
style.width = `${screenCenter[0] * 2}px`;
|
|
style.height = `${screenCenter[1] * 2}px`;
|
|
document.body.appendChild(target);
|
|
|
|
useGeographic();
|
|
|
|
view = new View({
|
|
center: centerGeographic,
|
|
zoom: 3,
|
|
});
|
|
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);
|
|
clearUserProjection();
|
|
});
|
|
|
|
it('gets coordinates in user projection', function (done) {
|
|
map.renderSync();
|
|
const coordinateGeographic = map.getCoordinateFromPixel(screenCenter);
|
|
expect(coordinateGeographic[0]).to.roughlyEqual(
|
|
centerGeographic[0],
|
|
1e-5
|
|
);
|
|
expect(coordinateGeographic[1]).to.roughlyEqual(
|
|
centerGeographic[1],
|
|
1e-5
|
|
);
|
|
done();
|
|
});
|
|
|
|
it('gets coordinates in view projection', function (done) {
|
|
map.renderSync();
|
|
const coordinateMercator =
|
|
map.getCoordinateFromPixelInternal(screenCenter);
|
|
expect(coordinateMercator[0]).to.roughlyEqual(centerMercator[0], 1e-5);
|
|
expect(coordinateMercator[1]).to.roughlyEqual(centerMercator[1], 1e-5);
|
|
done();
|
|
});
|
|
|
|
it('gets pixel from coordinates in user projection', function (done) {
|
|
map.renderSync();
|
|
const pixel = map.getPixelFromCoordinate(centerGeographic);
|
|
expect(pixel).to.eql(screenCenter);
|
|
done();
|
|
});
|
|
|
|
it('gets pixel from coordinates in view projection', function (done) {
|
|
map.renderSync();
|
|
const pixel = map.getPixelFromCoordinateInternal(centerMercator);
|
|
expect(pixel).to.eql(screenCenter);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#handleMapBrowserEvent()', function () {
|
|
let map, target, dragpan;
|
|
beforeEach(function () {
|
|
target = document.createElement('div');
|
|
target.style.width = '100px';
|
|
target.style.height = '100px';
|
|
document.body.appendChild(target);
|
|
dragpan = new DragPan();
|
|
map = new Map({
|
|
target: target,
|
|
interactions: [dragpan],
|
|
layers: [
|
|
new TileLayer({
|
|
source: new XYZ({
|
|
url: 'spec/ol/data/osm-{z}-{x}-{y}.png',
|
|
}),
|
|
}),
|
|
],
|
|
view: new View({
|
|
zoom: 0,
|
|
center: [0, 0],
|
|
}),
|
|
});
|
|
map.renderSync();
|
|
});
|
|
|
|
afterEach(function () {
|
|
map.setTarget(null);
|
|
document.body.removeChild(target);
|
|
});
|
|
|
|
it('calls handleEvent on interaction', function () {
|
|
const spy = sinon.spy(dragpan, 'handleEvent');
|
|
map.handleMapBrowserEvent(
|
|
new MapBrowserEvent('pointermove', map, new PointerEvent('pointermove'))
|
|
);
|
|
expect(spy.callCount).to.be(1);
|
|
spy.restore();
|
|
});
|
|
|
|
it('does not call handleEvent on interaction when map has no target', function () {
|
|
map.setTarget(null);
|
|
const spy = sinon.spy(dragpan, 'handleEvent');
|
|
map.handleMapBrowserEvent(
|
|
new MapBrowserEvent('pointermove', map, new PointerEvent('pointermove'))
|
|
);
|
|
expect(spy.callCount).to.be(0);
|
|
spy.restore();
|
|
});
|
|
|
|
it('does not call handleEvent on interaction that has been removed', function () {
|
|
const spy = sinon.spy(dragpan, 'handleEvent');
|
|
let callCount = 0;
|
|
const interaction = new Interaction({
|
|
handleEvent: function () {
|
|
++callCount;
|
|
map.removeInteraction(dragpan);
|
|
return true;
|
|
},
|
|
});
|
|
map.addInteraction(interaction);
|
|
map.handleMapBrowserEvent(
|
|
new MapBrowserEvent('pointermove', map, new PointerEvent('pointermove'))
|
|
);
|
|
expect(callCount).to.be(1);
|
|
expect(spy.callCount).to.be(0);
|
|
spy.restore();
|
|
});
|
|
|
|
it('does not call handleEvent on interaction when MapBrowserEvent propagation stopped', function () {
|
|
const select = new Select();
|
|
const selectStub = sinon.stub(select, 'handleEvent');
|
|
selectStub.callsFake(function (e) {
|
|
e.stopPropagation();
|
|
return true;
|
|
});
|
|
map.addInteraction(select);
|
|
const spy = sinon.spy(dragpan, 'handleEvent');
|
|
map.handleMapBrowserEvent(
|
|
new MapBrowserEvent('pointermove', map, new PointerEvent('pointermove'))
|
|
);
|
|
expect(spy.callCount).to.be(0);
|
|
expect(selectStub.callCount).to.be(1);
|
|
spy.restore();
|
|
selectStub.restore();
|
|
});
|
|
});
|
|
});
|