Compare commits

...

53 Commits

Author SHA1 Message Date
Tim Schaub
d7acbc40d5 Changes for 6.0.1 2019-09-30 12:35:08 -06:00
Olivier Guyot
176dccd6df Merge pull request #10060 from mike-000/patch-1
Ensure zoom level is not less than minimum integer zoom level for extent
2019-09-30 17:34:45 +02:00
Tim Schaub
526679433e Merge pull request #10045 from tschaub/immediate-geographic
Make the immediate API work with a user projection
2019-09-30 09:27:40 -06:00
Tim Schaub
b64ab8a6b2 Rendering test for immediate API with geographic coordinates 2019-09-30 08:52:07 -06:00
Tim Schaub
6c6c4ab1df Mark example as experimental 2019-09-30 08:45:44 -06:00
Tim Schaub
d3b47c794e Make the immediate API work with a user projection 2019-09-30 08:28:50 -06:00
Andreas Hocevar
8aa4a59fcf Merge pull request #10068 from ahocevar/jsdoc-plugin
Update jsdoc-plugin-typescript to 2.0.3
2019-09-30 08:47:07 +02:00
Andreas Hocevar
61e8b39626 Update jsdoc-plugin-typescript to 2.0.3 2019-09-29 21:46:50 +02:00
Tim Schaub
8c7aafd4df Merge pull request #10063 from tschaub/does-not-throw
Use the same spelling used elsewhere
2019-09-29 14:38:48 -05:00
Andreas Hocevar
37f9a6a6e9 Merge pull request #10067 from KlausBenndorf/jsdoc-event-annotations
fixed jsdoc type annotations
2019-09-29 20:02:24 +02:00
Simon Seyock
2e1dee1994 fixed jsdoc type annotations 2019-09-29 19:35:11 +02:00
Tim Schaub
ec9dcbee88 Merge pull request #10065 from openlayers/greenkeeper/mocha-6.2.1
Update mocha to the latest version 🚀
2019-09-29 10:36:09 -05:00
Tim Schaub
211c2ee531 Merge pull request #10064 from openlayers/greenkeeper/handlebars-4.4.0
Update handlebars to the latest version 🚀
2019-09-29 09:21:00 -05:00
greenkeeper[bot]
e1d3560dbf chore(package): update lockfile package-lock.json 2019-09-29 14:14:51 +00:00
greenkeeper[bot]
1d6284725d chore(package): update mocha to version 6.2.1 2019-09-29 14:14:39 +00:00
greenkeeper[bot]
c69201d5ad chore(package): update lockfile package-lock.json 2019-09-29 13:32:46 +00:00
greenkeeper[bot]
92e025b8e5 chore(package): update handlebars to version 4.4.0 2019-09-29 13:32:42 +00:00
Tim Schaub
7c8b2215d4 Remove unused code 2019-09-29 07:05:48 -06:00
Tim Schaub
d2b25533c2 Use the same spelling used elsewhere 2019-09-29 07:37:45 -05:00
mike-000
733b883ac0 Correct expected result to reflect #10054
Correct world extent constrained resolution test to expect integer zoom level
2019-09-29 12:19:42 +01:00
mike-000
eaa5af2c7a Fix for #10054
Ensure zoom level is not less than minimum integer zoom level for extent
2019-09-29 12:00:08 +01:00
Tim Schaub
1260dfc153 Merge pull request #10057 from tschaub/fewer-extensions
Remove unused test extensions
2019-09-28 19:02:02 -05:00
Tim Schaub
76df721b98 Merge pull request #10056 from tschaub/uncalled
Remove called assert extension
2019-09-28 19:01:15 -05:00
Andreas Hocevar
a55fec2759 Merge pull request #10055 from ahocevar/ensure-tile-load-sequence
Ensure proper tile load sequence
2019-09-29 01:34:59 +02:00
Tim Schaub
c984b28752 Remove unused test extensions 2019-09-28 12:02:48 -05:00
Tim Schaub
3b02f5597e Remove called assert extension 2019-09-28 18:55:38 +02:00
Andreas Hocevar
40f8510083 Merge pull request #10052 from openlayers/greenkeeper/handlebars-4.3.4
Update handlebars to the latest version 🚀
2019-09-28 15:33:38 +02:00
Andreas Hocevar
7f8fdd6219 Ensure proper tile load sequence 2019-09-28 15:24:37 +02:00
greenkeeper[bot]
ea0e1bff29 chore(package): update lockfile package-lock.json 2019-09-28 11:39:45 +00:00
greenkeeper[bot]
9b2089bc8f chore(package): update handlebars to version 4.3.4 2019-09-28 11:39:41 +00:00
Tim Schaub
32644c7ba9 Merge pull request #10051 from tschaub/unchained
Simplify the assertion
2019-09-28 08:17:09 +02:00
Tim Schaub
80b4f51d6e Merge pull request #10050 from tschaub/expect-fail
Use expect().fail() instead of expect.fail()
2019-09-28 08:15:42 +02:00
Tim Schaub
c8456868bd Simplify the assertion 2019-09-27 23:49:57 +02:00
Tim Schaub
239f5745c1 Correct fail 2019-09-27 23:23:24 +02:00
Andreas Hocevar
70706443f5 Merge pull request #10048 from ahocevar/early-empty-state
Early EMPTY state for VectorRenderTile
2019-09-27 22:29:42 +02:00
Andreas Hocevar
47dd60104d Set EMPTY state of VectorRenderTile early 2019-09-27 19:04:21 +02:00
Tim Schaub
80cf76e783 Merge pull request #10043 from tschaub/snap-geographic
User coordinates during snapping
2019-09-27 17:20:16 +02:00
Frédéric Junod
a7605c7447 Merge pull request #10042 from fredj/better_typing
Better typing
2019-09-27 16:39:26 +02:00
Andreas Hocevar
76af2b6466 Revert "Handle empty source tiles and queue them properly"
This reverts commit 818bdc411c.
2019-09-27 16:09:27 +02:00
Tim Schaub
a996d62d46 Test snap with geographic coordinates 2019-09-27 14:12:10 +02:00
Frederic Junod
f67476dd8f Mark properties as nullable 2019-09-27 13:57:59 +02:00
Frederic Junod
0e402073da Add more typecast for typescript 2019-09-27 13:11:30 +02:00
Tim Schaub
07678d960a User coordinates during snapping 2019-09-27 11:55:48 +02:00
Andreas Hocevar
a47025b9c9 Merge pull request #10040 from ahocevar/test-getclosestpoint
Additional tests for LineString
2019-09-27 11:22:29 +02:00
Andreas Hocevar
99c56a1f08 Additional tests for LineString 2019-09-27 11:10:14 +02:00
Frederic Junod
701dc3b54a Use the right variable to get the hitTolerance value 2019-09-27 11:03:21 +02:00
Frederic Junod
ea88e6cbd4 Remove invalid undefined type in params 2019-09-27 11:01:50 +02:00
Tim Schaub
b40709ea5b Merge pull request #10041 from openlayers/greenkeeper/handlebars-4.3.2
Update handlebars to the latest version 🚀
2019-09-27 09:07:09 +02:00
greenkeeper[bot]
20de880d2b chore(package): update lockfile package-lock.json 2019-09-26 22:21:37 +00:00
greenkeeper[bot]
1827d7a0d9 chore(package): update handlebars to version 4.3.2 2019-09-26 22:21:32 +00:00
Tim Schaub
400667fe95 Merge pull request #10038 from KlausBenndorf/stalebot
do not stale issues with `bug` or `pull request accepted` labels
2019-09-26 23:48:57 +02:00
Tim Schaub
d0a1fdc1d2 Merge pull request #10039 from openlayers/release-v6.0.0
🚀 Release 6
2019-09-26 23:33:42 +02:00
Simon Seyock
dd1243db73 do not stale issues with bug or pull request accepted labels 2019-09-26 22:31:37 +02:00
63 changed files with 719 additions and 452 deletions

2
.github/stale.yml vendored
View File

@@ -6,6 +6,8 @@ daysUntilClose: 7
exemptLabels:
- blocker
- regression
- bug
- 'pull request accepted'
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable

34
changelog/v6.0.1.md Normal file
View File

@@ -0,0 +1,34 @@
# 6.0.1
Hot on the heels of the 6.0 release, this patch release includes a few fixes for existing functionality. There should be nothing special needed to upgrade an application from 6.0.0 to 6.0.1. See the 6.0.0 release notes for details on upgrading from an older version.
## Changes
* [#10060](https://github.com/openlayers/openlayers/pull/10060) - Ensure zoom level is not less than minimum integer zoom level for extent ([@mike-000](https://github.com/mike-000))
* [#10045](https://github.com/openlayers/openlayers/pull/10045) - Make the immediate API work with a user projection ([@tschaub](https://github.com/tschaub))
* [#10068](https://github.com/openlayers/openlayers/pull/10068) - Update jsdoc-plugin-typescript to 2.0.3 ([@ahocevar](https://github.com/ahocevar))
* [#10063](https://github.com/openlayers/openlayers/pull/10063) - Use the same spelling used elsewhere ([@tschaub](https://github.com/tschaub))
* [#10067](https://github.com/openlayers/openlayers/pull/10067) - fixed jsdoc type annotations ([@KlausBenndorf](https://github.com/KlausBenndorf))
* [#10057](https://github.com/openlayers/openlayers/pull/10057) - Remove unused test extensions ([@tschaub](https://github.com/tschaub))
* [#10056](https://github.com/openlayers/openlayers/pull/10056) - Remove called assert extension ([@tschaub](https://github.com/tschaub))
* [#10055](https://github.com/openlayers/openlayers/pull/10055) - Ensure proper tile load sequence ([@ahocevar](https://github.com/ahocevar))
* [#10051](https://github.com/openlayers/openlayers/pull/10051) - Simplify the assertion ([@tschaub](https://github.com/tschaub))
* [#10050](https://github.com/openlayers/openlayers/pull/10050) - Use expect().fail() instead of expect.fail() ([@tschaub](https://github.com/tschaub))
* [#10048](https://github.com/openlayers/openlayers/pull/10048) - Early EMPTY state for VectorRenderTile ([@ahocevar](https://github.com/ahocevar))
* [#10043](https://github.com/openlayers/openlayers/pull/10043) - User coordinates during snapping ([@tschaub](https://github.com/tschaub))
* [#10042](https://github.com/openlayers/openlayers/pull/10042) - Better typing ([@fredj](https://github.com/fredj))
* [#10040](https://github.com/openlayers/openlayers/pull/10040) - Additional tests for LineString ([@ahocevar](https://github.com/ahocevar))
* [#10038](https://github.com/openlayers/openlayers/pull/10038) - do not stale issues with `bug` or `pull request accepted` labels ([@KlausBenndorf](https://github.com/KlausBenndorf))
* [#10039](https://github.com/openlayers/openlayers/pull/10039) - 🚀 Release 6 ([@openlayers](https://github.com/openlayers))
<details>
<summary>Dependency Updates</summary>
* [#10065](https://github.com/openlayers/openlayers/pull/10065) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10064](https://github.com/openlayers/openlayers/pull/10064) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10052](https://github.com/openlayers/openlayers/pull/10052) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
* [#10041](https://github.com/openlayers/openlayers/pull/10041) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
</details>

View File

@@ -1,6 +1,6 @@
import {Map, View} from '../src/ol/index.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import {Modify, Select, Draw} from '../src/ol/interaction.js';
import {Modify, Select, Draw, Snap} from '../src/ol/interaction.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {useGeographic} from '../src/ol/proj.js';
@@ -39,19 +39,30 @@ const draw = new Draw({
source: source
});
const snap = new Snap({
source: source
});
function removeInteractions() {
map.removeInteraction(modify);
map.removeInteraction(select);
map.removeInteraction(draw);
map.removeInteraction(select);
}
const mode = document.getElementById('mode');
function onChange() {
removeInteractions();
switch (mode.value) {
case 'draw': {
map.removeInteraction(modify);
map.removeInteraction(select);
map.addInteraction(draw);
map.addInteraction(snap);
break;
}
case 'modify': {
map.removeInteraction(draw);
map.addInteraction(select);
map.addInteraction(modify);
map.addInteraction(snap);
break;
}
default: {

View File

@@ -0,0 +1,15 @@
---
layout: example.html
title: Immediate Rendering (Geographic)
shortdesc: Using the immediate rendering API with geometries in geographic coordinates.
docs: >
This example uses the "immediate" rendering API with geometries in geographic coordinates.
The immediate rendering API lets you draw styled geometries without adding them to a layer first.
Use the `getVectorContext` function to create a rendering context from a render event. Using the
`context.drawGeometry()` and `context.setStyle()` methods on this rendering context, you can draw
any geometry on each render frame. The `useGeographic` function is used in this example so that
geometries can be in geographic coordinates.
tags: "immediate, geographic"
experimental: true
---
<div id="map" class="map"></div>

View File

@@ -0,0 +1,64 @@
import {Map, View} from '../src/ol/index.js';
import {Point} from '../src/ol/geom.js';
import TileLayer from '../src/ol/layer/Tile.js';
import Stamen from '../src/ol/source/Stamen.js';
import {Circle, Fill, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
import {useGeographic} from '../src/ol/proj.js';
import {upAndDown} from '../src/ol/easing.js';
useGeographic();
const layer = new TileLayer({
source: new Stamen({
layer: 'toner'
})
});
const map = new Map({
layers: [layer],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});
const image = new Circle({
radius: 8,
fill: new Fill({color: 'rgb(255, 153, 0)'})
});
const style = new Style({
image: image
});
const n = 1000;
const geometries = new Array(n);
for (let i = 0; i < n; ++i) {
const lon = 360 * Math.random() - 180;
const lat = 180 * Math.random() - 90;
geometries[i] = new Point([lon, lat]);
}
layer.on('postrender', function(event) {
const vectorContext = getVectorContext(event);
for (let i = 0; i < n; ++i) {
const importance = upAndDown(Math.pow((n - i) / n, 0.15));
if (importance < 0.1) {
continue;
}
image.setOpacity(importance);
image.setScale(importance);
vectorContext.setStyle(style);
vectorContext.drawGeometry(geometries[i]);
}
const lon = 360 * Math.random() - 180;
const lat = 180 * Math.random() - 90;
geometries.push(new Point([lon, lat]));
geometries.shift();
map.render();
});

171
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.0-beta.15",
"version": "6.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -5349,9 +5349,9 @@
"dev": true
},
"handlebars": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.1.tgz",
"integrity": "sha512-c0HoNHzDiHpBt4Kqe99N8tdLPKAnGCQ73gYMPWtAYM4PwGnf7xl8PBUHJqh9ijlzt2uQKaSRxbXRt+rZ7M2/kA==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.0.tgz",
"integrity": "sha512-xkRtOt3/3DzTKMOt3xahj2M/EqNhY988T+imYSlMgs5fVhLN2fmKVVj0LtEGmb+3UUYV5Qmm1052Mm3dIQxOvw==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
@@ -6455,9 +6455,9 @@
}
},
"jsdoc-plugin-typescript": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/jsdoc-plugin-typescript/-/jsdoc-plugin-typescript-2.0.2.tgz",
"integrity": "sha512-4/SveLQzTCkcQFfx9bDtVNRASmpv9E7iKncbSPkjnb+tm+9qHhCkF1Ewml3vBKZKU58LgW1zUsn4JYRlowP7NQ==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/jsdoc-plugin-typescript/-/jsdoc-plugin-typescript-2.0.3.tgz",
"integrity": "sha512-pcAHwWRyui9kUQ06L36Uyxw2m0Iy5dXqt/rGDg3cKj+2NSDZGeuw+TlbIURBJBpAkWi43zwojTtYpXo30vQJ+A==",
"dev": true
},
"jsesc": {
@@ -7298,9 +7298,9 @@
}
},
"mocha": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz",
"integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.1.tgz",
"integrity": "sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A==",
"dev": true,
"requires": {
"ansi-colors": "3.2.3",
@@ -7323,9 +7323,9 @@
"supports-color": "6.0.0",
"which": "1.3.1",
"wide-align": "1.1.3",
"yargs": "13.2.2",
"yargs-parser": "13.0.0",
"yargs-unparser": "1.5.0"
"yargs": "13.3.0",
"yargs-parser": "13.1.1",
"yargs-unparser": "1.6.0"
},
"dependencies": {
"ansi-colors": {
@@ -7340,6 +7340,17 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -7392,23 +7403,33 @@
"has-flag": "^3.0.0"
}
},
"yargs": {
"version": "13.2.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz",
"integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==",
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"cliui": "^4.0.0",
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"yargs": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.0.0"
"yargs-parser": "^13.1.1"
}
}
}
@@ -11368,9 +11389,9 @@
}
},
"yargs-parser": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz",
"integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==",
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
@@ -11386,62 +11407,80 @@
}
},
"yargs-unparser": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",
"integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
"integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
"dev": true,
"requires": {
"flat": "^4.1.0",
"lodash": "^4.17.11",
"yargs": "^12.0.5"
"lodash": "^4.17.15",
"yargs": "^13.3.0"
},
"dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"get-caller-file": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
"dev": true
},
"require-main-filename": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
"dev": true
},
"yargs": {
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"cliui": "^4.0.0",
"decamelize": "^1.2.0",
"find-up": "^3.0.0",
"get-caller-file": "^1.0.1",
"os-locale": "^3.0.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^2.0.0",
"which-module": "^2.0.0",
"y18n": "^3.2.1 || ^4.0.0",
"yargs-parser": "^11.1.1"
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"yargs-parser": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"yargs": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.1"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.0",
"version": "6.0.1",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -63,13 +63,13 @@
"fs-extra": "^8.0.0",
"glob": "^7.1.4",
"globby": "^10.0.0",
"handlebars": "4.3.1",
"handlebars": "4.4.0",
"html-to-image": "^0.1.0",
"istanbul": "0.4.5",
"istanbul-instrumenter-loader": "^3.0.1",
"jquery": "3.4.1",
"jsdoc": "3.6.3",
"jsdoc-plugin-typescript": "^2.0.2",
"jsdoc-plugin-typescript": "2.0.3",
"karma": "^4.1.0",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "^2.0.1",
@@ -80,7 +80,7 @@
"karma-webpack": "^4.0.0-rc.2",
"loglevelnext": "^3.0.1",
"marked": "0.7.0",
"mocha": "6.2.0",
"mocha": "6.2.1",
"ol-mapbox-style": "^5.0.0-beta.3",
"pixelmatch": "^5.0.0",
"pngjs": "^3.4.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -0,0 +1,40 @@
import {Map, View} from '../../../src/ol/index.js';
import {Point} from '../../../src/ol/geom.js';
import TileLayer from '../../../src/ol/layer/Tile.js';
import {useGeographic} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ.js';
import {Style, Circle, Fill} from '../../../src/ol/style.js';
import {getVectorContext} from '../../../src/ol/render.js';
useGeographic();
const center = [8.6, 50.1];
const layer = new TileLayer({
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
transition: 0
})
});
layer.on('postrender', event => {
const context = getVectorContext(event);
context.setStyle(new Style({
image: new Circle({
radius: 5,
fill: new Fill({color: 'red'})
})
}));
context.drawGeometry(new Point(center));
});
new Map({
target: 'map',
layers: [layer],
view: new View({
center: center,
zoom: 3
})
});
render();

View File

@@ -231,7 +231,7 @@ class Feature extends BaseObject {
* styles. If it is `null` the feature has no style (a `null` style).
* @param {import("./style/Style.js").StyleLike} style Style for this feature.
* @api
* @fires module:ol/events/Event~Event#event:change
* @fires module:ol/events/Event~BaseEvent#event:change
*/
setStyle(style) {
this.style_ = style;
@@ -246,7 +246,7 @@ class Feature extends BaseObject {
* {@link module:ol/source/Vector~VectorSource#getFeatureById} method.
* @param {number|string|undefined} id The feature id.
* @api
* @fires module:ol/events/Event~Event#event:change
* @fires module:ol/events/Event~BaseEvent#event:change
*/
setId(id) {
this.id_ = id;

View File

@@ -81,7 +81,7 @@ class GeolocationError extends BaseEvent {
* window.console.log(geolocation.getPosition());
* });
*
* @fires module:ol/events/Event~Event#event:error
* @fires module:ol/events/Event~BaseEvent#event:error
* @api
*/
class Geolocation extends BaseObject {
@@ -98,7 +98,7 @@ class Geolocation extends BaseObject {
/**
* The unprojected (EPSG:4326) device position.
* @private
* @type {import("./coordinate.js").Coordinate}
* @type {?import("./coordinate.js").Coordinate}
*/
this.position_ = null;

View File

@@ -59,7 +59,7 @@ class ImageWrapper extends ImageBase {
/**
* @private
* @type {function():void}
* @type {?function():void}
*/
this.unlisten_ = null;

View File

@@ -46,7 +46,7 @@ class ImageTile extends Tile {
/**
* @private
* @type {function():void}
* @type {?function():void}
*/
this.unlisten_ = null;

View File

@@ -31,13 +31,13 @@ class MapBrowserEvent extends MapEvent {
/**
* The map pixel relative to the viewport corresponding to the original browser event.
* @type {import("./pixel.js").Pixel}
* @type {?import("./pixel.js").Pixel}
*/
this.pixel_ = null;
/**
* The coordinate in the user projection corresponding to the original browser event.
* @type {import("./coordinate.js").Coordinate}
* @type {?import("./coordinate.js").Coordinate}
*/
this.coordinate_ = null;

View File

@@ -13,7 +13,7 @@ import EventType from './events/EventType.js';
* and unregistration. A generic `change` event is always available through
* {@link module:ol/Observable~Observable#changed}.
*
* @fires import("./events/Event.js").Event
* @fires import("./events/Event.js").default
* @api
*/
class Observable extends EventTarget {

View File

@@ -436,8 +436,8 @@ class Overlay extends BaseObject {
/**
* Get the extent of an element relative to the document
* @param {HTMLElement|undefined} element The element.
* @param {import("./size.js").Size|undefined} size The size of the element.
* @param {HTMLElement} element The element.
* @param {import("./size.js").Size} size The size of the element.
* @return {import("./extent.js").Extent} The extent.
* @protected
*/

View File

@@ -232,7 +232,7 @@ class PluggableMap extends BaseObject {
/**
* @private
* @type {Array<import("./events.js").EventsKey>}
* @type {?Array<import("./events.js").EventsKey>}
*/
this.layerGroupPropertyListenerKeys_ = null;
@@ -292,7 +292,7 @@ class PluggableMap extends BaseObject {
/**
* @private
* @type {Array<import("./events.js").EventsKey>}
* @type {?Array<import("./events.js").EventsKey>}
*/
this.keyHandlerKeys_ = null;
@@ -375,9 +375,9 @@ class PluggableMap extends BaseObject {
* @param {import("./control/Control.js").default} control Control.
* @this {PluggableMap}
*/
(function(control) {
function(control) {
control.setMap(this);
}).bind(this));
}.bind(this));
this.controls.addEventListener(CollectionEventType.ADD,
/**
@@ -400,9 +400,9 @@ class PluggableMap extends BaseObject {
* @param {import("./interaction/Interaction.js").default} interaction Interaction.
* @this {PluggableMap}
*/
(function(interaction) {
function(interaction) {
interaction.setMap(this);
}).bind(this));
}.bind(this));
this.interactions.addEventListener(CollectionEventType.ADD,
/**
@@ -604,7 +604,7 @@ class PluggableMap extends BaseObject {
}
const options = opt_options || /** @type {AtPixelOptions} */ ({});
const hitTolerance = options.hitTolerance !== undefined ?
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
options.hitTolerance * this.frameState_.pixelRatio : 0;
const layerFilter = options.layerFilter || TRUE;
return this.renderer_.forEachLayerAtPixel(pixel, this.frameState_, hitTolerance, callback, layerFilter);
}

View File

@@ -241,6 +241,9 @@ class Tile extends EventTarget {
* @api
*/
setState(state) {
if (this.state !== TileState.ERROR && this.state > state) {
throw new Error('Tile load sequence violation');
}
this.state = state;
this.changed();
}

View File

@@ -112,12 +112,10 @@ class TileQueue extends PriorityQueue {
if (state === TileState.ABORT) {
abortedTiles = true;
} else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
this.tilesLoadingKeys_[tileKey] = true;
++this.tilesLoading_;
++newLoads;
tile.load();
if (tile.getState() === TileState.LOADING) {
this.tilesLoadingKeys_[tileKey] = true;
++this.tilesLoading_;
++newLoads;
}
}
}
if (newLoads === 0 && abortedTiles) {

View File

@@ -97,7 +97,7 @@ class MousePosition extends Control {
/**
* @private
* @type {import("../proj/Projection.js").default}
* @type {?import("../proj/Projection.js").default}
*/
this.mapProjection_ = null;

View File

@@ -41,7 +41,7 @@ class ZoomToExtent extends Control {
});
/**
* @type {import("../extent.js").Extent}
* @type {?import("../extent.js").Extent}
* @protected
*/
this.extent = options.extent ? options.extent : null;

View File

@@ -72,6 +72,9 @@ export const CLASS_COLLAPSED = 'ol-collapsed';
* @return {FontParameters} The font families (or null if the input spec is invalid).
*/
export const getFontParameters = (function() {
/**
* @type {CSSStyleDeclaration}
*/
let style;
/**
* @type {Object<string, FontParameters>}

View File

@@ -9,14 +9,14 @@
export default {
/**
* Generic change event. Triggered when the revision counter is increased.
* @event module:ol/events/Event~Event#change
* @event module:ol/events/Event~BaseEvent#change
* @api
*/
CHANGE: 'change',
/**
* Generic error event. Triggered when an error occurs.
* @event module:ol/events/Event~Event#error
* @event module:ol/events/Event~BaseEvent#error
* @api
*/
ERROR: 'error',

View File

@@ -73,7 +73,7 @@ class TopoJSON extends JSONFeature {
/**
* @private
* @type {Array<string>}
* @type {?Array<string>}
*/
this.layers_ = options.layers ? options.layers : null;

View File

@@ -5,7 +5,7 @@ import {abstract} from '../util.js';
import BaseObject from '../Object.js';
import {createEmpty, getHeight, returnOrUpdate} from '../extent.js';
import {transform2D} from './flat/transform.js';
import {get as getProjection, getTransform, getTransformFromProjections} from '../proj.js';
import {get as getProjection, getTransform} from '../proj.js';
import Units from '../proj/Units.js';
import {create as createTransform, compose as composeTransform} from '../transform.js';
import {memoizeOne} from '../functions.js';
@@ -62,17 +62,15 @@ class Geometry extends BaseObject {
* @abstract
* @param {number} revision The geometry revision.
* @param {number} squaredTolerance Squared tolerance.
* @param {import("../proj/Projection.js").default} [sourceProjection] The source projection.
* @param {import("../proj/Projection.js").default} [destProjection] The destination projection.
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
* @return {Geometry} Simplified geometry.
*/
this.simplifyTransformedInternal = memoizeOne(function(revision, squaredTolerance, sourceProjection, destProjection) {
if (!sourceProjection || !destProjection) {
this.simplifyTransformedInternal = memoizeOne(function(revision, squaredTolerance, opt_transform) {
if (!opt_transform) {
return this.getSimplifiedGeometry(squaredTolerance);
}
const transform = getTransformFromProjections(sourceProjection, destProjection);
const clone = this.clone();
clone.applyTransform(transform);
clone.applyTransform(opt_transform);
return clone.getSimplifiedGeometry(squaredTolerance);
});
@@ -82,12 +80,11 @@ class Geometry extends BaseObject {
* Get a transformed and simplified version of the geometry.
* @abstract
* @param {number} squaredTolerance Squared tolerance.
* @param {import("../proj/Projection.js").default} sourceProjection The source projection.
* @param {import("../proj/Projection.js").default} destProjection The destination projection.
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
* @return {Geometry} Simplified geometry.
*/
simplifyTransformed(squaredTolerance, sourceProjection, destProjection) {
return this.simplifyTransformedInternal(this.getRevision(), squaredTolerance, sourceProjection, destProjection);
simplifyTransformed(squaredTolerance, opt_transform) {
return this.simplifyTransformedInternal(this.getRevision(), squaredTolerance, opt_transform);
}
/**

View File

@@ -115,7 +115,7 @@ class DragAndDrop extends Interaction {
/**
* @private
* @type {Array<import("../events.js").EventsKey>}
* @type {?Array<import("../events.js").EventsKey>}
*/
this.dropListenKeys_ = null;

View File

@@ -920,12 +920,12 @@ class Modify extends PointerInteraction {
*/
handlePointerAtPixel_(pixel, map) {
const pixelCoordinate = map.getCoordinateFromPixel(pixel);
const projection = map.getView().getProjection();
const sortByDistance = function(a, b) {
return pointDistanceToSegmentDataSquared(pixelCoordinate, a) -
pointDistanceToSegmentDataSquared(pixelCoordinate, b);
return projectedDistanceToSegmentDataSquared(pixelCoordinate, a, projection) -
projectedDistanceToSegmentDataSquared(pixelCoordinate, b, projection);
};
const projection = map.getView().getProjection();
const viewExtent = fromUserExtent(createExtent(pixelCoordinate, tempExtent), projection);
const buffer = map.getView().getResolution() * this.pixelTolerance_;
const box = toUserExtent(bufferExtent(viewExtent, buffer, tempExtent), projection);
@@ -1235,9 +1235,10 @@ function compareIndexes(a, b) {
* which to calculate the distance.
* @param {SegmentData} segmentData The object describing the line
* segment we are calculating the distance to.
* @param {import("../proj/Projection.js").default} projection The view projection.
* @return {number} The square of the distance between a point and a line segment.
*/
function pointDistanceToSegmentDataSquared(pointCoordinates, segmentData) {
function projectedDistanceToSegmentDataSquared(pointCoordinates, segmentData, projection) {
const geometry = segmentData.geometry;
if (geometry.getType() === GeometryType.CIRCLE) {
@@ -1251,7 +1252,11 @@ function pointDistanceToSegmentDataSquared(pointCoordinates, segmentData) {
return distanceToCircumference * distanceToCircumference;
}
}
return squaredDistanceToSegment(pointCoordinates, segmentData.segment);
const coordinate = fromUserCoordinate(pointCoordinates, projection);
tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
return squaredDistanceToSegment(coordinate, tempSegment);
}
/**

View File

@@ -14,6 +14,7 @@ import PointerInteraction from './Pointer.js';
import {getValues} from '../obj.js';
import VectorEventType from '../source/VectorEventType.js';
import RBush from '../structs/RBush.js';
import {fromUserCoordinate, toUserCoordinate} from '../proj.js';
/**
@@ -52,9 +53,10 @@ function getFeatureFromEvent(evt) {
} else if (/** @type {import("../Collection.js").CollectionEvent} */ (evt).element) {
return /** @type {import("../Feature.js").default} */ (/** @type {import("../Collection.js").CollectionEvent} */ (evt).element);
}
}
const tempSegment = [];
/**
* @classdesc
* Handles snapping of vector features while modifying or drawing them. The
@@ -70,10 +72,12 @@ function getFeatureFromEvent(evt) {
*
* import Snap from 'ol/interaction/Snap';
*
* var snap = new Snap({
* const snap = new Snap({
* source: source
* });
*
* map.addInteraction(snap);
*
* @api
*/
class Snap extends PointerInteraction {
@@ -149,13 +153,6 @@ class Snap extends PointerInteraction {
*/
this.pendingFeatures_ = {};
/**
* Used for distance sorting in sortByDistance_
* @type {import("../coordinate.js").Coordinate}
* @private
*/
this.pixelCoordinate_ = null;
/**
* @type {number}
* @private
@@ -163,13 +160,6 @@ class Snap extends PointerInteraction {
this.pixelTolerance_ = options.pixelTolerance !== undefined ?
options.pixelTolerance : 10;
/**
* @type {function(SegmentData, SegmentData): number}
* @private
*/
this.sortByDistance_ = sortByDistance.bind(this);
/**
* Segment RTree for each layer
* @type {import("../structs/RBush.js").default<SegmentData>}
@@ -177,22 +167,21 @@ class Snap extends PointerInteraction {
*/
this.rBush_ = new RBush();
/**
* @const
* @private
* @type {Object<string, function(import("../Feature.js").default, import("../geom/Geometry.js").default): void>}
*/
this.SEGMENT_WRITERS_ = {
'Point': this.writePointGeometry_,
'LineString': this.writeLineStringGeometry_,
'LinearRing': this.writeLineStringGeometry_,
'Polygon': this.writePolygonGeometry_,
'MultiPoint': this.writeMultiPointGeometry_,
'MultiLineString': this.writeMultiLineStringGeometry_,
'MultiPolygon': this.writeMultiPolygonGeometry_,
'GeometryCollection': this.writeGeometryCollectionGeometry_,
'Circle': this.writeCircleGeometry_
'Point': this.writePointGeometry_.bind(this),
'LineString': this.writeLineStringGeometry_.bind(this),
'LinearRing': this.writeLineStringGeometry_.bind(this),
'Polygon': this.writePolygonGeometry_.bind(this),
'MultiPoint': this.writeMultiPointGeometry_.bind(this),
'MultiLineString': this.writeMultiLineStringGeometry_.bind(this),
'MultiPolygon': this.writeMultiPolygonGeometry_.bind(this),
'GeometryCollection': this.writeGeometryCollectionGeometry_.bind(this),
'Circle': this.writeCircleGeometry_.bind(this)
};
}
@@ -211,7 +200,7 @@ class Snap extends PointerInteraction {
const segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()];
if (segmentWriter) {
this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(createEmpty());
segmentWriter.call(this, feature, geometry);
segmentWriter(feature, geometry);
}
}
@@ -383,10 +372,9 @@ class Snap extends PointerInteraction {
* @return {Result} Snap result
*/
snapTo(pixel, pixelCoordinate, map) {
const lowerLeft = map.getCoordinateFromPixelInternal(
const lowerLeft = map.getCoordinateFromPixel(
[pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
const upperRight = map.getCoordinateFromPixelInternal(
const upperRight = map.getCoordinateFromPixel(
[pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
const box = boundingExtent([lowerLeft, upperRight]);
@@ -400,57 +388,78 @@ class Snap extends PointerInteraction {
});
}
let snappedToVertex = false;
let snapped = false;
let vertex = null;
let vertexPixel = null;
let dist, pixel1, pixel2, squaredDist1, squaredDist2;
if (segments.length > 0) {
this.pixelCoordinate_ = pixelCoordinate;
segments.sort(this.sortByDistance_);
const closestSegment = segments[0].segment;
const isCircle = segments[0].feature.getGeometry().getType() ===
GeometryType.CIRCLE;
if (this.vertex_ && !this.edge_) {
pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]);
pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]);
squaredDist1 = squaredCoordinateDistance(pixel, pixel1);
squaredDist2 = squaredCoordinateDistance(pixel, pixel2);
dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
snappedToVertex = dist <= this.pixelTolerance_;
if (snappedToVertex) {
snapped = true;
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
vertexPixel = map.getPixelFromCoordinateInternal(vertex);
}
} else if (this.edge_) {
if (isCircle) {
vertex = closestOnCircle(pixelCoordinate,
/** @type {import("../geom/Circle.js").default} */ (segments[0].feature.getGeometry()));
} else {
vertex = closestOnSegment(pixelCoordinate, closestSegment);
}
vertexPixel = map.getPixelFromCoordinateInternal(vertex);
if (coordinateDistance(pixel, vertexPixel) <= this.pixelTolerance_) {
snapped = true;
if (this.vertex_ && !isCircle) {
pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]);
pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]);
squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
snappedToVertex = dist <= this.pixelTolerance_;
if (snappedToVertex) {
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
vertexPixel = map.getPixelFromCoordinateInternal(vertex);
}
if (segments.length === 0) {
return {
snapped: snapped,
vertex: vertex,
vertexPixel: vertexPixel
};
}
const projection = map.getView().getProjection();
const projectedCoordinate = fromUserCoordinate(pixelCoordinate, projection);
let closestSegmentData;
let minSquaredDistance = Infinity;
for (let i = 0; i < segments.length; ++i) {
const segmentData = segments[i];
tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
const delta = squaredDistanceToSegment(projectedCoordinate, tempSegment);
if (delta < minSquaredDistance) {
closestSegmentData = segmentData;
minSquaredDistance = delta;
}
}
const closestSegment = closestSegmentData.segment;
if (this.vertex_ && !this.edge_) {
const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
const squaredDist1 = squaredCoordinateDistance(pixel, pixel1);
const squaredDist2 = squaredCoordinateDistance(pixel, pixel2);
const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
if (dist <= this.pixelTolerance_) {
snapped = true;
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
vertexPixel = map.getPixelFromCoordinate(vertex);
}
} else if (this.edge_) {
const isCircle = closestSegmentData.feature.getGeometry().getType() === GeometryType.CIRCLE;
if (isCircle) {
vertex = closestOnCircle(pixelCoordinate,
/** @type {import("../geom/Circle.js").default} */ (closestSegmentData.feature.getGeometry()));
} else {
tempSegment[0] = fromUserCoordinate(closestSegment[0], projection);
tempSegment[1] = fromUserCoordinate(closestSegment[1], projection);
vertex = toUserCoordinate(closestOnSegment(projectedCoordinate, tempSegment), projection);
}
vertexPixel = map.getPixelFromCoordinate(vertex);
if (coordinateDistance(pixel, vertexPixel) <= this.pixelTolerance_) {
snapped = true;
if (this.vertex_ && !isCircle) {
const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
const squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
const squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
if (dist <= this.pixelTolerance_) {
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
vertexPixel = map.getPixelFromCoordinate(vertex);
}
}
}
if (snapped) {
vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
}
}
if (snapped) {
vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
}
return {
snapped: snapped,
vertex: vertex,
@@ -495,7 +504,7 @@ class Snap extends PointerInteraction {
for (let i = 0; i < geometries.length; ++i) {
const segmentWriter = this.SEGMENT_WRITERS_[geometries[i].getType()];
if (segmentWriter) {
segmentWriter.call(this, feature, geometries[i]);
segmentWriter(feature, geometries[i]);
}
}
}
@@ -613,17 +622,4 @@ class Snap extends PointerInteraction {
}
/**
* Sort segments by distance, helper function
* @param {SegmentData} a The first segment data.
* @param {SegmentData} b The second segment data.
* @return {number} The difference in distance.
* @this {Snap}
*/
function sortByDistance(a, b) {
const deltaA = squaredDistanceToSegment(this.pixelCoordinate_, a.segment);
const deltaB = squaredDistanceToSegment(this.pixelCoordinate_, b.segment);
return deltaA - deltaB;
}
export default Snap;

View File

@@ -5,11 +5,6 @@ import BaseImageLayer from './BaseImage.js';
import CanvasImageLayerRenderer from '../renderer/canvas/ImageLayer.js';
/**
* @typedef {import("./BaseImage.js").Options} Options
*/
/**
* @classdesc
* Server-rendered images that are available for arbitrary extents and
@@ -23,7 +18,7 @@ import CanvasImageLayerRenderer from '../renderer/canvas/ImageLayer.js';
class ImageLayer extends BaseImageLayer {
/**
* @param {Options=} opt_options Layer options.
* @param {import("./BaseImage.js").Options=} opt_options Layer options.
*/
constructor(opt_options) {
super(opt_options);

View File

@@ -9,6 +9,8 @@ import {
scale as scaleTransform
} from './transform.js';
import CanvasImmediateRenderer from './render/canvas/Immediate.js';
import {getSquaredTolerance} from './renderer/vector.js';
import {getUserProjection, getTransformFromProjections} from './proj.js';
/**
@@ -92,9 +94,15 @@ export function toContext(context, opt_options) {
export function getVectorContext(event) {
const frameState = event.frameState;
const transform = multiplyTransform(event.inversePixelTransform.slice(), frameState.coordinateToPixelTransform);
const squaredTolerance = getSquaredTolerance(frameState.viewState.resolution, frameState.pixelRatio);
let userTransform;
const userProjection = getUserProjection();
if (userProjection) {
userTransform = getTransformFromProjections(userProjection, frameState.viewState.projection);
}
return new CanvasImmediateRenderer(
event.context, frameState.pixelRatio, frameState.extent, transform,
frameState.viewState.rotation);
frameState.viewState.rotation, squaredTolerance, userTransform);
}
/**

View File

@@ -204,11 +204,10 @@ class RenderFeature {
* Get a transformed and simplified version of the geometry.
* @abstract
* @param {number} squaredTolerance Squared tolerance.
* @param {import("../proj/Projection.js").default} sourceProjection The source projection.
* @param {import("../proj/Projection.js").default} destProjection The destination projection.
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
* @return {RenderFeature} Simplified geometry.
*/
simplifyTransformed(squaredTolerance, sourceProjection, destProjection) {
simplifyTransformed(squaredTolerance, opt_transform) {
return this;
}

View File

@@ -300,6 +300,9 @@ function getMeasureContext() {
* @return {import("../size.js").Size} Measurement.
*/
export const measureTextHeight = (function() {
/**
* @type {HTMLDivElement}
*/
let div;
const heights = textHeights;
return function(font) {

View File

@@ -31,8 +31,10 @@ class CanvasImmediateRenderer extends VectorContext {
* @param {import("../../extent.js").Extent} extent Extent.
* @param {import("../../transform.js").Transform} transform Transform.
* @param {number} viewRotation View rotation.
* @param {number=} opt_squaredTolerance Optional squared tolerance for simplification.
* @param {import("../../proj.js").TransformFunction=} opt_userTransform Transform from user to view projection.
*/
constructor(context, pixelRatio, extent, transform, viewRotation) {
constructor(context, pixelRatio, extent, transform, viewRotation, opt_squaredTolerance, opt_userTransform) {
super();
/**
@@ -65,6 +67,18 @@ class CanvasImmediateRenderer extends VectorContext {
*/
this.viewRotation_ = viewRotation;
/**
* @private
* @type {number}
*/
this.squaredTolerance_ = opt_squaredTolerance;
/**
* @private
* @type {import("../../proj.js").TransformFunction}
*/
this.userTransform_ = opt_userTransform;
/**
* @private
* @type {?import("../canvas.js").FillState}
@@ -505,6 +519,9 @@ class CanvasImmediateRenderer extends VectorContext {
* @override
*/
drawPoint(geometry) {
if (this.squaredTolerance_) {
geometry = /** @type {import("../../geom/Point.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
}
const flatCoordinates = geometry.getFlatCoordinates();
const stride = geometry.getStride();
if (this.image_) {
@@ -523,6 +540,9 @@ class CanvasImmediateRenderer extends VectorContext {
* @override
*/
drawMultiPoint(geometry) {
if (this.squaredTolerance_) {
geometry = /** @type {import("../../geom/MultiPoint.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
}
const flatCoordinates = geometry.getFlatCoordinates();
const stride = geometry.getStride();
if (this.image_) {
@@ -541,6 +561,9 @@ class CanvasImmediateRenderer extends VectorContext {
* @override
*/
drawLineString(geometry) {
if (this.squaredTolerance_) {
geometry = /** @type {import("../../geom/LineString.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
}
if (!intersects(this.extent_, geometry.getExtent())) {
return;
}
@@ -567,6 +590,9 @@ class CanvasImmediateRenderer extends VectorContext {
* @override
*/
drawMultiLineString(geometry) {
if (this.squaredTolerance_) {
geometry = /** @type {import("../../geom/MultiLineString.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
}
const geometryExtent = geometry.getExtent();
if (!intersects(this.extent_, geometryExtent)) {
return;
@@ -598,6 +624,9 @@ class CanvasImmediateRenderer extends VectorContext {
* @override
*/
drawPolygon(geometry) {
if (this.squaredTolerance_) {
geometry = /** @type {import("../../geom/Polygon.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
}
if (!intersects(this.extent_, geometry.getExtent())) {
return;
}
@@ -632,6 +661,9 @@ class CanvasImmediateRenderer extends VectorContext {
* @override
*/
drawMultiPolygon(geometry) {
if (this.squaredTolerance_) {
geometry = /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
}
if (!intersects(this.extent_, geometry.getExtent())) {
return;
}

View File

@@ -4,7 +4,7 @@
import {getUid} from '../../util.js';
import ViewHint from '../../ViewHint.js';
import {buffer, createEmpty, containsExtent, getWidth, intersects as intersectsExtent} from '../../extent.js';
import {fromUserExtent, toUserExtent, getUserProjection} from '../../proj.js';
import {fromUserExtent, toUserExtent, getUserProjection, getTransformFromProjections} from '../../proj.js';
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import ExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
import CanvasLayerRenderer from './Layer.js';
@@ -307,8 +307,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
pixelRatio, vectorLayer.getDeclutter());
const userProjection = getUserProjection();
let userTransform;
if (userProjection) {
vectorSource.loadFeatures(toUserExtent(extent, projection), resolution, userProjection);
userTransform = getTransformFromProjections(userProjection, projection);
} else {
vectorSource.loadFeatures(extent, resolution, projection);
}
@@ -326,7 +328,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
styles = styleFunction(feature, resolution);
}
if (styles) {
const dirty = this.renderFeature(feature, squaredTolerance, styles, replayGroup, projection);
const dirty = this.renderFeature(feature, squaredTolerance, styles, replayGroup, userTransform);
this.dirty_ = this.dirty_ || dirty;
}
}.bind(this);
@@ -370,10 +372,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
* @param {number} squaredTolerance Squared render tolerance.
* @param {import("../../style/Style.js").default|Array<import("../../style/Style.js").default>} styles The style or array of styles.
* @param {import("../../render/canvas/BuilderGroup.js").default} builderGroup Builder group.
* @param {import("../../proj/Projection.js").default} projection The view projection.
* @param {import("../../proj.js").TransformFunction} opt_transform Transform from user to view projection.
* @return {boolean} `true` if an image is loading.
*/
renderFeature(feature, squaredTolerance, styles, builderGroup, projection) {
renderFeature(feature, squaredTolerance, styles, builderGroup, opt_transform) {
if (!styles) {
return false;
}
@@ -382,12 +384,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
for (let i = 0, ii = styles.length; i < ii; ++i) {
loading = renderFeature(
builderGroup, feature, styles[i], squaredTolerance,
this.boundHandleStyleImageChange_, projection) || loading;
this.boundHandleStyleImageChange_, opt_transform) || loading;
}
} else {
loading = renderFeature(
builderGroup, feature, styles, squaredTolerance,
this.boundHandleStyleImageChange_, projection);
this.boundHandleStyleImageChange_, opt_transform);
}
return loading;
}

View File

@@ -5,7 +5,6 @@ import {getUid} from '../util.js';
import ImageState from '../ImageState.js';
import GeometryType from '../geom/GeometryType.js';
import BuilderType from '../render/canvas/BuilderType.js';
import {getUserProjection} from '../proj.js';
/**
@@ -93,11 +92,11 @@ function renderCircleGeometry(builderGroup, geometry, style, feature) {
* @param {import("../style/Style.js").default} style Style.
* @param {number} squaredTolerance Squared tolerance.
* @param {function(import("../events/Event.js").default): void} listener Listener function.
* @param {import("../proj/Projection.js").default} [projection] The view projection.
* @param {import("../proj.js").TransformFunction} [opt_transform] Transform from user to view projection.
* @return {boolean} `true` if style is loading.
* @template T
*/
export function renderFeature(replayGroup, feature, style, squaredTolerance, listener, projection) {
export function renderFeature(replayGroup, feature, style, squaredTolerance, listener, opt_transform) {
let loading = false;
const imageStyle = style.getImage();
if (imageStyle) {
@@ -113,7 +112,7 @@ export function renderFeature(replayGroup, feature, style, squaredTolerance, lis
loading = true;
}
}
renderFeatureInternal(replayGroup, feature, style, squaredTolerance, projection);
renderFeatureInternal(replayGroup, feature, style, squaredTolerance, opt_transform);
return loading;
}
@@ -124,14 +123,14 @@ export function renderFeature(replayGroup, feature, style, squaredTolerance, lis
* @param {import("../Feature.js").FeatureLike} feature Feature.
* @param {import("../style/Style.js").default} style Style.
* @param {number} squaredTolerance Squared tolerance.
* @param {import("../proj/Projection.js").default} [projection] The view projection.
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
*/
function renderFeatureInternal(replayGroup, feature, style, squaredTolerance, projection) {
function renderFeatureInternal(replayGroup, feature, style, squaredTolerance, opt_transform) {
const geometry = style.getGeometryFunction()(feature);
if (!geometry) {
return;
}
const simplifiedGeometry = geometry.simplifyTransformed(squaredTolerance, getUserProjection(), projection);
const simplifiedGeometry = geometry.simplifyTransformed(squaredTolerance, opt_transform);
const renderer = style.getRenderer();
if (renderer) {
renderGeometry(replayGroup, simplifiedGeometry, style, feature);

View File

@@ -109,7 +109,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
/**
* @param {import("../../layer/Layer.js").default} layer Layer.
* @param {Options=} options Options.
* @param {Options} options Options.
*/
constructor(layer, options) {
const uniforms = options.uniforms || {};

View File

@@ -104,7 +104,7 @@ class ReprojTile extends Tile {
/**
* @private
* @type {Array<import("../events.js").EventsKey>}
* @type {?Array<import("../events.js").EventsKey>}
*/
this.sourcesListenerKeys_ = null;

View File

@@ -127,10 +127,14 @@ export function createSnapToPower(power, maxResolution, opt_minResolution, opt_s
return getSmoothClampedResolution(resolution, cappedMaxRes, minResolution);
}
const offset = -direction * (0.5 - 1e-9) + 0.5;
const tolerance = 1e-9;
const minZoomLevel = Math.ceil(
Math.log(maxResolution / cappedMaxRes) / Math.log(power) - tolerance);
const offset = -direction * (0.5 - tolerance) + 0.5;
const capped = Math.min(cappedMaxRes, resolution);
const zoomLevel = Math.floor(
const cappedZoomLevel = Math.floor(
Math.log(maxResolution / capped) / Math.log(power) + offset);
const zoomLevel = Math.max(minZoomLevel, cappedZoomLevel);
const newResolution = maxResolution / Math.pow(power, zoomLevel);
return clamp(newResolution, minResolution, cappedMaxRes);
} else {

View File

@@ -81,7 +81,7 @@ class TileWMS extends TileImage {
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options ? opt_options : /** @type {Options} */ ({});
const params = options.params || {};

View File

@@ -10,7 +10,6 @@ import UrlTile from './UrlTile.js';
import {getKeyZXY, getKey} from '../tilecoord.js';
import {createXYZ, extentFromProjection, createForProjection} from '../tilegrid.js';
import {buffer as bufferExtent, getIntersection, intersects} from '../extent.js';
import {listen, unlistenByKey} from '../events.js';
import EventType from '../events/EventType.js';
import {loadFeaturesXhr} from '../featureloader.js';
import {isEmpty} from '../obj.js';
@@ -200,11 +199,10 @@ class VectorTile extends UrlTile {
const minZoom = sourceTileGrid.getMinZoom();
const previousSourceTiles = this.sourceTilesByTileKey_[tile.getKey()];
let sourceTiles, covered, empty, loadedZ;
let sourceTiles, covered, loadedZ;
if (previousSourceTiles && previousSourceTiles.length > 0 && previousSourceTiles[0].tileCoord[0] === sourceZ) {
sourceTiles = previousSourceTiles;
covered = true;
empty = false;
loadedZ = sourceZ;
} else {
sourceTiles = [];
@@ -212,7 +210,6 @@ class VectorTile extends UrlTile {
do {
--loadedZ;
covered = true;
empty = true;
sourceTileGrid.forEachTileCoord(extent, loadedZ, function(sourceTileCoord) {
const coordKey = getKey(sourceTileCoord);
let sourceTile;
@@ -220,7 +217,6 @@ class VectorTile extends UrlTile {
sourceTile = this.sourceTileByCoordKey_[coordKey];
const state = sourceTile.getState();
if (state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) {
empty = empty && state === TileState.EMPTY;
sourceTiles.push(sourceTile);
return;
}
@@ -233,28 +229,25 @@ class VectorTile extends UrlTile {
sourceTile.projection = projection;
sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
this.sourceTileByCoordKey_[coordKey] = sourceTile;
empty = false;
sourceTile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this));
sourceTile.load();
} else {
sourceTile = null;
}
} else {
empty = false;
}
covered = false;
if (sourceTile === undefined) {
if (!sourceTile) {
return;
}
if (sourceTile !== null && tile.getState() === TileState.IDLE) {
if (sourceTile.getState() !== TileState.EMPTY && tile.getState() === TileState.IDLE) {
tile.loadingSourceTiles++;
const key = listen(sourceTile, EventType.CHANGE, function() {
const onSourceTileChange = function() {
const state = sourceTile.getState();
const sourceTileKey = sourceTile.getKey();
if (state === TileState.LOADED || state === TileState.ERROR) {
if (state === TileState.LOADED) {
unlistenByKey(key);
sourceTile.removeEventListener(EventType.CHANGE, onSourceTileChange);
tile.loadingSourceTiles--;
// eslint-disable-next-line no-use-before-define
tile.removeEventListener(EventType.CHANGE, onTileChange);
delete tile.errorSourceTileKeys[sourceTileKey];
} else if (state === TileState.ERROR) {
tile.errorSourceTileKeys[sourceTileKey] = true;
@@ -265,7 +258,15 @@ class VectorTile extends UrlTile {
tile.setState(isEmpty(tile.errorSourceTileKeys) ? TileState.LOADED : TileState.ERROR);
}
}
});
};
const onTileChange = function() {
if (tile.getState() === TileState.ABORT) {
sourceTile.removeEventListener(EventType.CHANGE, onSourceTileChange);
tile.removeEventListener(EventType.CHANGE, onTileChange);
}
};
sourceTile.addEventListener(EventType.CHANGE, onSourceTileChange);
tile.addEventListener(EventType.CHANGE, onTileChange);
}
}.bind(this));
if (!covered) {
@@ -274,14 +275,14 @@ class VectorTile extends UrlTile {
} while (!covered && loadedZ > minZoom);
}
if (!empty && tile.getState() === TileState.IDLE) {
if (tile.getState() === TileState.IDLE) {
tile.setState(TileState.LOADING);
}
if (covered || empty) {
if (covered) {
tile.hifi = sourceZ === loadedZ;
tile.sourceZ = loadedZ;
if (tile.getState() < TileState.LOADED) {
tile.setState(empty ? TileState.EMPTY : TileState.LOADED);
tile.setState(TileState.LOADED);
} else if (!previousSourceTiles || !equals(sourceTiles, previousSourceTiles)) {
this.removeSourceTiles(tile);
this.addSourceTiles(tile, sourceTiles);
@@ -336,8 +337,8 @@ class VectorTile extends UrlTile {
const tileCoord = [z, x, y];
let urlTileCoord = this.getTileCoordForTileUrlFunction(tileCoord, projection);
const sourceExtent = this.getTileGrid().getExtent();
const tileGrid = this.getTileGridForProjection(projection);
if (urlTileCoord && sourceExtent) {
const tileGrid = this.getTileGridForProjection(projection);
const tileExtent = tileGrid.getTileCoordExtent(urlTileCoord);
// make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
bufferExtent(tileExtent, -tileGrid.getResolution(z), tileExtent);
@@ -345,9 +346,21 @@ class VectorTile extends UrlTile {
urlTileCoord = null;
}
}
let empty = true;
if (urlTileCoord !== null) {
const sourceTileGrid = this.tileGrid;
const resolution = tileGrid.getResolution(z);
const sourceZ = sourceTileGrid.getZForResolution(resolution, 1);
// make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
const extent = tileGrid.getTileCoordExtent(urlTileCoord);
bufferExtent(extent, -resolution, extent);
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
empty = empty && !this.tileUrlFunction(sourceTileCoord, pixelRatio, projection);
}.bind(this));
}
const newTile = new VectorRenderTile(
tileCoord,
urlTileCoord !== null ? TileState.IDLE : TileState.EMPTY,
empty ? TileState.EMPTY : TileState.IDLE,
urlTileCoord,
this.tileGrid,
this.getSourceTiles.bind(this, pixelRatio, projection),

View File

@@ -22,7 +22,7 @@ import EventType from '../events/EventType.js';
* Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring
* items from the cache is the responsibility of the user.
*
* @fires import("../events/Event.js").Event
* @fires import("../events/Event.js").default
* @template T
*/
class LRUCache extends EventTarget {
@@ -96,7 +96,7 @@ class LRUCache extends EventTarget {
/**
* @param {function(T, string, LRUCache): ?} f The function
* @param {function(T, string, LRUCache<T>): ?} f The function
* to call for every entry from the oldest to the newer. This function takes
* 3 arguments (the entry value, the entry key and the LRUCache object).
* The return value is ignored.

View File

@@ -53,7 +53,7 @@ class IconImage extends EventTarget {
/**
* @private
* @type {function():void}
* @type {?function():void}
*/
this.unlisten_ = null;

View File

@@ -101,7 +101,7 @@ const DEFAULT_FRAGMENT_SHADER = `
class WebGLPostProcessingPass {
/**
* @param {Options=} options Options.
* @param {Options} options Options.
*/
constructor(options) {
this.gl_ = options.webGlContext;

View File

@@ -95,7 +95,7 @@ describe('ol.collection', function() {
describe('on an empty collection', function() {
it('does not call the callback', function() {
collection.forEach(cb);
expect(cb).to.not.be.called();
expect(cb.called).to.be(false);
});
});
describe('on a non-empty collection', function() {
@@ -120,7 +120,7 @@ describe('ol.collection', function() {
const cb = sinon.spy();
listen(collection, CollectionEventType.REMOVE, cb);
expect(collection.remove(1)).to.eql(1);
expect(cb).to.be.called();
expect(cb.called).to.be(true);
expect(cb.lastCall.args[0].element).to.eql(1);
});
it('does not remove more than one matching element', function() {
@@ -216,21 +216,21 @@ describe('ol.collection', function() {
describe('insertAt', function() {
it('triggers change:length event', function() {
collection.insertAt(2, 3);
expect(cb).to.be.called();
expect(cb.called).to.be(true);
});
});
describe('removeAt', function() {
it('triggers change:length event', function() {
collection.removeAt(0);
expect(cb).to.be.called();
expect(cb.called).to.be(true);
});
});
describe('setAt', function() {
it('does not trigger change:length event', function() {
collection.setAt(1, 1);
expect(cb).to.not.be.called();
expect(cb.called).to.be(false);
});
});
});

View File

@@ -2,21 +2,6 @@
describe('expect.js', function() {
describe('arreqlNaN', function() {
it('considers NaN in array to be equal', function() {
expect([1, NaN, 2]).to.arreqlNaN([1, NaN, 2]);
expect([1, NaN, 2]).not.to.arreqlNaN([1, 1.5, 2]);
});
it('allows a mix of number and string', function() {
expect([1, NaN, 'foo']).to.arreqlNaN([1, NaN, 'foo']);
expect([1, NaN, 'foo']).not.to.arreqlNaN([1, NaN, 'bar']);
expect([1, NaN]).not.to.arreqlNaN([1, 'foo']);
});
});
describe('roughlyEqual', function() {
it('can tell the difference between 1 and 3', function() {
@@ -42,38 +27,6 @@ describe('expect.js', function() {
});
describe('called', function() {
let telephone;
beforeEach(function() {
telephone = sinon.spy();
});
it('has caller ID', function() {
telephone();
expect(telephone).to.be.called();
});
it('also knows when it\'s speaking to the hand', function() {
(function() {})();
expect(telephone).not.to.be.called();
});
it('reminds you that you forgot', function() {
expect(function() {
expect(telephone).to.be.called();
}).to.throwException();
});
it('gets moody all too quickly', function() {
telephone();
expect(function() {
expect(telephone).not.to.be.called();
}).to.throwException();
});
});
describe('Test equality of XML documents - xmleql', function() {
it('Test XML document with single root, different prefix', function() {

View File

@@ -208,7 +208,7 @@ describe('ol.Feature', function() {
expect(feature.getGeometry()).to.be(point2);
feature.on('change', function() {
expect.fail();
expect().fail();
});
point.setCoordinates([0, 2]);
});

View File

@@ -73,6 +73,12 @@ describe('ol.geom.LineString', function() {
expect(lineString.getStride()).to.be(2);
});
describe('#intersectsCoordinate', function() {
it('returns true for an intersecting coordinate', function() {
expect(lineString.intersectsCoordinate([1.5, 2.5])).to.be(true);
});
});
describe('#intersectsExtent', function() {
it('return false for non matching extent', function() {
@@ -89,6 +95,23 @@ describe('ol.geom.LineString', function() {
});
describe('#intersectsCoordinate', function() {
it('detects intersecting coordinates', function() {
expect(lineString.intersectsCoordinate([1, 2])).to.be(true);
});
});
describe('#getClosestPoint', function() {
it('uses existing vertices', function() {
const closestPoint = lineString.getClosestPoint([0.9, 1.8]);
expect(closestPoint).to.eql([1, 2]);
});
});
describe('#getCoordinateAt', function() {
it('return the first point when fraction is 0', function() {

View File

@@ -1,5 +1,5 @@
import Point from '../../../../src/ol/geom/Point.js';
import {get as getProjection} from '../../../../src/ol/proj.js';
import {get as getProjection, getTransformFromProjections} from '../../../../src/ol/proj.js';
describe('ol.geom.Point', function() {
@@ -161,9 +161,10 @@ describe('ol.geom.Point', function() {
const geom = new Point([1, 2]);
const source = getProjection('EPSG:4326');
const dest = getProjection('EPSG:3857');
const transform = getTransformFromProjections(source, dest);
const squaredTolerance = 0.5;
const first = geom.simplifyTransformed(squaredTolerance, source, dest);
const second = geom.simplifyTransformed(squaredTolerance, source, dest);
const first = geom.simplifyTransformed(squaredTolerance, transform);
const second = geom.simplifyTransformed(squaredTolerance, transform);
expect(second).to.be(first);
});
@@ -171,9 +172,10 @@ describe('ol.geom.Point', function() {
const geom = new Point([1, 2]);
const source = getProjection('EPSG:4326');
const dest = getProjection('EPSG:3857');
const transform = getTransformFromProjections(source, dest);
const squaredTolerance = 0.5;
const first = geom.simplifyTransformed(squaredTolerance, source, dest);
const second = geom.simplifyTransformed(squaredTolerance * 2, source, dest);
const first = geom.simplifyTransformed(squaredTolerance, transform);
const second = geom.simplifyTransformed(squaredTolerance * 2, transform);
expect(second).not.to.be(first);
});
@@ -181,11 +183,12 @@ describe('ol.geom.Point', function() {
const geom = new Point([1, 2]);
const source = getProjection('EPSG:4326');
const dest = getProjection('EPSG:3857');
const transform = getTransformFromProjections(source, dest);
const squaredTolerance = 0.5;
const first = geom.simplifyTransformed(squaredTolerance, source, dest);
const first = geom.simplifyTransformed(squaredTolerance, transform);
geom.setCoordinates([3, 4]);
const second = geom.simplifyTransformed(squaredTolerance * 2, source, dest);
const second = geom.simplifyTransformed(squaredTolerance * 2, transform);
expect(second).not.to.be(first);
});

View File

@@ -15,8 +15,8 @@ describe('HTML Image loading', function() {
listenImage(img, handleLoad, handleError);
setTimeout(function() {
expect(handleLoad).to.be.called();
expect(handleError).not.to.be.called();
expect(handleLoad.called).to.be(true);
expect(handleError.called).to.be(false);
done();
}, 200);
});
@@ -26,8 +26,8 @@ describe('HTML Image loading', function() {
img.src = 'spec/ol/data/dot.png';
setTimeout(function() {
expect(handleLoad).to.be.called();
expect(handleError).not.to.be.called();
expect(handleLoad.called).to.be(true);
expect(handleError.called).to.be(false);
done();
}, 200);
});
@@ -37,8 +37,8 @@ describe('HTML Image loading', function() {
listenImage(img, handleLoad, handleError);
setTimeout(function() {
expect(handleLoad).not.to.be.called();
expect(handleError).to.be.called();
expect(handleLoad.called).to.be(false);
expect(handleError.called).to.be(true);
done();
}, 200);
});
@@ -48,8 +48,8 @@ describe('HTML Image loading', function() {
listenImage(img, handleLoad, handleError)();
setTimeout(function() {
expect(handleLoad).not.to.be.called();
expect(handleError).not.to.be.called();
expect(handleLoad.called).to.be(false);
expect(handleError.called).to.be(false);
done();
}, 200);
});

View File

@@ -216,8 +216,8 @@ describe('ol.interaction.Draw', function() {
simulateEvent('pointermove', 10, 20);
simulateEvent('pointerdown', 10, 20);
simulateEvent('pointerup', 10, 20);
expect(ds).to.be.called();
expect(de).to.be.called();
expect(ds.called).to.be(true);
expect(de.called).to.be(true);
simulateEvent('pointermove', 20, 20);
expect(ds.callCount).to.be(1);
expect(de.callCount).to.be(1);
@@ -390,7 +390,6 @@ describe('ol.interaction.Draw', function() {
simulateEvent('pointerup', 60, 70);
const features = source.getFeatures();
// expect(features).to.have.length(1);
const geometry = features[0].getGeometry();
expect(geometry).to.be.a(LineString);
expect(geometry.getCoordinates()).to.eql(
@@ -478,9 +477,9 @@ describe('ol.interaction.Draw', function() {
simulateEvent('pointerup', 30, 20);
simulateEvent('pointermove', 10, 20);
expect(ds).to.be.called();
expect(ds.called).to.be(true);
expect(ds.callCount).to.be(1);
expect(de).to.be.called();
expect(de.called).to.be(true);
expect(de.callCount).to.be(1);
});
@@ -801,9 +800,9 @@ describe('ol.interaction.Draw', function() {
simulateEvent('pointerdown', 10, 20);
simulateEvent('pointerup', 10, 20);
expect(ds).to.be.called();
expect(ds.called).to.be(true);
expect(ds.callCount).to.be(1);
expect(de).to.be.called();
expect(de.called).to.be(true);
expect(de.callCount).to.be(1);
});
@@ -963,9 +962,9 @@ describe('ol.interaction.Draw', function() {
simulateEvent('pointerdown', 30, 20);
simulateEvent('pointerup', 30, 20);
expect(ds).to.be.called();
expect(ds.called).to.be(true);
expect(ds.callCount).to.be(1);
expect(de).to.be.called();
expect(de.called).to.be(true);
expect(de.callCount).to.be(1);
});

View File

@@ -708,7 +708,7 @@ describe('ol.interaction.Modify', function() {
collection.remove(features[0]);
expect(function() {
simulateEvent('pointerup', -10, -10, null, 0);
}).to.not.throwError();
}).to.not.throwException();
});
});

View File

@@ -6,6 +6,8 @@ import Circle from '../../../../src/ol/geom/Circle.js';
import Point from '../../../../src/ol/geom/Point.js';
import LineString from '../../../../src/ol/geom/LineString.js';
import Snap from '../../../../src/ol/interaction/Snap.js';
import {useGeographic, clearUserProjection} from '../../../../src/ol/proj.js';
import {overrideRAF} from '../../util.js';
describe('ol.interaction.Snap', function() {
@@ -190,6 +192,78 @@ describe('ol.interaction.Snap', function() {
expect(event.coordinate).to.eql([10, 0]);
});
});
describe('handleEvent - useGeographic', () => {
let target, map;
const size = 256;
let restoreRAF;
beforeEach(done => {
restoreRAF = overrideRAF();
useGeographic();
target = document.createElement('div');
Object.assign(target.style, {
position: 'absolute',
top: 0,
left: 0,
width: `${size}px`,
height: `${size}px`
});
document.body.appendChild(target);
map = new Map({
target: target,
view: new View({
center: [0, 0],
zoom: 0
})
});
map.once('postrender', () => {
done();
});
});
afterEach(() => {
map.dispose();
document.body.removeChild(target);
clearUserProjection();
restoreRAF();
});
it('snaps to user coordinates', () => {
const lon = -90;
const lat = 45;
const point = new Feature(new Point([lon, lat]));
const snap = new Snap({
features: new Collection([point])
});
snap.setMap(map);
const expectedPixel = map.getPixelFromCoordinate([lon, lat]).map(value => Math.round(value));
const delta = 5;
const pixel = expectedPixel.slice();
pixel[0] += delta;
pixel[1] += delta;
const coordinate = map.getCoordinateFromPixel(pixel);
const event = {
pixel: pixel,
coordinate: coordinate,
map: map
};
snap.handleEvent(event);
expect(event.coordinate).to.eql([lon, lat]);
expect(event.pixel).to.eql(expectedPixel);
});
});

View File

@@ -67,7 +67,7 @@ describe('ol.net', function() {
};
};
function callback() {
expect.fail();
expect().fail();
}
function errback() {
expect(window[key]).to.be(undefined);

View File

@@ -156,7 +156,7 @@ describe('ol.Object', function() {
it('dispatches events to object', function() {
o.set('k', 1);
expect(listener1).to.be.called();
expect(listener1.called).to.be(true);
expect(o.getKeys()).to.eql(['k']);
});
@@ -190,7 +190,7 @@ describe('ol.Object', function() {
it('does not call the setter', function() {
o.set('x', 1);
expect(o.get('x')).to.eql(1);
expect(o.setX).to.not.be.called();
expect(o.setX.called).to.be(false);
expect(o.getKeys()).to.eql(['x']);
});
@@ -206,7 +206,7 @@ describe('ol.Object', function() {
it('does not call the getter', function() {
expect(o.get('x')).to.be(undefined);
expect(o.getX).to.not.be.called();
expect(o.getX.called).to.be(false);
});
});
@@ -231,8 +231,8 @@ describe('ol.Object', function() {
it('dispatches the expected event', function() {
o.set('K', 1);
expect(listener1).to.not.be.called();
expect(listener2).to.be.called();
expect(listener1.called).to.be(false);
expect(listener2.called).to.be(true);
expect(o.getKeys()).to.eql(['K']);
});

View File

@@ -30,15 +30,11 @@ describe('ol.obj.assign()', function() {
});
it('throws a TypeError with `undefined` as target', function() {
expect(assign).withArgs(undefined).to.throwException(function(e) {
expect(e).to.be.a(TypeError);
});
expect(() => assign()).to.throwException(/Cannot convert undefined or null to object/);
});
it('throws a TypeError with `null` as target', function() {
expect(assign).withArgs(null).to.throwException(function(e) {
expect(e).to.be.a(TypeError);
});
expect(() => assign(null)).to.throwException(/Cannot convert undefined or null to object/);
});
});

View File

@@ -74,7 +74,8 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
source = new VectorTileSource({
format: new MVT(),
tileClass: TileClass,
tileGrid: createXYZ()
tileGrid: createXYZ(),
url: '{z}/{x}/{y}.pbf'
});
source.getSourceTiles = function() {
return [new TileClass([0, 0, 0])];

View File

@@ -17,7 +17,7 @@ import Feature from '../../../../src/ol/Feature.js';
describe('ol.renderer.vector', function() {
describe('#renderFeature', function() {
let builderGroup;
let feature, iconStyle, style, squaredTolerance, listener, listenerThis;
let feature, iconStyle, style, squaredTolerance, listener;
let iconStyleLoadSpy;
beforeEach(function() {
@@ -33,7 +33,6 @@ describe('ol.renderer.vector', function() {
});
squaredTolerance = 1;
listener = function() {};
listenerThis = {};
iconStyleLoadSpy = sinon.stub(iconStyle, 'load').callsFake(function() {
iconStyle.iconImage_.imageState_ = 1; // LOADING
});
@@ -49,16 +48,14 @@ describe('ol.renderer.vector', function() {
let listeners;
// call #1
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(iconStyleLoadSpy.calledOnce).to.be.ok();
listeners = iconStyle.iconImage_.listeners_['change'];
expect(listeners.length).to.eql(1);
// call #2
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(iconStyleLoadSpy.calledOnce).to.be.ok();
listeners = iconStyle.iconImage_.listeners_['change'];
@@ -75,8 +72,7 @@ describe('ol.renderer.vector', function() {
style.getZIndex(), 'Image');
const setImageStyleSpy = sinon.spy(imageReplay, 'setImageStyle');
const drawPointSpy = sinon.stub(imageReplay, 'drawPoint').callsFake(VOID);
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(setImageStyleSpy.called).to.be(false);
setImageStyleSpy.restore();
drawPointSpy.restore();
@@ -88,8 +84,7 @@ describe('ol.renderer.vector', function() {
style.getZIndex(), 'Image');
const setImageStyleSpy = sinon.spy(imageReplay, 'setImageStyle');
const drawMultiPointSpy = sinon.stub(imageReplay, 'drawMultiPoint').callsFake(VOID);
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(setImageStyleSpy.called).to.be(false);
setImageStyleSpy.restore();
drawMultiPointSpy.restore();
@@ -102,8 +97,7 @@ describe('ol.renderer.vector', function() {
const setFillStrokeStyleSpy = sinon.spy(lineStringReplay,
'setFillStrokeStyle');
const drawLineStringSpy = sinon.stub(lineStringReplay, 'drawLineString').callsFake(VOID);
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(setFillStrokeStyleSpy.called).to.be(true);
expect(drawLineStringSpy.called).to.be(true);
setFillStrokeStyleSpy.restore();
@@ -117,8 +111,7 @@ describe('ol.renderer.vector', function() {
const setFillStrokeStyleSpy = sinon.spy(lineStringReplay,
'setFillStrokeStyle');
const drawMultiLineStringSpy = sinon.stub(lineStringReplay, 'drawMultiLineString').callsFake(VOID);
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(setFillStrokeStyleSpy.called).to.be(true);
expect(drawMultiLineStringSpy.called).to.be(true);
setFillStrokeStyleSpy.restore();
@@ -133,8 +126,7 @@ describe('ol.renderer.vector', function() {
const setFillStrokeStyleSpy = sinon.spy(polygonReplay,
'setFillStrokeStyle');
const drawPolygonSpy = sinon.stub(polygonReplay, 'drawPolygon').callsFake(VOID);
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(setFillStrokeStyleSpy.called).to.be(true);
expect(drawPolygonSpy.called).to.be(true);
setFillStrokeStyleSpy.restore();
@@ -149,8 +141,7 @@ describe('ol.renderer.vector', function() {
const setFillStrokeStyleSpy = sinon.spy(polygonReplay,
'setFillStrokeStyle');
const drawMultiPolygonSpy = sinon.stub(polygonReplay, 'drawMultiPolygon').callsFake(VOID);
renderFeature(builderGroup, feature,
style, squaredTolerance, listener, listenerThis);
renderFeature(builderGroup, feature, style, squaredTolerance, listener);
expect(setFillStrokeStyleSpy.called).to.be(true);
expect(drawMultiPolygonSpy.called).to.be(true);
setFillStrokeStyleSpy.restore();

View File

@@ -211,7 +211,7 @@ describe('ol.source.ImageWMS', function() {
const source = new ImageWMS(options);
const image = source.getImage(extent, resolution, pixelRatio, projection);
image.load();
expect(imageLoadFunction).to.be.called();
expect(imageLoadFunction.called).to.be(true);
expect(imageLoadFunction.calledWith(image, image.src_)).to.be(true);
});

View File

@@ -34,7 +34,7 @@ describe('ol.source.Vector', function() {
it('does not call the callback', function() {
const f = sinon.spy();
vectorSource.forEachFeatureInExtent(infiniteExtent, f);
expect(f).not.to.be.called();
expect(f.called).to.be(false);
});
});
@@ -71,7 +71,7 @@ describe('ol.source.Vector', function() {
const listener = sinon.spy();
listen(vectorSource, 'change', listener);
vectorSource.addFeature(pointFeature);
expect(listener).to.be.called();
expect(listener.called).to.be(true);
});
it('adds same id features only once', function() {
@@ -249,9 +249,9 @@ describe('ol.source.Vector', function() {
vectorSource.clear(true);
expect(vectorSource.getFeatures()).to.eql([]);
expect(vectorSource.isEmpty()).to.be(true);
expect(removeFeatureSpy).not.to.be.called();
expect(removeFeatureSpy.called).to.be(false);
expect(removeFeatureSpy.callCount).to.be(0);
expect(clearSourceSpy).to.be.called();
expect(clearSourceSpy.called).to.be(true);
expect(clearSourceSpy.callCount).to.be(1);
});
@@ -263,9 +263,9 @@ describe('ol.source.Vector', function() {
vectorSource.clear();
expect(vectorSource.getFeatures()).to.eql([]);
expect(vectorSource.isEmpty()).to.be(true);
expect(removeFeatureSpy).to.be.called();
expect(removeFeatureSpy.called).to.be(true);
expect(removeFeatureSpy.callCount).to.be(features.length);
expect(clearSourceSpy).to.be.called();
expect(clearSourceSpy.called).to.be(true);
expect(clearSourceSpy.callCount).to.be(1);
});
@@ -323,14 +323,14 @@ describe('ol.source.Vector', function() {
const listener = sinon.spy();
listen(vectorSource, 'change', listener);
vectorSource.removeFeature(features[0]);
expect(listener).to.be.called();
expect(listener.called).to.be(true);
});
it('fires a removefeature event', function() {
const listener = sinon.spy();
listen(vectorSource, 'removefeature', listener);
vectorSource.removeFeature(features[0]);
expect(listener).to.be.called();
expect(listener.called).to.be(true);
});
});
@@ -416,7 +416,7 @@ describe('ol.source.Vector', function() {
const listener = sinon.spy();
listen(vectorSource, 'change', listener);
feature.set('foo', 'bar');
expect(listener).to.be.called();
expect(listener.called).to.be(true);
});
it('fires a changefeature event when updating a feature', function() {
@@ -427,7 +427,7 @@ describe('ol.source.Vector', function() {
});
vectorSource.on('changefeature', listener);
feature.setStyle(null);
expect(listener).to.be.called();
expect(listener.called).to.be(true);
});
});

View File

@@ -71,19 +71,13 @@ describe('ol.source.VectorTile', function() {
});
});
it('handles empty tiles', function(done) {
it('handles empty tiles', function() {
const source = new VectorTileSource({
format: new GeoJSON(),
url: ''
});
const tile = source.getTile(0, 0, 0, 1, source.getProjection());
const key = listen(tile, 'change', function(e) {
unlistenByKey(key);
expect(tile.getState()).to.be(TileState.EMPTY);
done();
});
tile.load();
expect(tile.getState()).to.be(TileState.EMPTY);
});
it('creates empty tiles outside the source extent', function() {
@@ -103,14 +97,30 @@ describe('ol.source.VectorTile', function() {
expect(tile.getState()).to.be(TileState.EMPTY);
});
it('creates empty tiles when the tileUrlFunction returns undefined', function() {
const source = new VectorTileSource({
tileUrlFunction: function(tileCoord) {
return;
}
});
const tile = source.getTile(1, 1, 1, 1, source.getProjection());
expect(tile.getState()).to.be(TileState.EMPTY);
});
it('creates non-empty tiles outside the world extent when wrapX === true', function() {
const source = new VectorTileSource({});
const source = new VectorTileSource({
url: '{z}/{x}/{y}.pbf'
});
const tile = source.getTile(0, -1, 0, 1, source.getProjection());
expect(tile.getState()).to.be(TileState.IDLE);
});
it('creates non-empty tiles for overzoomed resolutions', function() {
const source = new VectorTileSource({
url: '{z}/{x}/{y}.pbf',
tileLoadFunction: function(tile) {
tile.setLoader(function() {});
},
maxZoom: 16
});
const tile = source.getTile(24, 9119385, 5820434, 1, source.getProjection());

View File

@@ -454,7 +454,7 @@ describe('ol.View', function() {
maxResolution: maxResolution,
constrainResolution: true
});
expect(fn(defaultMaxRes, 0, size)).to.be(defaultMaxRes / 2);
expect(fn(defaultMaxRes, 0, size)).to.be(maxResolution / 4);
});
it('enabled, with constrainResolution', function() {

17
test/spec/util.js Normal file
View File

@@ -0,0 +1,17 @@
export function overrideRAF() {
const raf = window.requestAnimationFrame;
const caf = window.cancelAnimationFrame;
window.requestAnimationFrame = function(callback) {
return setTimeout(callback, 1);
};
window.cancelAnimationFrame = function(key) {
return clearTimeout(key);
};
return function() {
window.requestAnimationFrame = raf;
window.cancelAnimationFrame = caf;
};
}

View File

@@ -1,4 +1,3 @@
import {equals} from '../src/ol/array.js';
// avoid importing anything that results in an instanceof check
// since these extensions are global, instanceof checks fail with modules
@@ -88,23 +87,6 @@ import {equals} from '../src/ol/array.js';
};
/**
* Assert that a sinon spy was called.
* @return {expect.Assertion} The assertion.
*/
expect.Assertion.prototype.called = function() {
this.assert(
this.obj.called,
function() {
return 'expected ' + expect.stringify(this.obj) + ' to be called';
},
function() {
return 'expected ' + expect.stringify(this.obj) + ' not to be called';
});
return this;
};
function getChildNodes(node, options) {
// check whitespace
if (options && options.includeWhiteSpace) {
@@ -309,50 +291,6 @@ import {equals} from '../src/ol/array.js';
};
/**
* Checks if the array sort of equals another array.
* @param {Object} obj The other object.
* @return {expect.Assertion} The assertion.
*/
expect.Assertion.prototype.arreql = function(obj) {
this.assert(
equals(this.obj, obj),
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of equal ' + expect.stringify(obj);
},
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of not equal ' + expect.stringify(obj);
});
return this;
};
/**
* Checks if the array sort of equals another array (allows NaNs to be equal).
* @param {Object} obj The other object.
* @return {expect.Assertion} The assertion.
*/
expect.Assertion.prototype.arreqlNaN = function(obj) {
function compare(a, i) {
const b = obj[i];
return a === b || (typeof a === 'number' && typeof b === 'number' &&
isNaN(a) && isNaN(b));
}
this.assert(
this.obj.length === obj.length && this.obj.every(compare),
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of equal ' + expect.stringify(obj);
},
function() {
return 'expected ' + expect.stringify(this.obj) +
' to sort of not equal ' + expect.stringify(obj);
});
return this;
};
global.createMapDiv = function(width, height) {
const target = document.createElement('div');
const style = target.style;