Organize tests
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
getMapboxPath,
|
||||
normalizeSourceUrl,
|
||||
normalizeSpriteUrl,
|
||||
normalizeStyleUrl,
|
||||
} from '../../../../../src/ol/layer/MapboxVector.js';
|
||||
|
||||
describe('ol/layer/MapboxVector', () => {
|
||||
describe('getMapboxPath()', () => {
|
||||
const cases = [
|
||||
{
|
||||
url: 'mapbox://path/to/resource',
|
||||
expected: 'path/to/resource',
|
||||
},
|
||||
{
|
||||
url: 'mapbox://path/to/resource?query',
|
||||
expected: 'path/to/resource?query',
|
||||
},
|
||||
{
|
||||
url: 'https://example.com/resource',
|
||||
expected: '',
|
||||
},
|
||||
];
|
||||
|
||||
for (const c of cases) {
|
||||
it(`works for ${c.url}`, () => {
|
||||
expect(getMapboxPath(c.url)).to.be(c.expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('normalizeStyleUrl()', () => {
|
||||
const cases = [
|
||||
{
|
||||
url: 'mapbox://styles/mapbox/bright-v9',
|
||||
expected:
|
||||
'https://api.mapbox.com/styles/v1/mapbox/bright-v9?&access_token=test-token',
|
||||
},
|
||||
{
|
||||
url: 'https://example.com/style',
|
||||
expected: 'https://example.com/style',
|
||||
},
|
||||
];
|
||||
|
||||
const token = 'test-token';
|
||||
for (const c of cases) {
|
||||
it(`works for ${c.url}`, () => {
|
||||
expect(normalizeStyleUrl(c.url, token)).to.be(c.expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('normalizeSpriteUrl()', () => {
|
||||
const cases = [
|
||||
{
|
||||
url: 'mapbox://sprites/mapbox/bright-v9',
|
||||
expected:
|
||||
'https://api.mapbox.com/styles/v1/mapbox/bright-v9/sprite?access_token=test-token',
|
||||
},
|
||||
{
|
||||
url: 'https://example.com/sprite',
|
||||
expected: 'https://example.com/sprite',
|
||||
},
|
||||
];
|
||||
|
||||
const token = 'test-token';
|
||||
for (const c of cases) {
|
||||
it(`works for ${c.url}`, () => {
|
||||
expect(normalizeSpriteUrl(c.url, token)).to.be(c.expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('normalizeSourceUrl()', () => {
|
||||
const cases = [
|
||||
{
|
||||
url: 'mapbox://mapbox.mapbox-streets-v7',
|
||||
expected:
|
||||
'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v7/{z}/{x}/{y}.vector.pbf?access_token=test-token',
|
||||
},
|
||||
{
|
||||
url: 'https://example.com/source/{z}/{x}/{y}.pbf',
|
||||
expected: 'https://example.com/source/{z}/{x}/{y}.pbf',
|
||||
},
|
||||
];
|
||||
|
||||
const token = 'test-token';
|
||||
for (const c of cases) {
|
||||
it(`works for ${c.url}`, () => {
|
||||
expect(normalizeSourceUrl(c.url, token)).to.be(c.expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,502 @@
|
||||
import Collection from '../../../../../src/ol/Collection.js';
|
||||
import Layer from '../../../../../src/ol/layer/Layer.js';
|
||||
import LayerGroup from '../../../../../src/ol/layer/Group.js';
|
||||
import Source from '../../../../../src/ol/source/Source.js';
|
||||
import {assign} from '../../../../../src/ol/obj.js';
|
||||
import {getIntersection} from '../../../../../src/ol/extent.js';
|
||||
import {getUid} from '../../../../../src/ol/util.js';
|
||||
|
||||
describe('ol.layer.Group', function () {
|
||||
describe('constructor (defaults)', function () {
|
||||
let layerGroup;
|
||||
|
||||
beforeEach(function () {
|
||||
layerGroup = new LayerGroup();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('creates an instance', function () {
|
||||
expect(layerGroup).to.be.a(LayerGroup);
|
||||
});
|
||||
|
||||
it('provides default opacity', function () {
|
||||
expect(layerGroup.getOpacity()).to.be(1);
|
||||
});
|
||||
|
||||
it('provides default visibility', function () {
|
||||
expect(layerGroup.getVisible()).to.be(true);
|
||||
});
|
||||
|
||||
it('provides default layerState', function () {
|
||||
expect(layerGroup.getLayerState()).to.eql({
|
||||
layer: layerGroup,
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
});
|
||||
|
||||
it('provides default empty layers collection', function () {
|
||||
expect(layerGroup.getLayers()).to.be.a(Collection);
|
||||
expect(layerGroup.getLayers().getLength()).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generic change event', function () {
|
||||
let layer, group, listener;
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
});
|
||||
group = new LayerGroup({
|
||||
layers: [layer],
|
||||
});
|
||||
listener = sinon.spy();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
group.dispose();
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('is dispatched by the group when layer opacity changes', function () {
|
||||
group.on('change', listener);
|
||||
|
||||
layer.setOpacity(0.5);
|
||||
expect(listener.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('is dispatched by the group when layer visibility changes', function () {
|
||||
group.on('change', listener);
|
||||
|
||||
layer.setVisible(false);
|
||||
expect(listener.callCount).to.be(1);
|
||||
|
||||
layer.setVisible(true);
|
||||
expect(listener.callCount).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('property change event', function () {
|
||||
let layer, group, listener;
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
});
|
||||
group = new LayerGroup({
|
||||
layers: [layer],
|
||||
});
|
||||
listener = sinon.spy();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
group.dispose();
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('is dispatched by the group when group opacity changes', function () {
|
||||
group.on('propertychange', listener);
|
||||
|
||||
group.setOpacity(0.5);
|
||||
expect(listener.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('is dispatched by the group when group visibility changes', function () {
|
||||
group.on('propertychange', listener);
|
||||
|
||||
group.setVisible(false);
|
||||
expect(listener.callCount).to.be(1);
|
||||
|
||||
group.setVisible(true);
|
||||
expect(listener.callCount).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('constructor (options)', function () {
|
||||
it('accepts options', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
});
|
||||
const layerGroup = new LayerGroup({
|
||||
layers: [layer],
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: 1,
|
||||
maxZoom: 10,
|
||||
});
|
||||
|
||||
expect(layerGroup.getOpacity()).to.be(0.5);
|
||||
expect(layerGroup.getVisible()).to.be(false);
|
||||
expect(layerGroup.getMaxResolution()).to.be(500);
|
||||
expect(layerGroup.getMinResolution()).to.be(0.25);
|
||||
expect(layerGroup.getMinZoom()).to.be(1);
|
||||
expect(layerGroup.getMaxZoom()).to.be(10);
|
||||
expect(layerGroup.getLayerState()).to.eql({
|
||||
layer: layerGroup,
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: 1,
|
||||
maxZoom: 10,
|
||||
});
|
||||
expect(layerGroup.getLayers()).to.be.a(Collection);
|
||||
expect(layerGroup.getLayers().getLength()).to.be(1);
|
||||
expect(layerGroup.getLayers().item(0)).to.be(layer);
|
||||
|
||||
layer.dispose();
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('accepts an extent option', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
});
|
||||
|
||||
const groupExtent = [-10, -5, 10, 5];
|
||||
const layerGroup = new LayerGroup({
|
||||
layers: [layer],
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
extent: groupExtent,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
});
|
||||
|
||||
expect(layerGroup.getOpacity()).to.be(0.5);
|
||||
expect(layerGroup.getVisible()).to.be(false);
|
||||
expect(layerGroup.getExtent()).to.eql(groupExtent);
|
||||
expect(layerGroup.getMaxResolution()).to.be(500);
|
||||
expect(layerGroup.getMinResolution()).to.be(0.25);
|
||||
expect(layerGroup.getLayerState()).to.eql({
|
||||
layer: layerGroup,
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: groupExtent,
|
||||
zIndex: 0,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
expect(layerGroup.getLayers()).to.be.a(Collection);
|
||||
expect(layerGroup.getLayers().getLength()).to.be(1);
|
||||
expect(layerGroup.getLayers().item(0)).to.be(layer);
|
||||
|
||||
layer.dispose();
|
||||
layerGroup.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLayerState', function () {
|
||||
let layerGroup;
|
||||
|
||||
beforeEach(function () {
|
||||
layerGroup = new LayerGroup();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('returns a layerState from the properties values', function () {
|
||||
layerGroup.setOpacity(0.3);
|
||||
layerGroup.setVisible(false);
|
||||
layerGroup.setZIndex(10);
|
||||
const groupExtent = [-100, 50, 100, 50];
|
||||
layerGroup.setExtent(groupExtent);
|
||||
layerGroup.setMaxResolution(500);
|
||||
layerGroup.setMinResolution(0.25);
|
||||
layerGroup.setMinZoom(5);
|
||||
layerGroup.setMaxZoom(10);
|
||||
expect(layerGroup.getLayerState()).to.eql({
|
||||
layer: layerGroup,
|
||||
opacity: 0.3,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: groupExtent,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: 5,
|
||||
maxZoom: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a layerState with clamped values', function () {
|
||||
layerGroup.setOpacity(-1.5);
|
||||
layerGroup.setVisible(false);
|
||||
expect(layerGroup.getLayerState()).to.eql({
|
||||
layer: layerGroup,
|
||||
opacity: 0,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
|
||||
layerGroup.setOpacity(3);
|
||||
layerGroup.setVisible(true);
|
||||
expect(layerGroup.getLayerState()).to.eql({
|
||||
layer: layerGroup,
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('layers events', function () {
|
||||
it('listen / unlisten for layers added to the collection', function () {
|
||||
const layers = new Collection();
|
||||
const layerGroup = new LayerGroup({
|
||||
layers: layers,
|
||||
});
|
||||
expect(Object.keys(layerGroup.listenerKeys_).length).to.eql(0);
|
||||
const layer = new Layer({});
|
||||
layers.push(layer);
|
||||
expect(Object.keys(layerGroup.listenerKeys_).length).to.eql(1);
|
||||
|
||||
const listeners = layerGroup.listenerKeys_[getUid(layer)];
|
||||
expect(listeners.length).to.eql(2);
|
||||
expect(typeof listeners[0]).to.be('object');
|
||||
expect(typeof listeners[1]).to.be('object');
|
||||
|
||||
// remove the layer from the group
|
||||
layers.pop();
|
||||
expect(Object.keys(layerGroup.listenerKeys_).length).to.eql(0);
|
||||
expect(listeners[0].listener).to.be(undefined);
|
||||
expect(listeners[1].listener).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setLayers', function () {
|
||||
it('sets layers property', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
});
|
||||
const layers = new Collection([layer]);
|
||||
const layerGroup = new LayerGroup();
|
||||
|
||||
layerGroup.setLayers(layers);
|
||||
expect(layerGroup.getLayers()).to.be(layers);
|
||||
|
||||
layerGroup.dispose();
|
||||
layer.dispose();
|
||||
layers.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLayerStatesArray', function () {
|
||||
let layer1, layer2, layer3;
|
||||
beforeEach(function () {
|
||||
layer1 = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
});
|
||||
layer2 = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
});
|
||||
layer3 = new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
extent: [-5, -2, 5, 2],
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer1.dispose();
|
||||
layer2.dispose();
|
||||
layer3.dispose();
|
||||
});
|
||||
|
||||
it('returns an empty array if no layer', function () {
|
||||
const layerGroup = new LayerGroup();
|
||||
|
||||
const layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
expect(layerStatesArray).to.be.a(Array);
|
||||
expect(layerStatesArray.length).to.be(0);
|
||||
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('does not transform layerStates by default', function () {
|
||||
const layerGroup = new LayerGroup({
|
||||
layers: [layer1, layer2],
|
||||
});
|
||||
|
||||
const layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
expect(layerStatesArray).to.be.a(Array);
|
||||
expect(layerStatesArray.length).to.be(2);
|
||||
expect(layerStatesArray[0]).to.eql(layer1.getLayerState());
|
||||
|
||||
// layer state should match except for layer reference
|
||||
const layerState = assign({}, layerStatesArray[0]);
|
||||
delete layerState.layer;
|
||||
const groupState = assign({}, layerGroup.getLayerState());
|
||||
delete groupState.layer;
|
||||
expect(layerState).to.eql(groupState);
|
||||
|
||||
expect(layerStatesArray[1]).to.eql(layer2.getLayerState());
|
||||
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('uses the layer group extent if layer has no extent', function () {
|
||||
const groupExtent = [-10, -5, 10, 5];
|
||||
const layerGroup = new LayerGroup({
|
||||
extent: groupExtent,
|
||||
layers: [layer1],
|
||||
});
|
||||
const layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
expect(layerStatesArray[0].extent).to.eql(groupExtent);
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('uses the intersection of group and child extent', function () {
|
||||
const groupExtent = [-10, -5, 10, 5];
|
||||
const layerGroup = new LayerGroup({
|
||||
extent: groupExtent,
|
||||
layers: [layer3],
|
||||
});
|
||||
const layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
expect(layerStatesArray[0].extent).to.eql(
|
||||
getIntersection(layer3.getExtent(), groupExtent)
|
||||
);
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('transforms layerStates correctly', function () {
|
||||
const layerGroup = new LayerGroup({
|
||||
layers: [layer1, layer2],
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
maxResolution: 150,
|
||||
minResolution: 0.2,
|
||||
});
|
||||
|
||||
const layerStatesArray = layerGroup.getLayerStatesArray();
|
||||
|
||||
// compare layer state to group state
|
||||
|
||||
// layer state should match except for layer reference
|
||||
let layerState = assign({}, layerStatesArray[0]);
|
||||
delete layerState.layer;
|
||||
const groupState = assign({}, layerGroup.getLayerState());
|
||||
delete groupState.layer;
|
||||
expect(layerState).to.eql(groupState);
|
||||
|
||||
// layer state should be transformed (and we ignore layer reference)
|
||||
layerState = assign({}, layerStatesArray[1]);
|
||||
delete layerState.layer;
|
||||
expect(layerState).to.eql({
|
||||
opacity: 0.25,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: 150,
|
||||
minResolution: 0.25,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
|
||||
layerGroup.dispose();
|
||||
});
|
||||
|
||||
it('returns max minZoom', function () {
|
||||
const group = new LayerGroup({
|
||||
minZoom: 5,
|
||||
layers: [
|
||||
new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
}),
|
||||
new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
minZoom: 10,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(group.getLayerStatesArray()[0].minZoom).to.be(5);
|
||||
expect(group.getLayerStatesArray()[1].minZoom).to.be(10);
|
||||
});
|
||||
|
||||
it('returns min maxZoom of layers', function () {
|
||||
const group = new LayerGroup({
|
||||
maxZoom: 5,
|
||||
layers: [
|
||||
new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
}),
|
||||
new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
maxZoom: 2,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(group.getLayerStatesArray()[0].maxZoom).to.be(5);
|
||||
expect(group.getLayerStatesArray()[1].maxZoom).to.be(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
import Feature from '../../../../../src/ol/Feature.js';
|
||||
import HeatmapLayer from '../../../../../src/ol/layer/Heatmap.js';
|
||||
import Map from '../../../../../src/ol/Map.js';
|
||||
import Point from '../../../../../src/ol/geom/Point.js';
|
||||
import VectorSource from '../../../../../src/ol/source/Vector.js';
|
||||
import View from '../../../../../src/ol/View.js';
|
||||
|
||||
describe('ol.layer.Heatmap', function () {
|
||||
describe('constructor', function () {
|
||||
it('can be constructed without arguments', function () {
|
||||
const instance = new HeatmapLayer();
|
||||
expect(instance).to.be.an(HeatmapLayer);
|
||||
});
|
||||
it('has a default className', function () {
|
||||
const layer = new HeatmapLayer({
|
||||
source: new VectorSource(),
|
||||
});
|
||||
const canvas = layer.getRenderer().helper.getCanvas();
|
||||
expect(canvas.className).to.eql('ol-layer');
|
||||
});
|
||||
it('accepts a custom className', function () {
|
||||
const layer = new HeatmapLayer({
|
||||
source: new VectorSource(),
|
||||
className: 'a-class-name',
|
||||
});
|
||||
const canvas = layer.getRenderer().helper.getCanvas();
|
||||
expect(canvas.className).to.eql('a-class-name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hit detection', function () {
|
||||
it('hit detects two distinct features', function (done) {
|
||||
const target = document.createElement('div');
|
||||
target.style.width = '300px';
|
||||
target.style.height = '300px';
|
||||
document.body.appendChild(target);
|
||||
|
||||
const feature = new Feature({
|
||||
geometry: new Point([0, 0]),
|
||||
id: 1,
|
||||
weight: 10,
|
||||
});
|
||||
const feature2 = new Feature({
|
||||
geometry: new Point([14, 14]),
|
||||
id: 2,
|
||||
weight: 10,
|
||||
});
|
||||
|
||||
const source = new VectorSource({
|
||||
features: [feature, feature2],
|
||||
});
|
||||
const layer = new HeatmapLayer({
|
||||
source: source,
|
||||
blur: 10,
|
||||
radius: 10,
|
||||
});
|
||||
const map = new Map({
|
||||
layers: [layer],
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
resolution: 0.1,
|
||||
}),
|
||||
target: target,
|
||||
});
|
||||
map.render();
|
||||
|
||||
function hitTest(coordinate) {
|
||||
const features = map.getFeaturesAtPixel(
|
||||
map.getPixelFromCoordinate(coordinate)
|
||||
);
|
||||
return features.length ? features[0] : null;
|
||||
}
|
||||
|
||||
const renderer = layer.getRenderer();
|
||||
renderer.worker_.addEventListener('message', function (event) {
|
||||
if (!renderer.hitRenderInstructions_) {
|
||||
return;
|
||||
}
|
||||
map.renderSync();
|
||||
|
||||
let res;
|
||||
|
||||
res = hitTest([0, 0]);
|
||||
expect(res).to.be(feature);
|
||||
res = hitTest([20, 0]);
|
||||
expect(res).to.be(null);
|
||||
res = hitTest([14, 14]);
|
||||
expect(res).to.be(feature2);
|
||||
res = hitTest([0, 14]);
|
||||
expect(res).to.be(null);
|
||||
|
||||
document.body.removeChild(target);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,692 @@
|
||||
import Layer, {inView} from '../../../../../src/ol/layer/Layer.js';
|
||||
import Map from '../../../../../src/ol/Map.js';
|
||||
import RenderEvent from '../../../../../src/ol/render/Event.js';
|
||||
import Source from '../../../../../src/ol/source/Source.js';
|
||||
import {get as getProjection} from '../../../../../src/ol/proj.js';
|
||||
|
||||
describe('ol.layer.Layer', function () {
|
||||
describe('constructor (defaults)', function () {
|
||||
let layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: getProjection('EPSG:4326'),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('creates an instance', function () {
|
||||
expect(layer).to.be.a(Layer);
|
||||
});
|
||||
|
||||
it('provides default opacity', function () {
|
||||
expect(layer.getOpacity()).to.be(1);
|
||||
});
|
||||
|
||||
it('provides default visibility', function () {
|
||||
expect(layer.getVisible()).to.be(true);
|
||||
});
|
||||
|
||||
it('provides default max resolution', function () {
|
||||
expect(layer.getMaxResolution()).to.be(Infinity);
|
||||
});
|
||||
|
||||
it('provides default min resolution', function () {
|
||||
expect(layer.getMinResolution()).to.be(0);
|
||||
});
|
||||
|
||||
it('provides default min zoom', function () {
|
||||
expect(layer.getMinZoom()).to.be(-Infinity);
|
||||
});
|
||||
|
||||
it('provides default max zoom', function () {
|
||||
expect(layer.getMaxZoom()).to.be(Infinity);
|
||||
});
|
||||
|
||||
it('provides default layerState', function () {
|
||||
expect(layer.getLayerState()).to.eql({
|
||||
layer: layer,
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
maxResolution: Infinity,
|
||||
minResolution: 0,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('constructor (options)', function () {
|
||||
it('accepts options', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({
|
||||
projection: getProjection('EPSG:4326'),
|
||||
}),
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: 1,
|
||||
maxZoom: 10,
|
||||
foo: 42,
|
||||
});
|
||||
|
||||
expect(layer.getOpacity()).to.be(0.5);
|
||||
expect(layer.getVisible()).to.be(false);
|
||||
expect(layer.getMaxResolution()).to.be(500);
|
||||
expect(layer.getMinResolution()).to.be(0.25);
|
||||
expect(layer.getMinZoom()).to.be(1);
|
||||
expect(layer.getMaxZoom()).to.be(10);
|
||||
expect(layer.get('foo')).to.be(42);
|
||||
expect(layer.getLayerState()).to.eql({
|
||||
layer: layer,
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: 1,
|
||||
maxZoom: 10,
|
||||
});
|
||||
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('throws on non-numeric opacity', function () {
|
||||
function create() {
|
||||
new Layer({
|
||||
source: new Source({
|
||||
projection: 'EPSG:4326',
|
||||
}),
|
||||
opacity: 'foo',
|
||||
});
|
||||
}
|
||||
|
||||
expect(create).to.throwException();
|
||||
});
|
||||
|
||||
it('accepts a custom render function', function () {
|
||||
let called = false;
|
||||
const layer = new Layer({
|
||||
render: function () {
|
||||
called = true;
|
||||
},
|
||||
});
|
||||
layer.render();
|
||||
expect(called).to.eql(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('inView', function () {
|
||||
let layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: getProjection('EPSG:4326'),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
const cases = [
|
||||
{
|
||||
when: 'layer is not visible',
|
||||
visible: false,
|
||||
view: {
|
||||
resolution: 4,
|
||||
zoom: 4,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'layer is not visible (with min/max zoom and resolution)',
|
||||
visible: false,
|
||||
minZoom: 2,
|
||||
maxZoom: 6,
|
||||
minResolution: 2,
|
||||
maxResolution: 6,
|
||||
view: {
|
||||
resolution: 4,
|
||||
zoom: 4,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is less than minZoom',
|
||||
minZoom: 2,
|
||||
view: {
|
||||
resolution: 1,
|
||||
zoom: 1,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is less than minZoom (with maxZoom)',
|
||||
minZoom: 2,
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 1,
|
||||
zoom: 1,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is equal to minZoom',
|
||||
minZoom: 2,
|
||||
view: {
|
||||
resolution: 2,
|
||||
zoom: 2,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is equal to minZoom (with maxZoom)',
|
||||
minZoom: 2,
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 2,
|
||||
zoom: 2,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is greater than minZoom',
|
||||
minZoom: 2,
|
||||
view: {
|
||||
resolution: 3,
|
||||
zoom: 3,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is greater than minZoom (with maxZoom)',
|
||||
minZoom: 2,
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 3,
|
||||
zoom: 3,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is equal to maxZoom',
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 4,
|
||||
zoom: 4,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is equal to maxZoom (with minZoom)',
|
||||
minZoom: 2,
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 4,
|
||||
zoom: 4,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is greater than maxZoom',
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 5,
|
||||
zoom: 5,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view zoom is greater than maxZoom (with minZoom)',
|
||||
minZoom: 2,
|
||||
maxZoom: 4,
|
||||
view: {
|
||||
resolution: 5,
|
||||
zoom: 5,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is less than minResolution',
|
||||
minResolution: 2,
|
||||
view: {
|
||||
resolution: 1,
|
||||
zoom: 1,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is less than minResolution (with maxResolution)',
|
||||
minResolution: 2,
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 1,
|
||||
zoom: 1,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is equal to minResolution',
|
||||
minResolution: 2,
|
||||
view: {
|
||||
resolution: 2,
|
||||
zoom: 2,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is equal to minResolution (with maxResolution)',
|
||||
minResolution: 2,
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 2,
|
||||
zoom: 2,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is greater than minResolution',
|
||||
minResolution: 2,
|
||||
view: {
|
||||
resolution: 3,
|
||||
zoom: 3,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when:
|
||||
'view resolution is greater than minResolution (with maxResolution)',
|
||||
minResolution: 2,
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 3,
|
||||
zoom: 3,
|
||||
},
|
||||
inView: true,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is equal to maxResolution',
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 4,
|
||||
zoom: 4,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is equal to maxResolution (with minResolution)',
|
||||
minResolution: 2,
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 4,
|
||||
zoom: 4,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when: 'view resolution is greater than maxResolution',
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 5,
|
||||
zoom: 5,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
{
|
||||
when:
|
||||
'view resolution is greater than maxResolution (with minResolution)',
|
||||
minResolution: 2,
|
||||
maxResolution: 4,
|
||||
view: {
|
||||
resolution: 5,
|
||||
zoom: 5,
|
||||
},
|
||||
inView: false,
|
||||
},
|
||||
];
|
||||
|
||||
cases.forEach(function (c, i) {
|
||||
it('returns ' + c.inView + ' when ' + c.when, function () {
|
||||
if ('visible' in c) {
|
||||
layer.setVisible(c.visible);
|
||||
}
|
||||
if ('minZoom' in c) {
|
||||
layer.setMinZoom(c.minZoom);
|
||||
}
|
||||
if ('maxZoom' in c) {
|
||||
layer.setMaxZoom(c.maxZoom);
|
||||
}
|
||||
if ('minResolution' in c) {
|
||||
layer.setMinResolution(c.minResolution);
|
||||
}
|
||||
if ('maxResolution' in c) {
|
||||
layer.setMaxResolution(c.maxResolution);
|
||||
}
|
||||
const layerState = layer.getLayerState();
|
||||
expect(inView(layerState, c.view)).to.be(c.inView);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLayerState', function () {
|
||||
let layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: getProjection('EPSG:4326'),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('returns a layerState from the properties values', function () {
|
||||
layer.setOpacity(1 / 3);
|
||||
layer.setVisible(false);
|
||||
layer.setMaxResolution(500);
|
||||
layer.setMinResolution(0.25);
|
||||
layer.setZIndex(10);
|
||||
expect(layer.getLayerState()).to.eql({
|
||||
layer: layer,
|
||||
opacity: 0.33,
|
||||
visible: false,
|
||||
managed: true,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
maxResolution: 500,
|
||||
minResolution: 0.25,
|
||||
minZoom: -Infinity,
|
||||
maxZoom: Infinity,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a layerState with clamped values', function () {
|
||||
layer.setOpacity(-1.5);
|
||||
layer.setVisible(false);
|
||||
let state = layer.getLayerState();
|
||||
expect(state.opacity).to.be(0);
|
||||
expect(state.visible).to.be(false);
|
||||
|
||||
layer.setOpacity(3);
|
||||
layer.setVisible(true);
|
||||
state = layer.getLayerState();
|
||||
expect(state.opacity).to.be(1);
|
||||
expect(state.visible).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getSource', function () {
|
||||
it('gets the layer source', function () {
|
||||
const source = new Source({projection: getProjection('EPSG:4326')});
|
||||
const layer = new Layer({source: source});
|
||||
expect(layer.getSource()).to.be(source);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#set("source", source)', function () {
|
||||
const projection = getProjection('EPSG:4326');
|
||||
|
||||
it('sets the layer source', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({projection: projection}),
|
||||
});
|
||||
|
||||
const source = new Source({projection: projection});
|
||||
layer.set('source', source);
|
||||
expect(layer.getSource()).to.be(source);
|
||||
});
|
||||
|
||||
it('calls changed', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({projection: projection}),
|
||||
});
|
||||
sinon.spy(layer, 'changed');
|
||||
|
||||
const source = new Source({projection: projection});
|
||||
layer.set('source', source);
|
||||
expect(layer.changed.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('sets up event listeners', function () {
|
||||
sinon.spy(Layer.prototype, 'handleSourceChange_');
|
||||
|
||||
const first = new Source({projection: projection});
|
||||
const layer = new Layer({source: first});
|
||||
|
||||
first.setState('ready');
|
||||
expect(layer.handleSourceChange_.calledOnce).to.be(true);
|
||||
|
||||
const second = new Source({projection: projection});
|
||||
layer.set('source', second);
|
||||
|
||||
expect(layer.handleSourceChange_.calledOnce).to.be(true);
|
||||
second.setState('ready');
|
||||
expect(layer.handleSourceChange_.callCount).to.be(2);
|
||||
|
||||
// remove spy
|
||||
Layer.prototype.handleSourceChange_.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setSource()', function () {
|
||||
const projection = getProjection('EPSG:4326');
|
||||
|
||||
it('sets the layer source', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({projection: projection}),
|
||||
});
|
||||
|
||||
const source = new Source({projection: projection});
|
||||
layer.setSource(source);
|
||||
expect(layer.getSource()).to.be(source);
|
||||
});
|
||||
|
||||
it('calls changed', function () {
|
||||
const layer = new Layer({
|
||||
source: new Source({projection: projection}),
|
||||
});
|
||||
sinon.spy(layer, 'changed');
|
||||
|
||||
const source = new Source({projection: projection});
|
||||
layer.setSource(source);
|
||||
expect(layer.changed.calledOnce).to.be(true);
|
||||
});
|
||||
|
||||
it('sets up event listeners', function () {
|
||||
sinon.spy(Layer.prototype, 'handleSourceChange_');
|
||||
|
||||
const first = new Source({projection: projection});
|
||||
const layer = new Layer({source: first});
|
||||
|
||||
first.setState('ready');
|
||||
expect(layer.handleSourceChange_.calledOnce).to.be(true);
|
||||
|
||||
const second = new Source({projection: projection});
|
||||
layer.setSource(second);
|
||||
|
||||
expect(layer.handleSourceChange_.calledOnce).to.be(true);
|
||||
second.setState('ready');
|
||||
expect(layer.handleSourceChange_.callCount).to.be(2);
|
||||
|
||||
// remove spy
|
||||
Layer.prototype.handleSourceChange_.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setOpacity', function () {
|
||||
let layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: getProjection('EPSG:4326'),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('accepts a positive number', function () {
|
||||
layer.setOpacity(0.3);
|
||||
expect(layer.getOpacity()).to.be(0.3);
|
||||
});
|
||||
|
||||
it('throws on types other than number', function () {
|
||||
function set() {
|
||||
layer.setOpacity('foo');
|
||||
}
|
||||
expect(set).to.throwException();
|
||||
});
|
||||
|
||||
it('triggers a change event', function () {
|
||||
const listener = sinon.spy();
|
||||
layer.on('propertychange', listener);
|
||||
layer.setOpacity(0.4);
|
||||
expect(listener.calledOnce).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setVisible', function () {
|
||||
let layer;
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
source: new Source({
|
||||
projection: getProjection('EPSG:4326'),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('sets visible property', function () {
|
||||
layer.setVisible(false);
|
||||
expect(layer.getVisible()).to.be(false);
|
||||
|
||||
layer.setVisible(true);
|
||||
expect(layer.getVisible()).to.be(true);
|
||||
});
|
||||
|
||||
it('fires a change event', function () {
|
||||
const listener = sinon.spy();
|
||||
layer.on('propertychange', listener);
|
||||
|
||||
layer.setVisible(false);
|
||||
expect(listener.callCount).to.be(1);
|
||||
|
||||
layer.setVisible(true);
|
||||
expect(listener.callCount).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setMap (unmanaged layer)', function () {
|
||||
let map;
|
||||
|
||||
beforeEach(function () {
|
||||
map = new Map({});
|
||||
});
|
||||
|
||||
describe('with map in constructor options', function () {
|
||||
it('renders the layer', function () {
|
||||
const layer = new Layer({
|
||||
map: map,
|
||||
});
|
||||
const frameState = {
|
||||
layerStatesArray: [],
|
||||
};
|
||||
map.dispatchEvent(
|
||||
new RenderEvent('precompose', null, frameState, null)
|
||||
);
|
||||
expect(frameState.layerStatesArray.length).to.be(1);
|
||||
const layerState = frameState.layerStatesArray[0];
|
||||
expect(layerState.layer).to.equal(layer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setMap sequences', function () {
|
||||
let mapRenderSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
mapRenderSpy = sinon.spy(map, 'render');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
mapRenderSpy.restore();
|
||||
});
|
||||
|
||||
it('requests a render frame', function () {
|
||||
const layer = new Layer({});
|
||||
|
||||
layer.setMap(map);
|
||||
expect(mapRenderSpy.callCount).to.be(1);
|
||||
|
||||
layer.setMap(null);
|
||||
expect(mapRenderSpy.callCount).to.be(2);
|
||||
|
||||
layer.setMap(map);
|
||||
expect(mapRenderSpy.callCount).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('zIndex for unmanaged layers', function () {
|
||||
let frameState, layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new Layer({
|
||||
map: map,
|
||||
});
|
||||
frameState = {
|
||||
layerStatesArray: [],
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.setMap(null);
|
||||
});
|
||||
|
||||
it('has Infinity as zIndex when not configured otherwise', function () {
|
||||
map.dispatchEvent(
|
||||
new RenderEvent('precompose', null, frameState, null)
|
||||
);
|
||||
const layerState = frameState.layerStatesArray[0];
|
||||
expect(layerState.zIndex).to.be(Infinity);
|
||||
});
|
||||
|
||||
it('respects the configured zIndex', function () {
|
||||
[-5, 0, 42].forEach((index) => {
|
||||
layer.setZIndex(index);
|
||||
map.dispatchEvent(
|
||||
new RenderEvent('precompose', null, frameState, null)
|
||||
);
|
||||
const layerState = frameState.layerStatesArray[0];
|
||||
frameState.layerStatesArray.length = 0;
|
||||
expect(layerState.zIndex).to.be(index);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
import TileLayer from '../../../../../src/ol/layer/Tile.js';
|
||||
import {Map, View} from '../../../../../src/ol/index.js';
|
||||
import {OSM, XYZ} from '../../../../../src/ol/source.js';
|
||||
|
||||
describe('ol.layer.Tile', function () {
|
||||
describe('constructor (defaults)', function () {
|
||||
let layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new TileLayer({
|
||||
source: new OSM(),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('creates an instance', function () {
|
||||
expect(layer).to.be.a(TileLayer);
|
||||
});
|
||||
|
||||
it('provides default preload', function () {
|
||||
expect(layer.getPreload()).to.be(0);
|
||||
});
|
||||
|
||||
it('provides default useInterimTilesOnError', function () {
|
||||
expect(layer.getUseInterimTilesOnError()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('frameState.animate after tile transition with layer opacity', function () {
|
||||
let target, map;
|
||||
|
||||
beforeEach(function (done) {
|
||||
target = document.createElement('div');
|
||||
Object.assign(target.style, {
|
||||
position: 'absolute',
|
||||
left: '-1000px',
|
||||
top: '-1000px',
|
||||
width: '256px',
|
||||
height: '256px',
|
||||
});
|
||||
document.body.appendChild(target);
|
||||
|
||||
map = new Map({
|
||||
target: target,
|
||||
view: new View({center: [0, 0], zoom: 1}),
|
||||
});
|
||||
|
||||
map.once('rendercomplete', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
map.dispose();
|
||||
document.body.removeChild(target);
|
||||
});
|
||||
|
||||
it('sets frameState.animate to false when opacity is 1', function (done) {
|
||||
let lastFrameState;
|
||||
const layer = new TileLayer({
|
||||
opacity: 1,
|
||||
source: new XYZ({
|
||||
url: 'spec/ol/data/osm-0-0-0.png',
|
||||
}),
|
||||
});
|
||||
layer.on('postrender', function (event) {
|
||||
lastFrameState = event.frameState;
|
||||
});
|
||||
|
||||
map.once('rendercomplete', function () {
|
||||
expect(lastFrameState.animate).to.be(false);
|
||||
done();
|
||||
});
|
||||
|
||||
map.addLayer(layer);
|
||||
});
|
||||
|
||||
it('sets frameState.animate to false when opacity is 0.5', function (done) {
|
||||
let lastFrameState;
|
||||
const layer = new TileLayer({
|
||||
opacity: 0.5,
|
||||
source: new XYZ({
|
||||
url: 'spec/ol/data/osm-0-0-0.png',
|
||||
}),
|
||||
});
|
||||
layer.on('postrender', function (event) {
|
||||
lastFrameState = event.frameState;
|
||||
});
|
||||
|
||||
map.once('rendercomplete', function () {
|
||||
expect(lastFrameState.animate).to.be(false);
|
||||
done();
|
||||
});
|
||||
|
||||
map.addLayer(layer);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,229 @@
|
||||
import Feature from '../../../../../src/ol/Feature.js';
|
||||
import ImageStyle from '../../../../../src/ol/style/Image.js';
|
||||
import Layer from '../../../../../src/ol/layer/Layer.js';
|
||||
import LineString from '../../../../../src/ol/geom/LineString.js';
|
||||
import Map from '../../../../../src/ol/Map.js';
|
||||
import Point from '../../../../../src/ol/geom/Point.js';
|
||||
import Stroke from '../../../../../src/ol/style/Stroke.js';
|
||||
import Style, {createDefaultStyle} from '../../../../../src/ol/style/Style.js';
|
||||
import VectorLayer from '../../../../../src/ol/layer/Vector.js';
|
||||
import VectorSource from '../../../../../src/ol/source/Vector.js';
|
||||
import View from '../../../../../src/ol/View.js';
|
||||
|
||||
describe('ol.layer.Vector', function () {
|
||||
describe('constructor', function () {
|
||||
const source = new VectorSource();
|
||||
const style = new Style();
|
||||
|
||||
it('creates a new layer', function () {
|
||||
const layer = new VectorLayer({source: source});
|
||||
expect(layer).to.be.a(VectorLayer);
|
||||
expect(layer).to.be.a(Layer);
|
||||
});
|
||||
|
||||
it('accepts a style option with a single style', function () {
|
||||
const layer = new VectorLayer({
|
||||
source: source,
|
||||
style: style,
|
||||
});
|
||||
|
||||
const styleFunction = layer.getStyleFunction();
|
||||
expect(styleFunction()).to.eql([style]);
|
||||
});
|
||||
|
||||
it('accepts a style option with an array of styles', function () {
|
||||
const layer = new VectorLayer({
|
||||
source: source,
|
||||
style: [style],
|
||||
});
|
||||
|
||||
const styleFunction = layer.getStyleFunction();
|
||||
expect(styleFunction()).to.eql([style]);
|
||||
});
|
||||
|
||||
it('accepts a style option with a style function', function () {
|
||||
const layer = new VectorLayer({
|
||||
source: source,
|
||||
style: function (feature, resolution) {
|
||||
return [style];
|
||||
},
|
||||
});
|
||||
|
||||
const styleFunction = layer.getStyleFunction();
|
||||
expect(styleFunction()).to.eql([style]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setStyle()', function () {
|
||||
let layer, style;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new VectorLayer({
|
||||
source: new VectorSource(),
|
||||
});
|
||||
style = new Style();
|
||||
});
|
||||
|
||||
it('allows the style to be set after construction', function () {
|
||||
layer.setStyle(style);
|
||||
expect(layer.getStyle()).to.be(style);
|
||||
});
|
||||
|
||||
it('dispatches the change event', function (done) {
|
||||
layer.on('change', function () {
|
||||
done();
|
||||
});
|
||||
layer.setStyle(style);
|
||||
});
|
||||
|
||||
it('updates the internal style function', function () {
|
||||
expect(layer.getStyleFunction()).to.be(createDefaultStyle);
|
||||
layer.setStyle(style);
|
||||
expect(layer.getStyleFunction()).not.to.be(createDefaultStyle);
|
||||
});
|
||||
|
||||
it('allows setting an null style', function () {
|
||||
layer.setStyle(null);
|
||||
expect(layer.getStyle()).to.be(null);
|
||||
expect(layer.getStyleFunction()).to.be(undefined);
|
||||
});
|
||||
|
||||
it('sets the default style when passing undefined', function () {
|
||||
layer.setStyle(style);
|
||||
layer.setStyle(undefined);
|
||||
expect(layer.getStyle()).to.be(createDefaultStyle);
|
||||
expect(layer.getStyleFunction()).to.be(createDefaultStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getStyle()', function () {
|
||||
const source = new VectorSource();
|
||||
const style = new Style();
|
||||
|
||||
it('returns what is provided to setStyle', function () {
|
||||
const layer = new VectorLayer({
|
||||
source: source,
|
||||
});
|
||||
|
||||
expect(layer.getStyle()).to.be(createDefaultStyle);
|
||||
|
||||
layer.setStyle(style);
|
||||
expect(layer.getStyle()).to.be(style);
|
||||
|
||||
layer.setStyle([style]);
|
||||
expect(layer.getStyle()).to.eql([style]);
|
||||
|
||||
const styleFunction = function (feature, resolution) {
|
||||
return [style];
|
||||
};
|
||||
layer.setStyle(styleFunction);
|
||||
expect(layer.getStyle()).to.be(styleFunction);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getFeatures()', function () {
|
||||
let map;
|
||||
beforeEach(function () {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '256px';
|
||||
container.style.height = '256px';
|
||||
document.body.appendChild(container);
|
||||
map = new Map({
|
||||
target: container,
|
||||
view: new View({
|
||||
zoom: 2,
|
||||
center: [0, 0],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.removeChild(map.getTargetElement());
|
||||
map.setTarget(null);
|
||||
});
|
||||
|
||||
it('detects features properly', function (done) {
|
||||
const source = new VectorSource({
|
||||
features: [
|
||||
new Feature({
|
||||
geometry: new Point([-1000000, 0]),
|
||||
name: 'feature1',
|
||||
}),
|
||||
new Feature({
|
||||
geometry: new Point([1000000, 0]),
|
||||
name: 'feature2',
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const feature = new Feature({
|
||||
geometry: new Point([-1000000, 0]),
|
||||
name: 'feature with no size',
|
||||
});
|
||||
|
||||
const testImage = new ImageStyle({
|
||||
opacity: 1,
|
||||
displacement: [],
|
||||
});
|
||||
|
||||
testImage.getImageState = () => {};
|
||||
testImage.listenImageChange = () => {};
|
||||
testImage.getImageSize = () => {};
|
||||
|
||||
feature.setStyle([
|
||||
new Style({
|
||||
image: testImage,
|
||||
}),
|
||||
]);
|
||||
|
||||
source.addFeature(feature);
|
||||
|
||||
const layer = new VectorLayer({
|
||||
source,
|
||||
});
|
||||
map.addLayer(layer);
|
||||
map.renderSync();
|
||||
|
||||
const pixel = map.getPixelFromCoordinate([-1000000, 0]);
|
||||
|
||||
layer.getFeatures(pixel).then(function (features) {
|
||||
expect(features.length).to.equal(1);
|
||||
expect(features[0].get('name')).to.be('feature1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('hits lines even if they are dashed', function (done) {
|
||||
const geometry = new LineString([
|
||||
[-1e6, 0],
|
||||
[1e6, 0],
|
||||
]);
|
||||
const feature = new Feature(geometry);
|
||||
const layer = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
features: [feature],
|
||||
}),
|
||||
style: new Style({
|
||||
stroke: new Stroke({
|
||||
color: 'black',
|
||||
width: 8,
|
||||
lineDash: [10, 20],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
map.addLayer(layer);
|
||||
map.renderSync();
|
||||
|
||||
const pixel = map.getPixelFromCoordinate([0, 0]);
|
||||
|
||||
layer
|
||||
.getFeatures(pixel)
|
||||
.then(function (features) {
|
||||
expect(features.length).to.equal(1);
|
||||
expect(features[0]).to.be(feature);
|
||||
done();
|
||||
}, done)
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import Feature from '../../../../../src/ol/Feature.js';
|
||||
import Map from '../../../../../src/ol/Map.js';
|
||||
import Point from '../../../../../src/ol/geom/Point.js';
|
||||
import VectorImageLayer from '../../../../../src/ol/layer/VectorImage.js';
|
||||
import VectorSource from '../../../../../src/ol/source/Vector.js';
|
||||
import View from '../../../../../src/ol/View.js';
|
||||
|
||||
describe('ol/layer/VectorImage', function () {
|
||||
describe('#getFeatures()', function () {
|
||||
let map, layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new VectorImageLayer({
|
||||
source: new VectorSource({
|
||||
features: [
|
||||
new Feature({
|
||||
geometry: new Point([-1000000, 0]),
|
||||
name: 'feature1',
|
||||
}),
|
||||
new Feature({
|
||||
geometry: new Point([1000000, 0]),
|
||||
name: 'feture2',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '256px';
|
||||
container.style.height = '256px';
|
||||
document.body.appendChild(container);
|
||||
map = new Map({
|
||||
target: container,
|
||||
layers: [layer],
|
||||
view: new View({
|
||||
zoom: 2,
|
||||
center: [0, 0],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.removeChild(map.getTargetElement());
|
||||
map.setTarget(null);
|
||||
});
|
||||
|
||||
it('detects features properly', function (done) {
|
||||
map.renderSync();
|
||||
const pixel = map.getPixelFromCoordinate([-1000000, 0]);
|
||||
layer.getFeatures(pixel).then(function (features) {
|
||||
expect(features[0].get('name')).to.be('feature1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
import GeoJSON from '../../../../../src/ol/format/GeoJSON.js';
|
||||
import Map from '../../../../../src/ol/Map.js';
|
||||
import VectorTileLayer from '../../../../../src/ol/layer/VectorTile.js';
|
||||
import VectorTileSource from '../../../../../src/ol/source/VectorTile.js';
|
||||
import View from '../../../../../src/ol/View.js';
|
||||
import {fromLonLat} from '../../../../../src/ol/proj.js';
|
||||
|
||||
describe('ol.layer.VectorTile', function () {
|
||||
describe('constructor (defaults)', function () {
|
||||
let layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new VectorTileLayer({
|
||||
source: new VectorTileSource({}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
layer.dispose();
|
||||
});
|
||||
|
||||
it('creates an instance', function () {
|
||||
expect(layer).to.be.a(VectorTileLayer);
|
||||
});
|
||||
|
||||
it('provides default preload', function () {
|
||||
expect(layer.getPreload()).to.be(0);
|
||||
});
|
||||
|
||||
it('provides default useInterimTilesOnError', function () {
|
||||
expect(layer.getUseInterimTilesOnError()).to.be(true);
|
||||
});
|
||||
|
||||
it('provides default renderMode', function () {
|
||||
expect(layer.getRenderMode()).to.be('hybrid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('constructor (options)', function () {
|
||||
it('works with options', function () {
|
||||
let layer = new VectorTileLayer({
|
||||
renderMode: 'hybrid',
|
||||
source: new VectorTileSource({}),
|
||||
});
|
||||
expect(layer.getRenderMode()).to.be('hybrid');
|
||||
expect(function () {
|
||||
layer = new VectorTileLayer({
|
||||
renderMode: 'foo',
|
||||
source: new VectorTileSource({}),
|
||||
});
|
||||
}).to.throwException();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getFeatures()', function () {
|
||||
let map, layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new VectorTileLayer({
|
||||
source: new VectorTileSource({
|
||||
format: new GeoJSON(),
|
||||
url: `data:application/json;charset=utf-8,
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-36, 0]
|
||||
},
|
||||
"properties": {
|
||||
"name": "feature1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [36, 0]
|
||||
},
|
||||
"properties": {
|
||||
"name": "feature2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
}),
|
||||
});
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '256px';
|
||||
container.style.height = '256px';
|
||||
document.body.appendChild(container);
|
||||
map = new Map({
|
||||
target: container,
|
||||
layers: [layer],
|
||||
view: new View({
|
||||
zoom: 0,
|
||||
center: [0, 0],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.removeChild(map.getTargetElement());
|
||||
map.setTarget(null);
|
||||
});
|
||||
|
||||
it('detects features properly', function (done) {
|
||||
map.once('rendercomplete', function () {
|
||||
const pixel = map.getPixelFromCoordinate(fromLonLat([-36, 0]));
|
||||
layer
|
||||
.getFeatures(pixel)
|
||||
.then(function (features) {
|
||||
expect(features[0].get('name')).to.be('feature1');
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not give false positives', function (done) {
|
||||
map.once('rendercomplete', function () {
|
||||
const pixel = map.getPixelFromCoordinate(fromLonLat([0, 0]));
|
||||
layer
|
||||
.getFeatures(pixel)
|
||||
.then(function (features) {
|
||||
expect(features.length).to.be(0);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('stores separate hit detection data for each layer that uses the source', function (done) {
|
||||
const layer2 = new VectorTileLayer({
|
||||
source: layer.getSource(),
|
||||
});
|
||||
map.addLayer(layer2);
|
||||
map.once('rendercomplete', function () {
|
||||
const pixel = map.getPixelFromCoordinate(fromLonLat([-36, 0]));
|
||||
Promise.all([layer.getFeatures(pixel), layer2.getFeatures(pixel)])
|
||||
.then(function (result) {
|
||||
const tile = layer.getSource().tileCache.get('0/0/0');
|
||||
expect(Object.keys(tile.hitDetectionImageData).length).to.be(2);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user