Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4be8309f7 | ||
|
|
39a5511073 | ||
|
|
396f07bea1 | ||
|
|
33980d0ba8 | ||
|
|
7da86ae71f | ||
|
|
af15cfb815 | ||
|
|
600e1a4647 | ||
|
|
43010c8934 | ||
|
|
f7b0f6750b | ||
|
|
e5e03d46a0 | ||
|
|
e78c14c061 | ||
|
|
21f99e01c3 | ||
|
|
8098572346 | ||
|
|
ac50cc3460 | ||
|
|
06ae419db6 | ||
|
|
43d6247671 | ||
|
|
442213f85b | ||
|
|
2a96b6a8e3 | ||
|
|
89f92a53b4 | ||
|
|
9c26d9d7dd | ||
|
|
3de05c249b | ||
|
|
bb2bdb17aa | ||
|
|
b8c70bcbe7 | ||
|
|
c23d59e3a8 | ||
|
|
5dec336f94 | ||
|
|
e3f83f3601 | ||
|
|
3d0f7e4af8 | ||
|
|
4b13c6dae0 | ||
|
|
7097a4c6ba | ||
|
|
79ea5bf9cd | ||
|
|
97d0d277fb | ||
|
|
025b27bdec | ||
|
|
00af5a87be | ||
|
|
53f6359f8f | ||
|
|
bac3a8e9d8 | ||
|
|
66eedbfed2 | ||
|
|
7d7228d45c | ||
|
|
459efede60 | ||
|
|
b0ed775bc6 | ||
|
|
43ebfc4653 | ||
|
|
49c1486e06 |
17
changelog/v6.1.1.md
Normal file
17
changelog/v6.1.1.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 6.1.1
|
||||
|
||||
Hot on the heels of OpenLayers 6.x, this patch release includes a few fixes for existing functionality. There should be nothing special needed to upgrade an application from 6.x to 6.1.1. See the 6.0.0 release notes for details on upgrading from an older version.
|
||||
|
||||
## Changes
|
||||
|
||||
* [#10235](https://github.com/openlayers/openlayers/pull/10235) - Various optimizations and fixes for the WebGL points renderer ([@jahow](https://github.com/jahow))
|
||||
* [#10244](https://github.com/openlayers/openlayers/pull/10244) - Update to new eslint config with no-multi-assign ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10243](https://github.com/openlayers/openlayers/pull/10243) - Store correct font value ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10239](https://github.com/openlayers/openlayers/pull/10239) - Simpler container reuse ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10237](https://github.com/openlayers/openlayers/pull/10237) - Fix layer zIndex test with falsy values ([@fredj](https://github.com/fredj))
|
||||
* [#10221](https://github.com/openlayers/openlayers/pull/10221) - Fix for undefined Source ([@Kai-W](https://github.com/Kai-W))
|
||||
* [#10228](https://github.com/openlayers/openlayers/pull/10228) - Use render tiles instead of source tiles for hit detection ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10226](https://github.com/openlayers/openlayers/pull/10226) - ABORT reproj tiles properly ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10224](https://github.com/openlayers/openlayers/pull/10224) - Vector tile hit detection fixes ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10218](https://github.com/openlayers/openlayers/pull/10218) - Documentation fixes in ol/style/expressions ([@fredj](https://github.com/fredj))
|
||||
* [#10216](https://github.com/openlayers/openlayers/pull/10216) - Update changelog script to recognize dependabot instead of greenkeeper ([@ahocevar](https://github.com/ahocevar))
|
||||
@@ -59,7 +59,7 @@ const style = {
|
||||
rotateWithView: false,
|
||||
offset: [
|
||||
0,
|
||||
9
|
||||
0
|
||||
],
|
||||
textureCoord: [
|
||||
'match',
|
||||
@@ -144,7 +144,7 @@ map.addLayer(
|
||||
|
||||
const info = document.getElementById('info');
|
||||
map.on('pointermove', function(evt) {
|
||||
if (map.getView().getInteracting()) {
|
||||
if (map.getView().getInteracting() || map.getView().getAnimating()) {
|
||||
return;
|
||||
}
|
||||
const pixel = evt.pixel;
|
||||
|
||||
@@ -7,18 +7,19 @@ import {Fill, Stroke, Style} from '../src/ol/style.js';
|
||||
|
||||
// lookup for selection objects
|
||||
let selection = {};
|
||||
// feature property to act as identifier
|
||||
const idProp = 'iso_a3';
|
||||
|
||||
const vtLayer = new VectorTileLayer({
|
||||
declutter: true,
|
||||
source: new VectorTileSource({
|
||||
format: new MVT(),
|
||||
maxZoom: 15,
|
||||
format: new MVT({
|
||||
idProperty: 'iso_a3'
|
||||
}),
|
||||
url: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' +
|
||||
'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
|
||||
}),
|
||||
style: function(feature) {
|
||||
const selected = !!selection[feature.get(idProp)];
|
||||
const selected = !!selection[feature.getId()];
|
||||
return new Style({
|
||||
stroke: new Stroke({
|
||||
color: selected ? 'rgba(200,20,20,0.8)' : 'gray',
|
||||
@@ -56,7 +57,7 @@ map.on('click', function(event) {
|
||||
if (!feature) {
|
||||
return;
|
||||
}
|
||||
const fid = feature.get(idProp);
|
||||
const fid = feature.getId();
|
||||
|
||||
if (selectElement.value === 'singleselect') {
|
||||
selection = {};
|
||||
|
||||
@@ -124,6 +124,7 @@ function refreshLayer(newStyle) {
|
||||
|
||||
if (previousLayer) {
|
||||
map.removeLayer(previousLayer);
|
||||
previousLayer.dispose();
|
||||
}
|
||||
literalStyle = newStyle;
|
||||
}
|
||||
|
||||
48
package-lock.json
generated
48
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.0.1",
|
||||
"version": "6.1.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -3636,12 +3636,12 @@
|
||||
}
|
||||
},
|
||||
"eslint-config-openlayers": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-openlayers/-/eslint-config-openlayers-12.0.0.tgz",
|
||||
"integrity": "sha512-cln+A0qoBvf9ZTVFt9UJ1pTb+TfKOZ5B55jPtYrIcREKXsRycTtWNQjtHQJRbfTPp8CGoU6tjJ6yLUsseVgv0Q==",
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-openlayers/-/eslint-config-openlayers-13.0.0.tgz",
|
||||
"integrity": "sha512-FlhPbUhrgh9nyIrcf6jX8cZHLOxl2Z4rmLnMrhwBhE+KQK2n3hywXpkNvUROWV9TQpxavzaA7punYHL4ggUpig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-plugin-import": "^2.17.3"
|
||||
"eslint-plugin-import": "^2.18.2"
|
||||
}
|
||||
},
|
||||
"eslint-import-resolver-node": {
|
||||
@@ -3672,9 +3672,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-module-utils": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz",
|
||||
"integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==",
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz",
|
||||
"integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^2.6.8",
|
||||
@@ -3751,9 +3751,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-import": {
|
||||
"version": "2.17.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.17.3.tgz",
|
||||
"integrity": "sha512-qeVf/UwXFJbeyLbxuY8RgqDyEKCkqV7YC+E5S5uOjAp4tOc8zj01JP3ucoBM8JcEqd1qRasJSg6LLlisirfy0Q==",
|
||||
"version": "2.18.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz",
|
||||
"integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-includes": "^3.0.3",
|
||||
@@ -3763,8 +3763,8 @@
|
||||
"eslint-import-resolver-node": "^0.3.2",
|
||||
"eslint-module-utils": "^2.4.0",
|
||||
"has": "^1.0.3",
|
||||
"lodash": "^4.17.11",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.values": "^1.1.0",
|
||||
"read-pkg-up": "^2.0.0",
|
||||
"resolve": "^1.11.0"
|
||||
},
|
||||
@@ -3795,9 +3795,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
|
||||
"integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
|
||||
"integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
@@ -5767,9 +5767,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
|
||||
"integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
|
||||
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"agent-base": "^4.3.0",
|
||||
@@ -8013,6 +8013,18 @@
|
||||
"isobject": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"object.values": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz",
|
||||
"integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.12.0",
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"obuf": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.1.0",
|
||||
"version": "6.1.1",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
"map",
|
||||
@@ -57,7 +57,7 @@
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"coveralls": "3.0.7",
|
||||
"eslint": "^6.0.0",
|
||||
"eslint-config-openlayers": "^12.0.0",
|
||||
"eslint-config-openlayers": "^13.0.0",
|
||||
"expect.js": "0.3.1",
|
||||
"front-matter": "^3.0.2",
|
||||
"fs-extra": "^8.0.0",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.5 KiB |
@@ -65,6 +65,22 @@ feature.setStyle(new Style({
|
||||
}));
|
||||
vectorSource.addFeature(feature);
|
||||
|
||||
// align left
|
||||
feature = new Feature({
|
||||
geometry: new Point([50, 50])
|
||||
});
|
||||
feature.setStyle(new Style({
|
||||
text: new Text({
|
||||
font: 'Ubuntu',
|
||||
text: 'align left',
|
||||
textAlign: 'left',
|
||||
stroke: new Stroke({
|
||||
color: [10, 10, 10, 0.5]
|
||||
})
|
||||
})
|
||||
}));
|
||||
vectorSource.addFeature(feature);
|
||||
|
||||
// background and padding
|
||||
feature = new Feature({
|
||||
geometry: new Point([-10, 0])
|
||||
|
||||
@@ -69,8 +69,6 @@ class ImageTile extends Tile {
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
|
||||
@@ -512,15 +512,18 @@ class Overlay extends BaseObject {
|
||||
positioning == OverlayPositioning.CENTER_RIGHT ||
|
||||
positioning == OverlayPositioning.TOP_RIGHT) {
|
||||
if (this.rendered.left_ !== '') {
|
||||
this.rendered.left_ = style.left = '';
|
||||
this.rendered.left_ = '';
|
||||
style.left = '';
|
||||
}
|
||||
const right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
|
||||
if (this.rendered.right_ != right) {
|
||||
this.rendered.right_ = style.right = right;
|
||||
this.rendered.right_ = right;
|
||||
style.right = right;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.right_ !== '') {
|
||||
this.rendered.right_ = style.right = '';
|
||||
this.rendered.right_ = '';
|
||||
style.right = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
@@ -529,22 +532,26 @@ class Overlay extends BaseObject {
|
||||
}
|
||||
const left = Math.round(pixel[0] + offsetX) + 'px';
|
||||
if (this.rendered.left_ != left) {
|
||||
this.rendered.left_ = style.left = left;
|
||||
this.rendered.left_ = left;
|
||||
style.left = left;
|
||||
}
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_LEFT ||
|
||||
positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.BOTTOM_RIGHT) {
|
||||
if (this.rendered.top_ !== '') {
|
||||
this.rendered.top_ = style.top = '';
|
||||
this.rendered.top_ = '';
|
||||
style.top = '';
|
||||
}
|
||||
const bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
|
||||
if (this.rendered.bottom_ != bottom) {
|
||||
this.rendered.bottom_ = style.bottom = bottom;
|
||||
this.rendered.bottom_ = bottom;
|
||||
style.bottom = bottom;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.bottom_ !== '') {
|
||||
this.rendered.bottom_ = style.bottom = '';
|
||||
this.rendered.bottom_ = '';
|
||||
style.bottom = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.CENTER_LEFT ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
@@ -553,7 +560,8 @@ class Overlay extends BaseObject {
|
||||
}
|
||||
const top = Math.round(pixel[1] + offsetY) + 'px';
|
||||
if (this.rendered.top_ != top) {
|
||||
this.rendered.top_ = style.top = top;
|
||||
this.rendered.top_ = 'top';
|
||||
style.top = top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,11 +87,6 @@ class Tile extends EventTarget {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {ImageData}
|
||||
*/
|
||||
this.hitDetectionImageData = null;
|
||||
|
||||
/**
|
||||
* @type {import("./tilecoord.js").TileCoord}
|
||||
*/
|
||||
@@ -149,6 +144,13 @@ class Tile extends EventTarget {
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setState(TileState.ABORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} Key.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
import {getUid} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import TileState from './TileState.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
import {unlistenByKey} from './events.js';
|
||||
|
||||
@@ -25,7 +24,7 @@ class VectorRenderTile extends Tile {
|
||||
|
||||
/**
|
||||
* @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {TileState} state State.
|
||||
* @param {import("./TileState.js").default} state State.
|
||||
* @param {import("./tilecoord.js").TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
|
||||
* @param {import("./tilegrid/TileGrid.js").default} sourceTileGrid Tile grid of the source.
|
||||
* @param {function(VectorRenderTile):Array<import("./VectorTile").default>} getSourceTiles Function
|
||||
@@ -61,6 +60,11 @@ class VectorRenderTile extends Tile {
|
||||
*/
|
||||
this.errorSourceTileKeys = {};
|
||||
|
||||
/**
|
||||
* @type {ImageData}
|
||||
*/
|
||||
this.hitDetectionImageData = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, ReplayState>}
|
||||
@@ -73,9 +77,9 @@ class VectorRenderTile extends Tile {
|
||||
this.wantedResolution;
|
||||
|
||||
/**
|
||||
* @type {!function(import("./VectorRenderTile.js").default):Array<import("./VectorTile.js").default>}
|
||||
* @type {!function():Array<import("./VectorTile.js").default>}
|
||||
*/
|
||||
this.getSourceTiles_ = getSourceTiles;
|
||||
this.getSourceTiles = getSourceTiles.bind(this, this);
|
||||
|
||||
/**
|
||||
* @type {!function(import("./VectorRenderTile.js").default):void}
|
||||
@@ -120,7 +124,8 @@ class VectorRenderTile extends Tile {
|
||||
this.removeSourceTiles_(this);
|
||||
for (const key in this.context_) {
|
||||
const canvas = this.context_[key].canvas;
|
||||
canvas.width = canvas.height = 0;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
for (const key in this.executorGroups) {
|
||||
const executorGroups = this.executorGroups[key];
|
||||
@@ -128,7 +133,6 @@ class VectorRenderTile extends Tile {
|
||||
executorGroups[i].disposeInternal();
|
||||
}
|
||||
}
|
||||
this.setState(TileState.ABORT);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
@@ -186,7 +190,7 @@ class VectorRenderTile extends Tile {
|
||||
* @inheritDoc
|
||||
*/
|
||||
load() {
|
||||
this.getSourceTiles_(this);
|
||||
this.getSourceTiles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,14 +73,6 @@ class VectorTile extends Tile {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setState(TileState.ABORT);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {import("./format/Feature.js").default} Feature format.
|
||||
|
||||
@@ -37,10 +37,12 @@ export function createExtent(extent, onlyCenter, smooth) {
|
||||
// note: when zooming out of bounds, min and max values for x and y may
|
||||
// end up inverted (min > max); this has to be accounted for
|
||||
if (minX > maxX) {
|
||||
minX = maxX = (maxX + minX) / 2;
|
||||
minX = (maxX + minX) / 2;
|
||||
maxX = minX;
|
||||
}
|
||||
if (minY > maxY) {
|
||||
minY = maxY = (maxY + minY) / 2;
|
||||
minY = (maxY + minY) / 2;
|
||||
maxY = minY;
|
||||
}
|
||||
|
||||
let x = clamp(center[0], minX, maxX);
|
||||
|
||||
@@ -72,7 +72,8 @@ class Target extends Disposable {
|
||||
}
|
||||
let listeners = this.listeners_[type];
|
||||
if (!listeners) {
|
||||
listeners = this.listeners_[type] = [];
|
||||
listeners = [];
|
||||
this.listeners_[type] = listeners;
|
||||
}
|
||||
if (listeners.indexOf(listener) === -1) {
|
||||
listeners.push(listener);
|
||||
|
||||
@@ -1777,7 +1777,9 @@ function setCommonGeometryProperties(multiGeometry, geometries) {
|
||||
const tessellates = new Array(geometries.length);
|
||||
const altitudeModes = new Array(geometries.length);
|
||||
let hasExtrude, hasTessellate, hasAltitudeMode;
|
||||
hasExtrude = hasTessellate = hasAltitudeMode = false;
|
||||
hasExtrude = false;
|
||||
hasTessellate = false;
|
||||
hasAltitudeMode = false;
|
||||
for (let i = 0; i < ii; ++i) {
|
||||
const geometry = geometries[i];
|
||||
extrudes[i] = geometry.get('extrude');
|
||||
|
||||
@@ -654,7 +654,8 @@ class Modify extends PointerInteraction {
|
||||
};
|
||||
|
||||
const featureSegments = [centerSegmentData, circumferenceSegmentData];
|
||||
centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments;
|
||||
centerSegmentData.featureSegments = featureSegments;
|
||||
circumferenceSegmentData.featureSegments = featureSegments;
|
||||
this.rBush_.insert(createExtent(coordinates), centerSegmentData);
|
||||
this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
|
||||
}
|
||||
@@ -746,12 +747,14 @@ class Modify extends PointerInteraction {
|
||||
switch (geometry.getType()) {
|
||||
case GeometryType.POINT:
|
||||
coordinates = vertex;
|
||||
segment[0] = segment[1] = vertex;
|
||||
segment[0] = vertex;
|
||||
segment[1] = vertex;
|
||||
break;
|
||||
case GeometryType.MULTI_POINT:
|
||||
coordinates = geometry.getCoordinates();
|
||||
coordinates[segmentData.index] = vertex;
|
||||
segment[0] = segment[1] = vertex;
|
||||
segment[0] = vertex;
|
||||
segment[1] = vertex;
|
||||
break;
|
||||
case GeometryType.LINE_STRING:
|
||||
coordinates = geometry.getCoordinates();
|
||||
@@ -774,7 +777,8 @@ class Modify extends PointerInteraction {
|
||||
segment[index] = vertex;
|
||||
break;
|
||||
case GeometryType.CIRCLE:
|
||||
segment[0] = segment[1] = vertex;
|
||||
segment[0] = vertex;
|
||||
segment[1] = vertex;
|
||||
if (segmentData.index === CIRCLE_CENTER_INDEX) {
|
||||
this.changingFeature_ = true;
|
||||
geometry.setCenter(vertex);
|
||||
@@ -889,8 +893,10 @@ class Modify extends PointerInteraction {
|
||||
const coordinates = geometry.getCenter();
|
||||
const centerSegmentData = segmentData.featureSegments[0];
|
||||
const circumferenceSegmentData = segmentData.featureSegments[1];
|
||||
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
|
||||
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
|
||||
centerSegmentData.segment[0] = coordinates;
|
||||
centerSegmentData.segment[1] = coordinates;
|
||||
circumferenceSegmentData.segment[0] = coordinates;
|
||||
circumferenceSegmentData.segment[1] = coordinates;
|
||||
this.rBush_.update(createExtent(coordinates), centerSegmentData);
|
||||
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
|
||||
} else {
|
||||
|
||||
@@ -198,7 +198,7 @@ class Translate extends PointerInteraction {
|
||||
handleDownEvent(event) {
|
||||
this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
|
||||
if (!this.lastCoordinate_ && this.lastFeature_) {
|
||||
this.startCoordinate_ =
|
||||
this.startCoordinate_ = event.coordinate;
|
||||
this.lastCoordinate_ = event.coordinate;
|
||||
this.handleMoveEvent(event);
|
||||
|
||||
|
||||
@@ -105,14 +105,14 @@ class BaseLayer extends BaseObject {
|
||||
/** @type {import("./Layer.js").State} */
|
||||
const state = this.state_ || /** @type {?} */ ({
|
||||
layer: this,
|
||||
managed: opt_managed === undefined ? true : opt_managed,
|
||||
hasOverlay: false
|
||||
managed: opt_managed === undefined ? true : opt_managed
|
||||
});
|
||||
const zIndex = this.getZIndex();
|
||||
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
|
||||
state.sourceState = this.getSourceState();
|
||||
state.visible = this.getVisible();
|
||||
state.extent = this.getExtent();
|
||||
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
|
||||
state.zIndex = zIndex !== undefined ? zIndex : (state.managed === false ? Infinity : 0);
|
||||
state.maxResolution = this.getMaxResolution();
|
||||
state.minResolution = Math.max(this.getMinResolution(), 0);
|
||||
state.minZoom = this.getMinZoom();
|
||||
@@ -320,6 +320,17 @@ class BaseLayer extends BaseObject {
|
||||
setZIndex(zindex) {
|
||||
this.set(LayerProperty.Z_INDEX, zindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.state_) {
|
||||
this.state_.layer = null;
|
||||
this.state_ = null;
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -581,7 +581,8 @@ class Graticule extends VectorLayer {
|
||||
createGraticule_(extent, center, resolution, squaredTolerance) {
|
||||
const interval = this.getInterval_(resolution);
|
||||
if (interval == -1) {
|
||||
this.meridians_.length = this.parallels_.length = 0;
|
||||
this.meridians_.length = 0;
|
||||
this.parallels_.length = 0;
|
||||
if (this.meridiansLabels_) {
|
||||
this.meridiansLabels_.length = 0;
|
||||
}
|
||||
@@ -708,7 +709,8 @@ class Graticule extends VectorLayer {
|
||||
const flatCoordinates = meridian(lon, minLat, maxLat, this.projection_, squaredTolerance);
|
||||
let lineString = this.meridians_[index];
|
||||
if (!lineString) {
|
||||
lineString = this.meridians_[index] = new LineString(flatCoordinates, GeometryLayout.XY);
|
||||
lineString = new LineString(flatCoordinates, GeometryLayout.XY);
|
||||
this.meridians_[index] = lineString;
|
||||
} else {
|
||||
lineString.setFlatCoordinates(GeometryLayout.XY, flatCoordinates);
|
||||
lineString.changed();
|
||||
|
||||
@@ -46,7 +46,6 @@ import SourceState from '../source/State.js';
|
||||
* @property {SourceState} sourceState
|
||||
* @property {boolean} visible
|
||||
* @property {boolean} managed
|
||||
* @property {boolean} hasOverlay Set by the renderer when an overlay for points and text is used.
|
||||
* @property {import("../extent.js").Extent} [extent]
|
||||
* @property {number} zIndex
|
||||
* @property {number} maxResolution
|
||||
@@ -288,6 +287,13 @@ class Layer extends BaseLayer {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setSource(null);
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ import Layer from './Layer.js';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **Important: a `WebGLPoints` layer must be manually disposed when removed, otherwise the underlying WebGL context
|
||||
* will not be garbage collected.**
|
||||
*
|
||||
* Note that any property set in the options is set as a {@link module:ol/Object~BaseObject}
|
||||
* property on the layer object; for example, setting `title: 'My Title'` in the
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
@@ -100,6 +103,15 @@ class WebGLPointsLayer extends Layer {
|
||||
attributes: this.parseResult_.attributes
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.renderer_.dispose();
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
export default WebGLPointsLayer;
|
||||
|
||||
@@ -74,7 +74,10 @@ class RenderBox extends Disposable {
|
||||
if (this.map_) {
|
||||
this.map_.getOverlayContainer().removeChild(this.element_);
|
||||
const style = this.element_.style;
|
||||
style.left = style.top = style.width = style.height = 'inherit';
|
||||
style.left = 'inherit';
|
||||
style.top = 'inherit';
|
||||
style.width = 'inherit';
|
||||
style.height = 'inherit';
|
||||
}
|
||||
this.map_ = map;
|
||||
if (this.map_) {
|
||||
|
||||
@@ -268,10 +268,10 @@ class RenderFeature {
|
||||
/**
|
||||
* @return {Array<number>|Array<Array<number>>} Ends or endss.
|
||||
*/
|
||||
RenderFeature.prototype.getEnds =
|
||||
RenderFeature.prototype.getEndss = function() {
|
||||
RenderFeature.prototype.getEnds = function() {
|
||||
return this.ends_;
|
||||
};
|
||||
RenderFeature.prototype.getEndss = RenderFeature.prototype.getEnds;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -311,13 +311,15 @@ export const measureTextHeight = (function() {
|
||||
if (!div) {
|
||||
div = document.createElement('div');
|
||||
div.innerHTML = 'M';
|
||||
div.style.margin = div.style.padding = '0 !important';
|
||||
div.style.margin = '0 !important';
|
||||
div.style.padding = '0 !important';
|
||||
div.style.position = 'absolute !important';
|
||||
div.style.left = '-99999px !important';
|
||||
}
|
||||
div.style.font = font;
|
||||
document.body.appendChild(div);
|
||||
height = heights[font] = div.offsetHeight;
|
||||
height = div.offsetHeight;
|
||||
heights[font] = height;
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
return height;
|
||||
@@ -333,7 +335,8 @@ export const measureTextHeight = (function() {
|
||||
export function measureTextWidth(font, text) {
|
||||
const measureContext = getMeasureContext();
|
||||
if (font != measureFont) {
|
||||
measureContext.font = measureFont = font;
|
||||
measureContext.font = font;
|
||||
measureFont = measureContext.font;
|
||||
}
|
||||
return measureContext.measureText(text).width;
|
||||
}
|
||||
@@ -350,7 +353,8 @@ export function measureAndCacheTextWidth(font, text, cache) {
|
||||
if (text in cache) {
|
||||
return cache[text];
|
||||
}
|
||||
const width = cache[text] = measureTextWidth(font, text);
|
||||
const width = measureTextWidth(font, text);
|
||||
cache[text] = width;
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ class BuilderGroup {
|
||||
declutter = this.declutterGroups_;
|
||||
/** @type {number} */ (declutter[0][4])++;
|
||||
} else {
|
||||
declutter = this.declutterGroups_ = [createEmpty()];
|
||||
declutter = [createEmpty()];
|
||||
this.declutterGroups_ = declutter;
|
||||
declutter[0].push(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,10 +315,14 @@ class Executor extends Disposable {
|
||||
const boxY = y - padding[0];
|
||||
|
||||
if (fillStroke || rotation !== 0) {
|
||||
p1[0] = p4[0] = boxX;
|
||||
p1[1] = p2[1] = boxY;
|
||||
p2[0] = p3[0] = boxX + boxW;
|
||||
p3[1] = p4[1] = boxY + boxH;
|
||||
p1[0] = boxX;
|
||||
p4[0] = boxX;
|
||||
p1[1] = boxY;
|
||||
p2[1] = boxY;
|
||||
p2[0] = boxX + boxW;
|
||||
p3[0] = p2[0];
|
||||
p3[1] = boxY + boxH;
|
||||
p4[1] = p3[1];
|
||||
}
|
||||
|
||||
let transform = null;
|
||||
@@ -537,6 +541,7 @@ class Executor extends Disposable {
|
||||
let lastStrokeInstruction = null;
|
||||
const coordinateCache = this.coordinateCache_;
|
||||
const viewRotation = this.viewRotation_;
|
||||
const viewRotationFromTransform = Math.round(Math.atan2(-transform[1], transform[0]) * 1e12) / 1e12;
|
||||
|
||||
const state = /** @type {import("../../render.js").State} */ ({
|
||||
context: context,
|
||||
@@ -575,7 +580,8 @@ class Executor extends Disposable {
|
||||
}
|
||||
if (!pendingFill && !pendingStroke) {
|
||||
context.beginPath();
|
||||
prevX = prevY = NaN;
|
||||
prevX = NaN;
|
||||
prevY = NaN;
|
||||
}
|
||||
++i;
|
||||
break;
|
||||
@@ -643,13 +649,18 @@ class Executor extends Disposable {
|
||||
strokeKey = /** @type {string} */ (instruction[20]);
|
||||
fillKey = /** @type {string} */ (instruction[21]);
|
||||
const labelWithAnchor = this.drawTextImageWithPointPlacement_(text, textKey, strokeKey, fillKey);
|
||||
image = instruction[3] = labelWithAnchor.label;
|
||||
image = labelWithAnchor.label;
|
||||
instruction[3] = image;
|
||||
const textOffsetX = /** @type {number} */ (instruction[22]);
|
||||
anchorX = instruction[4] = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
|
||||
anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
|
||||
instruction[4] = anchorX;
|
||||
const textOffsetY = /** @type {number} */ (instruction[23]);
|
||||
anchorY = instruction[5] = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
|
||||
height = instruction[7] = image.height;
|
||||
width = instruction[14] = image.width;
|
||||
anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
|
||||
instruction[5] = anchorY;
|
||||
height = image.height;
|
||||
instruction[7] = height;
|
||||
width = image.width;
|
||||
instruction[14] = width;
|
||||
}
|
||||
|
||||
let geometryWidths;
|
||||
@@ -664,11 +675,16 @@ class Executor extends Disposable {
|
||||
backgroundStroke = /** @type {boolean} */ (instruction[17]);
|
||||
} else {
|
||||
padding = defaultPadding;
|
||||
backgroundFill = backgroundStroke = false;
|
||||
backgroundFill = false;
|
||||
backgroundStroke = false;
|
||||
}
|
||||
|
||||
if (rotateWithView) {
|
||||
if (rotateWithView && viewRotationFromTransform) {
|
||||
// Canvas is expected to be rotated to reverse view rotation.
|
||||
rotation += viewRotation;
|
||||
} else if (!rotateWithView && !viewRotationFromTransform) {
|
||||
// Canvas is not rotated, images need to be rotated back to be north-up.
|
||||
rotation -= viewRotation;
|
||||
}
|
||||
let widthIndex = 0;
|
||||
let declutterGroupIndex = 0;
|
||||
@@ -725,7 +741,8 @@ class Executor extends Disposable {
|
||||
if (font in this.widths_) {
|
||||
cachedWidths = this.widths_[font];
|
||||
} else {
|
||||
cachedWidths = this.widths_[font] = {};
|
||||
cachedWidths = {};
|
||||
this.widths_[font] = cachedWidths;
|
||||
}
|
||||
|
||||
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);
|
||||
|
||||
@@ -116,7 +116,8 @@ class ExecutorGroup extends Disposable {
|
||||
for (const zIndex in allInstructions) {
|
||||
let executors = this.executorsByZIndex_[zIndex];
|
||||
if (executors === undefined) {
|
||||
this.executorsByZIndex_[zIndex] = executors = {};
|
||||
executors = {};
|
||||
this.executorsByZIndex_[zIndex] = executors;
|
||||
}
|
||||
const instructionByZindex = allInstructions[zIndex];
|
||||
for (const builderType in instructionByZindex) {
|
||||
@@ -139,7 +140,8 @@ class ExecutorGroup extends Disposable {
|
||||
}
|
||||
if (this.hitDetectionContext_) {
|
||||
const canvas = this.hitDetectionContext_.canvas;
|
||||
canvas.width = canvas.height = 0;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
|
||||
super.disposeInternal();
|
||||
|
||||
@@ -719,7 +719,8 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
};
|
||||
} else {
|
||||
if (contextFillState.fillStyle != fillState.fillStyle) {
|
||||
contextFillState.fillStyle = context.fillStyle = fillState.fillStyle;
|
||||
contextFillState.fillStyle = fillState.fillStyle;
|
||||
context.fillStyle = fillState.fillStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -752,30 +753,33 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
};
|
||||
} else {
|
||||
if (contextStrokeState.lineCap != strokeState.lineCap) {
|
||||
contextStrokeState.lineCap = context.lineCap = strokeState.lineCap;
|
||||
contextStrokeState.lineCap = strokeState.lineCap;
|
||||
context.lineCap = strokeState.lineCap;
|
||||
}
|
||||
if (context.setLineDash) {
|
||||
if (!equals(contextStrokeState.lineDash, strokeState.lineDash)) {
|
||||
context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash);
|
||||
}
|
||||
if (contextStrokeState.lineDashOffset != strokeState.lineDashOffset) {
|
||||
contextStrokeState.lineDashOffset = context.lineDashOffset =
|
||||
strokeState.lineDashOffset;
|
||||
contextStrokeState.lineDashOffset = strokeState.lineDashOffset;
|
||||
context.lineDashOffset = strokeState.lineDashOffset;
|
||||
}
|
||||
}
|
||||
if (contextStrokeState.lineJoin != strokeState.lineJoin) {
|
||||
contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin;
|
||||
contextStrokeState.lineJoin = strokeState.lineJoin;
|
||||
context.lineJoin = strokeState.lineJoin;
|
||||
}
|
||||
if (contextStrokeState.lineWidth != strokeState.lineWidth) {
|
||||
contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth;
|
||||
contextStrokeState.lineWidth = strokeState.lineWidth;
|
||||
context.lineWidth = strokeState.lineWidth;
|
||||
}
|
||||
if (contextStrokeState.miterLimit != strokeState.miterLimit) {
|
||||
contextStrokeState.miterLimit = context.miterLimit =
|
||||
strokeState.miterLimit;
|
||||
contextStrokeState.miterLimit = strokeState.miterLimit;
|
||||
context.miterLimit = strokeState.miterLimit;
|
||||
}
|
||||
if (contextStrokeState.strokeStyle != strokeState.strokeStyle) {
|
||||
contextStrokeState.strokeStyle = context.strokeStyle =
|
||||
strokeState.strokeStyle;
|
||||
contextStrokeState.strokeStyle = strokeState.strokeStyle;
|
||||
context.strokeStyle = strokeState.strokeStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -800,14 +804,16 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
};
|
||||
} else {
|
||||
if (contextTextState.font != textState.font) {
|
||||
contextTextState.font = context.font = textState.font;
|
||||
contextTextState.font = textState.font;
|
||||
context.font = textState.font;
|
||||
}
|
||||
if (contextTextState.textAlign != textAlign) {
|
||||
contextTextState.textAlign = context.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
|
||||
contextTextState.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
|
||||
context.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
|
||||
}
|
||||
if (contextTextState.textBaseline != textState.textBaseline) {
|
||||
contextTextState.textBaseline = context.textBaseline =
|
||||
/** @type {CanvasTextBaseline} */ (textState.textBaseline);
|
||||
contextTextState.textBaseline = /** @type {CanvasTextBaseline} */ (textState.textBaseline);
|
||||
context.textBaseline = /** @type {CanvasTextBaseline} */ (textState.textBaseline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ class LabelCache extends LRUCache {
|
||||
}
|
||||
}
|
||||
const canvas = this.pop();
|
||||
canvas.width = canvas.height = 0;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
for (const consumerId in this.consumers) {
|
||||
delete this.consumers[consumerId][key];
|
||||
}
|
||||
|
||||
@@ -392,11 +392,13 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
|
||||
const textFillStyle = textStyle.getFill();
|
||||
if (!textFillStyle) {
|
||||
fillState = this.textFillState_ = null;
|
||||
fillState = null;
|
||||
this.textFillState_ = fillState;
|
||||
} else {
|
||||
fillState = this.textFillState_;
|
||||
if (!fillState) {
|
||||
fillState = this.textFillState_ = /** @type {import("../canvas.js").FillState} */ ({});
|
||||
fillState = /** @type {import("../canvas.js").FillState} */ ({});
|
||||
this.textFillState_ = fillState;
|
||||
}
|
||||
fillState.fillStyle = asColorLike(
|
||||
textFillStyle.getColor() || defaultFillStyle);
|
||||
@@ -404,11 +406,13 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
|
||||
const textStrokeStyle = textStyle.getStroke();
|
||||
if (!textStrokeStyle) {
|
||||
strokeState = this.textStrokeState_ = null;
|
||||
strokeState = null;
|
||||
this.textStrokeState_ = strokeState;
|
||||
} else {
|
||||
strokeState = this.textStrokeState_;
|
||||
if (!strokeState) {
|
||||
strokeState = this.textStrokeState_ = /** @type {import("../canvas.js").StrokeState} */ ({});
|
||||
strokeState = /** @type {import("../canvas.js").StrokeState} */ ({});
|
||||
this.textStrokeState_ = strokeState;
|
||||
}
|
||||
const lineDash = textStrokeStyle.getLineDash();
|
||||
const lineDashOffset = textStrokeStyle.getLineDashOffset();
|
||||
|
||||
@@ -62,7 +62,10 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
|
||||
const image = originalStyle.getImage();
|
||||
if (image) {
|
||||
const imgSize = image.getImageSize();
|
||||
const imgContext = createCanvasContext2D(imgSize[0], imgSize[1]);
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = imgSize[0];
|
||||
canvas.height = imgSize[1];
|
||||
const imgContext = canvas.getContext('2d', {alpha: false});
|
||||
imgContext.fillStyle = color;
|
||||
const img = imgContext.canvas;
|
||||
imgContext.fillRect(0, 0, img.width, img.height);
|
||||
@@ -87,7 +90,8 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
|
||||
const zIndex = Number(style.getZIndex());
|
||||
let byGeometryType = featuresByZIndex[zIndex];
|
||||
if (!byGeometryType) {
|
||||
byGeometryType = featuresByZIndex[zIndex] = {};
|
||||
byGeometryType = {};
|
||||
featuresByZIndex[zIndex] = byGeometryType;
|
||||
byGeometryType[GeometryType.POLYGON] = [];
|
||||
byGeometryType[GeometryType.CIRCLE] = [];
|
||||
byGeometryType[GeometryType.LINE_STRING] = [];
|
||||
@@ -133,13 +137,10 @@ export function hitDetect(pixel, features, imageData) {
|
||||
const r = imageData.data[index];
|
||||
const g = imageData.data[index + 1];
|
||||
const b = imageData.data[index + 2];
|
||||
const a = imageData.data[index + 3];
|
||||
if (a === 255) {
|
||||
const i = b + (256 * (g + (256 * r)));
|
||||
const indexFactor = Math.ceil((256 * 256 * 256) / features.length);
|
||||
if (i % indexFactor === 0) {
|
||||
resultFeatures.push(features[i / indexFactor]);
|
||||
}
|
||||
const i = b + (256 * (g + (256 * r)));
|
||||
const indexFactor = Math.ceil((256 * 256 * 256) / features.length);
|
||||
if (i % indexFactor === 0) {
|
||||
resultFeatures.push(features[i / indexFactor]);
|
||||
}
|
||||
}
|
||||
return resultFeatures;
|
||||
|
||||
@@ -98,11 +98,9 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
const viewState = frameState.viewState;
|
||||
|
||||
this.children_.length = 0;
|
||||
let hasOverlay = false;
|
||||
let previousElement = null;
|
||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
const layerState = layerStatesArray[i];
|
||||
hasOverlay = hasOverlay || layerState.hasOverlay;
|
||||
frameState.layerIndex = i;
|
||||
if (!inView(layerState, viewState) ||
|
||||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
|
||||
@@ -114,13 +112,8 @@ class CompositeMapRenderer extends MapRenderer {
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
const childElementCount = element.childElementCount;
|
||||
if ((element !== previousElement || i == ii - 1) && childElementCount === 2 && !hasOverlay) {
|
||||
element.removeChild(element.lastElementChild);
|
||||
}
|
||||
if (element !== previousElement) {
|
||||
this.children_.push(element);
|
||||
hasOverlay = childElementCount === 2;
|
||||
previousElement = element;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +134,8 @@ class MapRenderer extends Disposable {
|
||||
if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter.call(thisArg2, layer)) {
|
||||
const layerRenderer = layer.getRenderer();
|
||||
const source = layer.getSource();
|
||||
const coordinates = source.getWrapX() ? translatedCoordinate : coordinate;
|
||||
if (layerRenderer && source) {
|
||||
const coordinates = source.getWrapX() ? translatedCoordinate : coordinate;
|
||||
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
|
||||
tmpCoord[0] = coordinates[0] + offsets[i][0];
|
||||
tmpCoord[1] = coordinates[1] + offsets[i][1];
|
||||
|
||||
@@ -7,7 +7,7 @@ import {containsExtent, intersects} from '../../extent.js';
|
||||
import {fromUserExtent} from '../../proj.js';
|
||||
import {getIntersection, isEmpty} from '../../extent.js';
|
||||
import CanvasLayerRenderer from './Layer.js';
|
||||
import {compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
|
||||
import {compose as composeTransform, makeInverse} from '../../transform.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -92,7 +92,8 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
const rotation = viewState.rotation;
|
||||
if (rotation) {
|
||||
const size = Math.round(Math.sqrt(width * width + height * height));
|
||||
width = height = size;
|
||||
width = size;
|
||||
height = size;
|
||||
}
|
||||
|
||||
// set forward and inverse pixel transforms
|
||||
@@ -104,7 +105,9 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
);
|
||||
makeInverse(this.inversePixelTransform, this.pixelTransform);
|
||||
|
||||
this.useContainer(target, this.pixelTransform, layerState.opacity);
|
||||
const canvasTransform = this.createTransformString(this.pixelTransform);
|
||||
|
||||
this.useContainer(target, canvasTransform, layerState.opacity);
|
||||
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
@@ -162,7 +165,6 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
|
||||
context.restore();
|
||||
}
|
||||
|
||||
const canvasTransform = transformToString(this.pixelTransform);
|
||||
if (canvasTransform !== canvas.style.transform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import RenderEvent from '../../render/Event.js';
|
||||
import RenderEventType from '../../render/EventType.js';
|
||||
import {rotateAtOffset} from '../../render/canvas.js';
|
||||
import LayerRenderer from '../Layer.js';
|
||||
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString as transformToString} from '../../transform.js';
|
||||
import {create as createTransform, apply as applyTransform, compose as composeTransform, toString} from '../../transform.js';
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
@@ -69,12 +69,18 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
*/
|
||||
this.containerReused = false;
|
||||
|
||||
/**
|
||||
* @type {HTMLCanvasElement}
|
||||
* @private
|
||||
*/
|
||||
this.createTransformStringCanvas_ = createCanvasContext2D(1, 1).canvas;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a rendering container from an existing target, if compatible.
|
||||
* @param {HTMLElement} target Potential render target.
|
||||
* @param {import("../../transform").Transform} transform Transform.
|
||||
* @param {string} transform CSS Transform.
|
||||
* @param {number} opacity Opacity.
|
||||
*/
|
||||
useContainer(target, transform, opacity) {
|
||||
@@ -86,7 +92,7 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
context = canvas.getContext('2d');
|
||||
}
|
||||
}
|
||||
if (context && context.canvas.style.transform === transformToString(transform)) {
|
||||
if (context && context.canvas.style.transform === transform) {
|
||||
// Container of the previous layer renderer can be used.
|
||||
this.container = target;
|
||||
this.context = context;
|
||||
@@ -263,6 +269,15 @@ class CanvasLayerRenderer extends LayerRenderer {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../transform.js").Transform} transform Transform.
|
||||
* @return {string} CSS transform.
|
||||
*/
|
||||
createTransformString(transform) {
|
||||
this.createTransformStringCanvas_.style.transform = toString(transform);
|
||||
return this.createTransformStringCanvas_.style.transform;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CanvasLayerRenderer;
|
||||
|
||||
@@ -7,7 +7,7 @@ import TileRange from '../../TileRange.js';
|
||||
import TileState from '../../TileState.js';
|
||||
import {createEmpty, equals, getIntersection, getTopLeft} from '../../extent.js';
|
||||
import CanvasLayerRenderer from './Layer.js';
|
||||
import {apply as applyTransform, compose as composeTransform, makeInverse, toString as transformToString} from '../../transform.js';
|
||||
import {apply as applyTransform, compose as composeTransform, makeInverse} from '../../transform.js';
|
||||
import {numberSafeCompareFunction} from '../../array.js';
|
||||
|
||||
/**
|
||||
@@ -175,7 +175,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
|
||||
if (rotation) {
|
||||
const size = Math.round(Math.sqrt(width * width + height * height));
|
||||
width = height = size;
|
||||
width = size;
|
||||
height = size;
|
||||
}
|
||||
|
||||
const dx = tileResolution * width / 2 / tilePixelRatio;
|
||||
@@ -242,7 +243,9 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
-width / 2, -height / 2
|
||||
);
|
||||
|
||||
this.useContainer(target, this.pixelTransform, layerState.opacity);
|
||||
const canvasTransform = this.createTransformString(this.pixelTransform);
|
||||
|
||||
this.useContainer(target, canvasTransform, layerState.opacity);
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
@@ -368,7 +371,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
|
||||
context.restore();
|
||||
}
|
||||
|
||||
const canvasTransform = transformToString(this.pixelTransform);
|
||||
if (canvasTransform !== canvas.style.transform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,9 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
makeScale(this.pixelTransform, 1 / pixelRatio, 1 / pixelRatio);
|
||||
makeInverse(this.inversePixelTransform, this.pixelTransform);
|
||||
|
||||
this.useContainer(target, this.pixelTransform, layerState.opacity);
|
||||
const canvasTransform = transformToString(this.pixelTransform);
|
||||
|
||||
this.useContainer(target, canvasTransform, layerState.opacity);
|
||||
const context = this.context;
|
||||
const canvas = context.canvas;
|
||||
|
||||
@@ -145,7 +147,6 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
||||
if (canvas.width != width || canvas.height != height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const canvasTransform = transformToString(this.pixelTransform);
|
||||
if (canvas.style.transform !== canvasTransform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @module ol/renderer/canvas/VectorTileLayer
|
||||
*/
|
||||
import {getUid} from '../../util.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import TileState from '../../TileState.js';
|
||||
import ViewHint from '../../ViewHint.js';
|
||||
import {listen, unlistenByKey} from '../../events.js';
|
||||
@@ -20,9 +19,8 @@ import {
|
||||
reset as resetTransform,
|
||||
scale as scaleTransform,
|
||||
translate as translateTransform,
|
||||
toString as transformToString,
|
||||
makeScale,
|
||||
makeInverse
|
||||
multiply,
|
||||
scale
|
||||
} from '../../transform.js';
|
||||
import CanvasExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
|
||||
import {clear} from '../../obj.js';
|
||||
@@ -64,31 +62,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
/** @private */
|
||||
this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.overlayContext_ = null;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.overlayContextUid_;
|
||||
|
||||
/**
|
||||
* The transform for rendered pixels to viewport CSS pixels for the overlay canvas.
|
||||
* @private
|
||||
* @type {import("../../transform.js").Transform}
|
||||
*/
|
||||
this.overlayPixelTransform_ = createTransform();
|
||||
|
||||
/**
|
||||
* The transform for viewport CSS pixels to rendered pixels for the overlay canvas.
|
||||
* @private
|
||||
* @type {import("../../transform.js").Transform}
|
||||
*/
|
||||
this.inverseOverlayPixelTransform_ = createTransform();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
@@ -131,37 +104,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
this.tmpTransform_ = createTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
useContainer(target, transform, opacity) {
|
||||
let overlayContext;
|
||||
if (target && target.childElementCount === 2) {
|
||||
overlayContext = target.lastElementChild.getContext('2d');
|
||||
if (!overlayContext) {
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
const containerReused = this.containerReused;
|
||||
super.useContainer(target, transform, opacity);
|
||||
if (containerReused) {
|
||||
this.overlayContext_ = overlayContext || null;
|
||||
this.overlayContextUid_ = overlayContext ? getUid(overlayContext) : undefined;
|
||||
}
|
||||
if (!this.overlayContext_) {
|
||||
const overlayContext = createCanvasContext2D();
|
||||
const style = overlayContext.canvas.style;
|
||||
style.position = 'absolute';
|
||||
style.left = '0';
|
||||
style.transformOrigin = 'top left';
|
||||
this.overlayContext_ = overlayContext;
|
||||
this.overlayContextUid_ = getUid(overlayContext);
|
||||
}
|
||||
if (this.container.childElementCount === 1) {
|
||||
this.container.appendChild(this.overlayContext_.canvas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../VectorRenderTile.js").default} tile Tile.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
@@ -239,8 +181,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
* @inheritDoc
|
||||
*/
|
||||
prepareFrame(frameState) {
|
||||
const layerState = frameState.layerStatesArray[frameState.layerIndex];
|
||||
layerState.hasOverlay = true;
|
||||
const layerRevision = this.getLayer().getRevision();
|
||||
if (this.renderedLayerRevision_ != layerRevision) {
|
||||
this.renderedTiles.length = 0;
|
||||
@@ -281,6 +221,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
executorGroups[i].dispose();
|
||||
}
|
||||
}
|
||||
tile.hitDetectionImageData = null;
|
||||
tile.executorGroups[layerUid] = [];
|
||||
for (let t = 0, tt = sourceTiles.length; t < tt; ++t) {
|
||||
const sourceTile = sourceTiles[t];
|
||||
@@ -318,7 +259,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
if (renderOrder && renderOrder !== builderState.renderedRenderOrder) {
|
||||
features.sort(renderOrder);
|
||||
}
|
||||
sourceTile.hitDetectionImageData = null;
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
const feature = features[i];
|
||||
if (!bufferedExtent || intersects(bufferedExtent, feature.getGeometry().getExtent())) {
|
||||
@@ -405,59 +345,55 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
const projection = this.renderedProjection;
|
||||
const projectionExtent = projection.getExtent();
|
||||
const resolution = this.renderedResolution;
|
||||
const pixelRatio = this.renderedPixelRatio;
|
||||
const tileGrid = source.getTileGridForProjection(projection);
|
||||
const sourceTileGrid = source.getTileGrid();
|
||||
const coordinate = applyTransform(this.renderedPixelToCoordinateTransform_, pixel.slice());
|
||||
const tileCoord = tileGrid.getTileCoordForCoordAndResolution(coordinate, resolution);
|
||||
let sourceTile;
|
||||
let tile;
|
||||
for (let i = 0, ii = this.renderedTiles.length; i < ii; ++i) {
|
||||
if (tileCoord.toString() === this.renderedTiles[i].tileCoord.toString()) {
|
||||
const tile = this.renderedTiles[i];
|
||||
tile = this.renderedTiles[i];
|
||||
if (tile.getState() === TileState.LOADED && tile.hifi) {
|
||||
const extent = tileGrid.getTileCoordExtent(tileCoord);
|
||||
const extent = tileGrid.getTileCoordExtent(tile.tileCoord);
|
||||
if (source.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, extent)) {
|
||||
const worldWidth = getWidth(projectionExtent);
|
||||
const worldsAway = Math.floor((coordinate[0] - projectionExtent[0]) / worldWidth);
|
||||
coordinate[0] -= (worldsAway * worldWidth);
|
||||
}
|
||||
const sourceTiles = source.getSourceTiles(pixelRatio, projection, tile);
|
||||
const sourceTileCoord = sourceTileGrid.getTileCoordForCoordAndResolution(coordinate, resolution);
|
||||
for (let j = 0, jj = sourceTiles.length; j < jj; ++j) {
|
||||
if (sourceTileCoord.toString() === sourceTiles[j].tileCoord.toString()) {
|
||||
sourceTile = sourceTiles[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
tile = undefined;
|
||||
}
|
||||
}
|
||||
if (!sourceTile) {
|
||||
if (!tile) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
const corner = getTopLeft(tileGrid.getTileCoordExtent(sourceTile.tileCoord));
|
||||
const extent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
|
||||
const corner = getTopLeft(extent);
|
||||
const tilePixel = [
|
||||
(coordinate[0] - corner[0]) / resolution,
|
||||
(corner[1] - coordinate[1]) / resolution
|
||||
];
|
||||
if (!sourceTile.hitDetectionImageData) {
|
||||
const tileSize = toSize(sourceTileGrid.getTileSize(sourceTileGrid.getZForResolution(resolution)));
|
||||
const features = tile.getSourceTiles().reduce(function(accumulator, sourceTile) {
|
||||
return accumulator.concat(sourceTile.getFeatures());
|
||||
}, []);
|
||||
if (!tile.hitDetectionImageData) {
|
||||
const tileSize = toSize(tileGrid.getTileSize(tileGrid.getZForResolution(resolution)));
|
||||
const size = [tileSize[0] / 2, tileSize[1] / 2];
|
||||
const rotation = this.renderedRotation_;
|
||||
const transforms = [
|
||||
this.getRenderTransform(tileGrid.getTileCoordCenter(sourceTile.tileCoord),
|
||||
this.getRenderTransform(tileGrid.getTileCoordCenter(tile.wrappedTileCoord),
|
||||
resolution, 0, 0.5, size[0], size[1], 0)
|
||||
];
|
||||
requestAnimationFrame(function() {
|
||||
sourceTile.hitDetectionImageData = createHitDetectionImageData(tileSize, transforms,
|
||||
sourceTile.getFeatures(), layer.getStyleFunction(),
|
||||
tileGrid.getTileCoordExtent(sourceTile.tileCoord), resolution, rotation);
|
||||
resolve(hitDetect(tilePixel, sourceTile.getFeatures(), sourceTile.hitDetectionImageData));
|
||||
tile.hitDetectionImageData = createHitDetectionImageData(tileSize, transforms,
|
||||
features, layer.getStyleFunction(),
|
||||
tileGrid.getTileCoordExtent(tile.wrappedTileCoord),
|
||||
tile.getReplayState(layer).renderedResolution, rotation);
|
||||
resolve(hitDetect(tilePixel, features, tile.hitDetectionImageData));
|
||||
});
|
||||
} else {
|
||||
resolve(hitDetect(tilePixel, sourceTile.getFeatures(), sourceTile.hitDetectionImageData));
|
||||
resolve(hitDetect(tilePixel, features, tile.hitDetectionImageData));
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
@@ -510,7 +446,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
const context = this.overlayContext_;
|
||||
const context = this.context;
|
||||
const declutterReplays = layer.getDeclutter() ? {} : null;
|
||||
const replayTypes = VECTOR_REPLAYS[renderMode];
|
||||
const pixelRatio = frameState.pixelRatio;
|
||||
@@ -520,24 +456,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
const rotation = viewState.rotation;
|
||||
const size = frameState.size;
|
||||
|
||||
// set forward and inverse pixel transforms
|
||||
makeScale(this.overlayPixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
|
||||
makeInverse(this.inverseOverlayPixelTransform_, this.overlayPixelTransform_);
|
||||
|
||||
// resize and clear
|
||||
const canvas = context.canvas;
|
||||
const width = Math.round(size[0] * pixelRatio);
|
||||
const height = Math.round(size[1] * pixelRatio);
|
||||
if (canvas.width != width || canvas.height != height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const canvasTransform = transformToString(this.overlayPixelTransform_);
|
||||
if (canvas.style.transform !== canvasTransform) {
|
||||
canvas.style.transform = canvasTransform;
|
||||
}
|
||||
} else if (getUid(context) === this.overlayContextUid_) {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
const tiles = this.renderedTiles;
|
||||
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
@@ -551,7 +471,10 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
const tileCoord = tile.tileCoord;
|
||||
const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
|
||||
const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] - tileExtent[0];
|
||||
const transform = this.getRenderTransform(center, resolution, rotation, pixelRatio, width, height, worldOffset);
|
||||
const transform = multiply(
|
||||
scale(this.inversePixelTransform.slice(), 1 / pixelRatio, 1 / pixelRatio),
|
||||
this.getRenderTransform(center, resolution, rotation, pixelRatio, width, height, worldOffset)
|
||||
);
|
||||
const executorGroups = tile.executorGroups[getUid(layer)];
|
||||
let clipped = false;
|
||||
for (let t = 0, tt = executorGroups.length; t < tt; ++t) {
|
||||
@@ -711,34 +634,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
replayState.renderedTileResolution = tile.wantedResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getDataAtPixel(pixel, frameState, hitTolerance) {
|
||||
let data = super.getDataAtPixel(pixel, frameState, hitTolerance);
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const renderPixel = applyTransform(this.inverseOverlayPixelTransform_, pixel.slice());
|
||||
const context = this.overlayContext_;
|
||||
|
||||
try {
|
||||
data = context.getImageData(Math.round(renderPixel[0]), Math.round(renderPixel[1]), 1, 1).data;
|
||||
} catch (err) {
|
||||
if (err.name === 'SecurityError') {
|
||||
// tainted canvas, we assume there is data at the given pixel (although there might not be)
|
||||
return new Uint8Array();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
if (data[3] === 0) {
|
||||
return null;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class WebGLLayerRenderer extends LayerRenderer {
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.helper.disposeInternal();
|
||||
this.helper.dispose();
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
@@ -169,7 +169,10 @@ export function writePointFeatureToBuffers(instructions, elementIndex, vertexBuf
|
||||
export function getBlankImageData() {
|
||||
const canvas = document.createElement('canvas');
|
||||
const image = canvas.getContext('2d').createImageData(1, 1);
|
||||
image.data[0] = image.data[1] = image.data[2] = image.data[3] = 255;
|
||||
image.data[0] = 255;
|
||||
image.data[1] = 255;
|
||||
image.data[2] = 255;
|
||||
image.data[3] = 255;
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,23 @@ import {getUid} from '../../util.js';
|
||||
import WebGLRenderTarget from '../../webgl/RenderTarget.js';
|
||||
import {assert} from '../../asserts.js';
|
||||
import BaseVector from '../../layer/BaseVector.js';
|
||||
import {listen, unlistenByKey} from '../../events.js';
|
||||
import VectorEventType from '../../source/VectorEventType.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} CustomAttribute A description of a custom attribute to be passed on to the GPU, with a value different
|
||||
* for each feature.
|
||||
* @property {string} name Attribute name.
|
||||
* @property {function(import("../../Feature").default):number} callback This callback computes the numerical value of the
|
||||
* attribute for a given feature.
|
||||
* @property {function(import("../../Feature").default, Object<string, *>):number} callback This callback computes the numerical value of the
|
||||
* attribute for a given feature (properties are available as 2nd arg for quicker access).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FeatureCacheItem Object that holds a reference to a feature, its geometry and properties. Used to optimize
|
||||
* rebuildBuffers by accessing these objects quicker.
|
||||
* @property {import("../../Feature").default} feature Feature
|
||||
* @property {Object<string, *>} properties Feature properties
|
||||
* @property {import("../../geom").Geometry} geometry Feature geometry
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -269,6 +279,72 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.getLayer().changed();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
/**
|
||||
* This object will be updated when the source changes. Key is uid.
|
||||
* @type {Object<string, FeatureCacheItem>}
|
||||
* @private
|
||||
*/
|
||||
this.featureCache_ = {};
|
||||
|
||||
/**
|
||||
* Amount of features in the cache.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.featureCount_ = 0;
|
||||
|
||||
const source = this.getLayer().getSource();
|
||||
this.sourceListenKeys_ = [
|
||||
listen(source, VectorEventType.ADDFEATURE, this.handleSourceFeatureAdded_, this),
|
||||
listen(source, VectorEventType.CHANGEFEATURE, this.handleSourceFeatureChanged_, this),
|
||||
listen(source, VectorEventType.REMOVEFEATURE, this.handleSourceFeatureDelete_, this)
|
||||
];
|
||||
source.forEachFeature(function(feature) {
|
||||
this.featureCache_[getUid(feature)] = {
|
||||
feature: feature,
|
||||
properties: feature.getProperties(),
|
||||
geometry: feature.getGeometry()
|
||||
};
|
||||
this.featureCount_++;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../source/Vector.js").VectorSourceEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
handleSourceFeatureAdded_(event) {
|
||||
const feature = event.feature;
|
||||
this.featureCache_[getUid(feature)] = {
|
||||
feature: feature,
|
||||
properties: feature.getProperties(),
|
||||
geometry: feature.getGeometry()
|
||||
};
|
||||
this.featureCount_++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../source/Vector.js").VectorSourceEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
handleSourceFeatureChanged_(event) {
|
||||
const feature = event.feature;
|
||||
this.featureCache_[getUid(feature)] = {
|
||||
feature: feature,
|
||||
properties: feature.getProperties(),
|
||||
geometry: feature.getGeometry()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../../source/Vector.js").VectorSourceEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
handleSourceFeatureDelete_(event) {
|
||||
const feature = event.feature;
|
||||
delete this.featureCache_[getUid(feature)];
|
||||
this.featureCount_--;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,45 +419,41 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
* @private
|
||||
*/
|
||||
rebuildBuffers_(frameState) {
|
||||
const layer = this.getLayer();
|
||||
const vectorSource = layer.getSource();
|
||||
|
||||
// saves the projection transform for the current frame state
|
||||
const projectionTransform = createTransform();
|
||||
this.helper.makeProjectionTransform(frameState, projectionTransform);
|
||||
|
||||
const features = vectorSource.getFeatures();
|
||||
|
||||
// here we anticipate the amount of render instructions that we well generate
|
||||
// this can be done since we know that for normal render we only have x, y as base instructions,
|
||||
// and x, y, r, g, b, a and featureUid for hit render instructions
|
||||
// and we also know the amount of custom attributes to append to these
|
||||
const totalInstructionsCount = (2 + this.customAttributes.length) * features.length;
|
||||
const totalInstructionsCount = (2 + this.customAttributes.length) * this.featureCount_;
|
||||
if (!this.renderInstructions_ || this.renderInstructions_.length !== totalInstructionsCount) {
|
||||
this.renderInstructions_ = new Float32Array(totalInstructionsCount);
|
||||
}
|
||||
if (this.hitDetectionEnabled_) {
|
||||
const totalHitInstructionsCount = (7 + this.customAttributes.length) * features.length;
|
||||
const totalHitInstructionsCount = (7 + this.customAttributes.length) * this.featureCount_;
|
||||
if (!this.hitRenderInstructions_ || this.hitRenderInstructions_.length !== totalHitInstructionsCount) {
|
||||
this.hitRenderInstructions_ = new Float32Array(totalHitInstructionsCount);
|
||||
}
|
||||
}
|
||||
|
||||
// loop on features to fill the buffer
|
||||
let feature;
|
||||
let featureCache, geometry;
|
||||
const tmpCoords = [];
|
||||
const tmpColor = [];
|
||||
let renderIndex = 0;
|
||||
let hitIndex = 0;
|
||||
let hitColor;
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
feature = features[i];
|
||||
if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
|
||||
for (const featureUid in this.featureCache_) {
|
||||
featureCache = this.featureCache_[featureUid];
|
||||
geometry = /** @type {import("../../geom").Point} */(featureCache.geometry);
|
||||
if (!geometry || geometry.getType() !== GeometryType.POINT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmpCoords[0] = feature.getGeometry().getFlatCoordinates()[0];
|
||||
tmpCoords[1] = feature.getGeometry().getFlatCoordinates()[1];
|
||||
tmpCoords[0] = geometry.getFlatCoordinates()[0];
|
||||
tmpCoords[1] = geometry.getFlatCoordinates()[1];
|
||||
applyTransform(projectionTransform, tmpCoords);
|
||||
|
||||
hitColor = colorEncodeId(hitIndex + 6, tmpColor);
|
||||
@@ -398,13 +470,13 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.hitRenderInstructions_[hitIndex++] = hitColor[1];
|
||||
this.hitRenderInstructions_[hitIndex++] = hitColor[2];
|
||||
this.hitRenderInstructions_[hitIndex++] = hitColor[3];
|
||||
this.hitRenderInstructions_[hitIndex++] = Number(getUid(feature));
|
||||
this.hitRenderInstructions_[hitIndex++] = Number(featureUid);
|
||||
}
|
||||
|
||||
// pushing custom attributes
|
||||
let value;
|
||||
for (let j = 0; j < this.customAttributes.length; j++) {
|
||||
value = this.customAttributes[j].callback(feature);
|
||||
value = this.customAttributes[j].callback(featureCache.feature, featureCache.properties);
|
||||
this.renderInstructions_[renderIndex++] = value;
|
||||
if (this.hitDetectionEnabled_) {
|
||||
this.hitRenderInstructions_[hitIndex++] = value;
|
||||
@@ -448,7 +520,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
|
||||
const pixel = applyTransform(frameState.coordinateToPixelTransform, coordinate.slice());
|
||||
|
||||
const data = this.hitRenderTarget_.readPixel(pixel[0], pixel[1]);
|
||||
const data = this.hitRenderTarget_.readPixel(pixel[0] / 2, pixel[1] / 2);
|
||||
const color = [
|
||||
data[0] / 255,
|
||||
data[1] / 255,
|
||||
@@ -476,7 +548,10 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hitRenderTarget_.setSize(frameState.size);
|
||||
this.hitRenderTarget_.setSize([
|
||||
Math.floor(frameState.size[0] / 2),
|
||||
Math.floor(frameState.size[1] / 2)
|
||||
]);
|
||||
|
||||
this.helper.useProgram(this.hitProgram_);
|
||||
this.helper.prepareDrawToRenderTarget(frameState, this.hitRenderTarget_, true);
|
||||
@@ -495,6 +570,11 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.worker_.terminate();
|
||||
this.layer_ = null;
|
||||
this.sourceListenKeys_.forEach(function(key) {
|
||||
unlistenByKey(key);
|
||||
});
|
||||
this.sourceListenKeys_ = null;
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ export function toSize(size, opt_size) {
|
||||
if (opt_size === undefined) {
|
||||
opt_size = [size, size];
|
||||
} else {
|
||||
opt_size[0] = opt_size[1] = size;
|
||||
opt_size[0] = size;
|
||||
opt_size[1] = size;
|
||||
}
|
||||
return opt_size;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,8 @@ class UrlTile extends TileSource {
|
||||
* @api
|
||||
*/
|
||||
setUrl(url) {
|
||||
const urls = this.urls = expandUrl(url);
|
||||
const urls = expandUrl(url);
|
||||
this.urls = urls;
|
||||
this.setUrls(urls);
|
||||
}
|
||||
|
||||
|
||||
@@ -380,8 +380,9 @@ class VectorTile extends UrlTile {
|
||||
// A tile grid that matches the tile size of the source tile grid is more
|
||||
// likely to have 1:1 relationships between source tiles and rendered tiles.
|
||||
const sourceTileGrid = this.tileGrid;
|
||||
tileGrid = this.tileGrids_[code] = createForProjection(projection, undefined,
|
||||
tileGrid = createForProjection(projection, undefined,
|
||||
sourceTileGrid ? sourceTileGrid.getTileSize(sourceTileGrid.getMinZoom()) : undefined);
|
||||
this.tileGrids_[code] = tileGrid;
|
||||
}
|
||||
return tileGrid;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@ import {asArray, isStringColor} from '../color.js';
|
||||
* * `['time']` returns the time in seconds since the creation of the layer
|
||||
*
|
||||
* * Math operators:
|
||||
* * `['*', value1, value1]` multiplies `value1` by `value2`
|
||||
* * `['/', value1, value1]` divides `value1` by `value2`
|
||||
* * `['+', value1, value1]` adds `value1` and `value2`
|
||||
* * `['-', value1, value1]` subtracts `value2` from `value1`
|
||||
* * `['*', value1, value2]` multiplies `value1` by `value2`
|
||||
* * `['/', value1, value2]` divides `value1` by `value2`
|
||||
* * `['+', value1, value2]` adds `value1` and `value2`
|
||||
* * `['-', value1, value2]` subtracts `value2` from `value1`
|
||||
* * `['clamp', value, low, high]` clamps `value` between `low` and `high`
|
||||
* * `['%', value1, value1]` returns the result of `value1 % value2` (modulo)
|
||||
* * `['^', value1, value1]` returns the value of `value1` raised to the `value2` power
|
||||
* * `['%', value1, value2]` returns the result of `value1 % value2` (modulo)
|
||||
* * `['^', value1, value2]` returns the value of `value1` raised to the `value2` power
|
||||
*
|
||||
* * Transform operators:
|
||||
* * `['case', condition1, output1, ...conditionN, outputN, fallback]` selects the first output whose corresponding
|
||||
@@ -44,12 +44,12 @@ import {asArray, isStringColor} from '../color.js';
|
||||
* between `output1` and `outputN`.
|
||||
*
|
||||
* * Logical operators:
|
||||
* * `['<', value1, value2]` returns `true` if `value1` is strictly lower than value 2, or `false` otherwise.
|
||||
* * `['<=', value1, value2]` returns `true` if `value1` is lower than or equals value 2, or `false` otherwise.
|
||||
* * `['>', value1, value2]` returns `true` if `value1` is strictly greater than value 2, or `false` otherwise.
|
||||
* * `['>=', value1, value2]` returns `true` if `value1` is greater than or equals value 2, or `false` otherwise.
|
||||
* * `['==', value1, value2]` returns `true` if `value1` equals value 2, or `false` otherwise.
|
||||
* * `['!=', value1, value2]` returns `true` if `value1` equals value 2, or `false` otherwise.
|
||||
* * `['<', value1, value2]` returns `true` if `value1` is strictly lower than `value2`, or `false` otherwise.
|
||||
* * `['<=', value1, value2]` returns `true` if `value1` is lower than or equals `value2`, or `false` otherwise.
|
||||
* * `['>', value1, value2]` returns `true` if `value1` is strictly greater than `value2`, or `false` otherwise.
|
||||
* * `['>=', value1, value2]` returns `true` if `value1` is greater than or equals `value2`, or `false` otherwise.
|
||||
* * `['==', value1, value2]` returns `true` if `value1` equals `value2`, or `false` otherwise.
|
||||
* * `['!=', value1, value2]` returns `true` if `value1` does not equal `value2`, or `false` otherwise.
|
||||
* * `['!', value1]` returns `false` if `value1` is `true` or greater than `0`, or `true` otherwise.
|
||||
* * `['between', value1, value2, value3]` returns `true` if `value1` is contained between `value2` and `value3`
|
||||
* (inclusively), or `false` otherwise.
|
||||
@@ -203,6 +203,19 @@ export function colorToGlsl(color) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stable equivalent number for the string literal.
|
||||
* @param {ParsingContext} context Parsing context
|
||||
* @param {string} string String literal value
|
||||
* @returns {number} Number equivalent
|
||||
*/
|
||||
export function getStringNumberEquivalent(context, string) {
|
||||
if (context.stringLiteralsMap[string] === undefined) {
|
||||
context.stringLiteralsMap[string] = Object.keys(context.stringLiteralsMap).length;
|
||||
}
|
||||
return context.stringLiteralsMap[string];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stable equivalent number for the string literal, for use in shaders. This number is then
|
||||
* converted to be a GLSL-compatible string.
|
||||
@@ -211,10 +224,7 @@ export function colorToGlsl(color) {
|
||||
* @returns {string} GLSL-compatible string containing a number
|
||||
*/
|
||||
export function stringToGlsl(context, string) {
|
||||
if (context.stringLiteralsMap[string] === undefined) {
|
||||
context.stringLiteralsMap[string] = Object.keys(context.stringLiteralsMap).length;
|
||||
}
|
||||
return numberToGlsl(context.stringLiteralsMap[string]);
|
||||
return numberToGlsl(getStringNumberEquivalent(context, string));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -114,7 +114,7 @@ export function expandUrl(url) {
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
match = match = /\{(\d+)-(\d+)\}/.exec(url);
|
||||
match = /\{(\d+)-(\d+)\}/.exec(url);
|
||||
if (match) {
|
||||
// number range
|
||||
const stop = parseInt(match[2], 10);
|
||||
|
||||
@@ -266,18 +266,6 @@ class WebGLHelper extends Disposable {
|
||||
*/
|
||||
this.bufferCache_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Array<WebGLShader>}
|
||||
*/
|
||||
this.shaderCache_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Array<WebGLProgram>}
|
||||
*/
|
||||
this.programCache_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {WebGLProgram}
|
||||
@@ -379,10 +367,11 @@ class WebGLHelper extends Disposable {
|
||||
let bufferCache = this.bufferCache_[bufferKey];
|
||||
if (!bufferCache) {
|
||||
const webGlBuffer = gl.createBuffer();
|
||||
bufferCache = this.bufferCache_[bufferKey] = {
|
||||
bufferCache = {
|
||||
buffer: buffer,
|
||||
webGlBuffer: webGlBuffer
|
||||
};
|
||||
this.bufferCache_[bufferKey] = bufferCache;
|
||||
}
|
||||
gl.bindBuffer(buffer.getType(), bufferCache.webGlBuffer);
|
||||
}
|
||||
@@ -418,18 +407,6 @@ class WebGLHelper extends Disposable {
|
||||
disposeInternal() {
|
||||
this.canvas_.removeEventListener(ContextEventType.LOST, this.boundHandleWebGLContextLost_);
|
||||
this.canvas_.removeEventListener(ContextEventType.RESTORED, this.boundHandleWebGLContextRestored_);
|
||||
const gl = this.getGL();
|
||||
if (!gl.isContextLost()) {
|
||||
for (const key in this.bufferCache_) {
|
||||
gl.deleteBuffer(this.bufferCache_[key].buffer);
|
||||
}
|
||||
for (const key in this.programCache_) {
|
||||
gl.deleteProgram(this.programCache_[key]);
|
||||
}
|
||||
for (const key in this.shaderCache_) {
|
||||
gl.deleteShader(this.shaderCache_[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -479,9 +456,10 @@ class WebGLHelper extends Disposable {
|
||||
*/
|
||||
prepareDrawToRenderTarget(frameState, renderTarget, opt_disableAlphaBlend) {
|
||||
const gl = this.getGL();
|
||||
const size = renderTarget.getSize();
|
||||
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, renderTarget.getFramebuffer());
|
||||
gl.viewport(0, 0, frameState.size[0], frameState.size[1]);
|
||||
gl.viewport(0, 0, size[0], size[1]);
|
||||
gl.bindTexture(gl.TEXTURE_2D, renderTarget.getTexture());
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
@@ -651,7 +629,6 @@ class WebGLHelper extends Disposable {
|
||||
const shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
this.shaderCache_.push(shader);
|
||||
return shader;
|
||||
}
|
||||
|
||||
@@ -683,7 +660,6 @@ class WebGLHelper extends Disposable {
|
||||
gl.attachShader(program, fragmentShader);
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.linkProgram(program);
|
||||
this.programCache_.push(program);
|
||||
return program;
|
||||
}
|
||||
|
||||
@@ -810,8 +786,6 @@ class WebGLHelper extends Disposable {
|
||||
*/
|
||||
handleWebGLContextLost() {
|
||||
clear(this.bufferCache_);
|
||||
clear(this.shaderCache_);
|
||||
clear(this.programCache_);
|
||||
this.currentProgram_ = null;
|
||||
}
|
||||
|
||||
@@ -822,8 +796,6 @@ class WebGLHelper extends Disposable {
|
||||
handleWebGLContextRestored() {
|
||||
}
|
||||
|
||||
// TODO: shutdown program
|
||||
|
||||
/**
|
||||
* Will create or reuse a given webgl texture and apply the given size. If no image data
|
||||
* specified, the texture will be empty, otherwise image data will be used and the `size`
|
||||
|
||||
@@ -115,12 +115,21 @@ class WebGLRenderTarget {
|
||||
/**
|
||||
* Reads one pixel of the frame buffer as an array of r, g, b, a components
|
||||
* in the 0-255 range (unsigned byte).
|
||||
* If x and/or y are outside of existing data, an array filled with 0 is returned.
|
||||
* @param {number} x Pixel coordinate
|
||||
* @param {number} y Pixel coordinate
|
||||
* @returns {Uint8Array} Integer array with one color value (4 components)
|
||||
* @api
|
||||
*/
|
||||
readPixel(x, y) {
|
||||
if (x < 0 || y < 0 || x > this.size_[0] || y >= this.size_[1]) {
|
||||
tmpArray4[0] = 0;
|
||||
tmpArray4[1] = 0;
|
||||
tmpArray4[2] = 0;
|
||||
tmpArray4[3] = 0;
|
||||
return tmpArray4;
|
||||
}
|
||||
|
||||
this.readAll();
|
||||
const index = Math.floor(x) + (this.size_[1] - Math.floor(y) - 1) * this.size_[0];
|
||||
tmpArray4[0] = this.data_[index * 4];
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @module ol/webgl/ShaderBuilder
|
||||
*/
|
||||
|
||||
import {expressionToGlsl, stringToGlsl, ValueTypes} from '../style/expressions.js';
|
||||
import {expressionToGlsl, getStringNumberEquivalent, ValueTypes} from '../style/expressions.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} VaryingDescription
|
||||
@@ -450,7 +450,7 @@ export function parseLiteralStyle(style) {
|
||||
}
|
||||
let value = style.variables[varName];
|
||||
if (typeof value === 'string') {
|
||||
value = parseFloat(stringToGlsl(vertContext, value));
|
||||
value = getStringNumberEquivalent(vertContext, value);
|
||||
}
|
||||
return value !== undefined ? value : -9999999; // to avoid matching with the first string literal
|
||||
};
|
||||
@@ -484,10 +484,10 @@ export function parseLiteralStyle(style) {
|
||||
attributes: vertContext.attributes.map(function(attributeName) {
|
||||
return {
|
||||
name: attributeName,
|
||||
callback: function(feature) {
|
||||
let value = feature.get(attributeName);
|
||||
callback: function(feature, props) {
|
||||
let value = props[attributeName];
|
||||
if (typeof value === 'string') {
|
||||
value = parseFloat(stringToGlsl(vertContext, value));
|
||||
value = getStringNumberEquivalent(vertContext, value);
|
||||
}
|
||||
return value !== undefined ? value : -9999999; // to avoid matching with the first string literal
|
||||
}
|
||||
|
||||
@@ -215,7 +215,8 @@ export function makeObjectPropertyPusher(valueReader, opt_property, opt_this) {
|
||||
if (property in object) {
|
||||
array = object[property];
|
||||
} else {
|
||||
array = object[property] = [];
|
||||
array = [];
|
||||
object[property] = array;
|
||||
}
|
||||
array.push(value);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ main() {
|
||||
git log --first-parent --format='%aN|%s %b' ${1} |
|
||||
{
|
||||
while read l; do
|
||||
output="`[[ ${l} =~ "openlayers/greenkeeper" ]] && echo greenkeeper || echo main`_output"
|
||||
output="`[[ ${l} =~ "openlayers/dependabot" ]] && echo dependabot || echo main`_output"
|
||||
if [[ ${l} =~ ${MERGE_RE} ]] ; then
|
||||
number="${BASH_REMATCH[1]}"
|
||||
author="${BASH_REMATCH[2]}"
|
||||
@@ -60,12 +60,12 @@ main() {
|
||||
|
||||
echo -e "$main_output"
|
||||
|
||||
if [ -n "$greenkeeper_output" ]; then
|
||||
if [ -n "$dependabot_output" ]; then
|
||||
echo
|
||||
echo "<details>"
|
||||
echo " <summary>Dependency Updates</summary>"
|
||||
echo
|
||||
echo -e "$greenkeeper_output"
|
||||
echo -e "$dependabot_output"
|
||||
echo
|
||||
echo "</details>"
|
||||
fi
|
||||
|
||||
@@ -23,7 +23,8 @@ describe('ol.control.Attribution', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
const target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
map = new Map({
|
||||
target: target,
|
||||
|
||||
@@ -39,7 +39,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
@@ -165,7 +164,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
@@ -209,7 +207,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: groupExtent,
|
||||
zIndex: 0,
|
||||
@@ -254,7 +251,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 0.3,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: groupExtent,
|
||||
zIndex: 10,
|
||||
@@ -273,7 +269,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 0,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
@@ -290,7 +285,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
@@ -465,7 +459,6 @@ describe('ol.layer.Group', function() {
|
||||
opacity: 0.25,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
|
||||
@@ -57,7 +57,6 @@ describe('ol.layer.Layer', function() {
|
||||
opacity: 1,
|
||||
visible: true,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 0,
|
||||
@@ -99,7 +98,6 @@ describe('ol.layer.Layer', function() {
|
||||
opacity: 0.5,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
@@ -373,7 +371,6 @@ describe('ol.layer.Layer', function() {
|
||||
opacity: 0.33,
|
||||
visible: false,
|
||||
managed: true,
|
||||
hasOverlay: false,
|
||||
sourceState: 'ready',
|
||||
extent: undefined,
|
||||
zIndex: 10,
|
||||
@@ -592,7 +589,7 @@ describe('ol.layer.Layer', function() {
|
||||
const frameState = {
|
||||
layerStatesArray: []
|
||||
};
|
||||
map.dispatchEvent(new RenderEvent('precompose', null, frameState, null, null));
|
||||
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);
|
||||
@@ -644,18 +641,18 @@ describe('ol.layer.Layer', function() {
|
||||
});
|
||||
|
||||
it('has Infinity as zIndex when not configured otherwise', function() {
|
||||
map.dispatchEvent(new RenderEvent('precompose', null,
|
||||
frameState, null, null));
|
||||
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() {
|
||||
layer.setZIndex(42);
|
||||
map.dispatchEvent(new RenderEvent('precompose', null,
|
||||
frameState, null, null));
|
||||
const layerState = frameState.layerStatesArray[0];
|
||||
expect(layerState.zIndex).to.be(42);
|
||||
[-5, 0, 42].forEach(index => {
|
||||
layer.setZIndex(index);
|
||||
map.dispatchEvent(new RenderEvent('precompose', null, frameState, null));
|
||||
const layerState = frameState.layerStatesArray[0];
|
||||
expect(layerState.zIndex).to.be(index);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -197,7 +197,8 @@ describe('ol.Map', function() {
|
||||
let map;
|
||||
beforeEach(function() {
|
||||
const target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
map = new Map({
|
||||
target: target,
|
||||
@@ -259,7 +260,8 @@ describe('ol.Map', function() {
|
||||
let target, map, layer;
|
||||
beforeEach(function() {
|
||||
target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
layer = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
@@ -360,7 +362,8 @@ describe('ol.Map', function() {
|
||||
useGeographic();
|
||||
|
||||
target = document.createElement('div');
|
||||
target.style.width = target.style.height = size + 'px';
|
||||
target.style.width = size + 'px';
|
||||
target.style.height = size + 'px';
|
||||
document.body.appendChild(target);
|
||||
|
||||
map = new Map({
|
||||
@@ -413,7 +416,8 @@ describe('ol.Map', function() {
|
||||
useGeographic();
|
||||
|
||||
target = document.createElement('div');
|
||||
target.style.width = target.style.height = size + 'px';
|
||||
target.style.width = size + 'px';
|
||||
target.style.height = size + 'px';
|
||||
document.body.appendChild(target);
|
||||
|
||||
map = new Map({
|
||||
|
||||
@@ -81,7 +81,8 @@ describe('ol.renderer.canvas.ImageLayer', function() {
|
||||
});
|
||||
|
||||
div = document.createElement('div');
|
||||
div.style.width = div.style.height = '100px';
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
document.body.appendChild(div);
|
||||
map = new Map({
|
||||
target: div,
|
||||
@@ -131,7 +132,8 @@ describe('ol.renderer.canvas.ImageLayer', function() {
|
||||
});
|
||||
|
||||
div = document.createElement('div');
|
||||
div.style.width = div.style.height = '100px';
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
document.body.appendChild(div);
|
||||
map = new Map({
|
||||
target: div,
|
||||
|
||||
@@ -215,12 +215,9 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
||||
url: 'rendering/ol/data/tiles/osm/{z}/{x}/{y}.png'
|
||||
})
|
||||
}));
|
||||
map.once('postcompose', function(e) {
|
||||
expect(e.frameState.layerStatesArray[1].hasOverlay).to.be(true);
|
||||
});
|
||||
map.once('rendercomplete', function() {
|
||||
expect(document.querySelector('.ol-layers').childElementCount).to.be(1);
|
||||
expect(document.querySelector('.ol-layer').childElementCount).to.be(2);
|
||||
expect(document.querySelector('.ol-layer').childElementCount).to.be(1);
|
||||
map.removeLayer(map.getLayers().item(1));
|
||||
map.renderSync();
|
||||
expect(document.querySelector('.ol-layer').childElementCount).to.be(1);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {get as getProjection} from '../../../../../src/ol/proj.js';
|
||||
import ViewHint from '../../../../../src/ol/ViewHint.js';
|
||||
import {WebGLWorkerMessageType} from '../../../../../src/ol/renderer/webgl/Layer.js';
|
||||
import {compose as composeTransform, create as createTransform} from '../../../../../src/ol/transform.js';
|
||||
import {getUid} from '../../../../../src/ol/util.js';
|
||||
|
||||
const baseFrameState = {
|
||||
viewHints: [],
|
||||
@@ -388,4 +389,120 @@ describe('ol.renderer.webgl.PointsLayer', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('featureCache_', function() {
|
||||
let source, layer, features;
|
||||
|
||||
function getCache(feature, renderer) {
|
||||
return renderer.featureCache_[getUid(feature)];
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
source = new VectorSource();
|
||||
layer = new VectorLayer({
|
||||
source
|
||||
});
|
||||
features = [
|
||||
new Feature({
|
||||
id: 'A',
|
||||
test: 'abcd',
|
||||
geometry: new Point([0, 1])
|
||||
}),
|
||||
new Feature({
|
||||
id: 'D',
|
||||
test: 'efgh',
|
||||
geometry: new Point([2, 3])
|
||||
}),
|
||||
new Feature({
|
||||
id: 'C',
|
||||
test: 'ijkl',
|
||||
geometry: new Point([4, 5])
|
||||
})
|
||||
];
|
||||
});
|
||||
|
||||
it('contains no features initially', function() {
|
||||
const renderer = new WebGLPointsLayerRenderer(layer, {
|
||||
vertexShader: simpleVertexShader,
|
||||
fragmentShader: simpleFragmentShader
|
||||
});
|
||||
expect(renderer.featureCount_).to.be(0);
|
||||
});
|
||||
|
||||
it('contains the features initially present in the source', function() {
|
||||
source.addFeatures(features);
|
||||
const renderer = new WebGLPointsLayerRenderer(layer, {
|
||||
vertexShader: simpleVertexShader,
|
||||
fragmentShader: simpleFragmentShader
|
||||
});
|
||||
expect(renderer.featureCount_).to.be(3);
|
||||
expect(getCache(features[0], renderer).feature).to.be(features[0]);
|
||||
expect(getCache(features[0], renderer).geometry).to.be(features[0].getGeometry());
|
||||
expect(getCache(features[0], renderer).properties['test']).to.be(features[0].get('test'));
|
||||
expect(getCache(features[1], renderer).feature).to.be(features[1]);
|
||||
expect(getCache(features[1], renderer).geometry).to.be(features[1].getGeometry());
|
||||
expect(getCache(features[1], renderer).properties['test']).to.be(features[1].get('test'));
|
||||
expect(getCache(features[2], renderer).feature).to.be(features[2]);
|
||||
expect(getCache(features[2], renderer).geometry).to.be(features[2].getGeometry());
|
||||
expect(getCache(features[2], renderer).properties['test']).to.be(features[2].get('test'));
|
||||
});
|
||||
|
||||
it('contains the features added to the source', function() {
|
||||
const renderer = new WebGLPointsLayerRenderer(layer, {
|
||||
vertexShader: simpleVertexShader,
|
||||
fragmentShader: simpleFragmentShader
|
||||
});
|
||||
|
||||
source.addFeature(features[0]);
|
||||
expect(renderer.featureCount_).to.be(1);
|
||||
|
||||
source.addFeature(features[1]);
|
||||
expect(renderer.featureCount_).to.be(2);
|
||||
|
||||
expect(getCache(features[0], renderer).feature).to.be(features[0]);
|
||||
expect(getCache(features[0], renderer).geometry).to.be(features[0].getGeometry());
|
||||
expect(getCache(features[0], renderer).properties['test']).to.be(features[0].get('test'));
|
||||
expect(getCache(features[1], renderer).feature).to.be(features[1]);
|
||||
expect(getCache(features[1], renderer).geometry).to.be(features[1].getGeometry());
|
||||
expect(getCache(features[1], renderer).properties['test']).to.be(features[1].get('test'));
|
||||
});
|
||||
|
||||
it('does not contain the features removed to the source', function() {
|
||||
const renderer = new WebGLPointsLayerRenderer(layer, {
|
||||
vertexShader: simpleVertexShader,
|
||||
fragmentShader: simpleFragmentShader
|
||||
});
|
||||
|
||||
source.addFeatures(features);
|
||||
expect(renderer.featureCount_).to.be(3);
|
||||
|
||||
source.removeFeature(features[1]);
|
||||
expect(renderer.featureCount_).to.be(2);
|
||||
|
||||
expect(getCache(features[0], renderer).feature).to.be(features[0]);
|
||||
expect(getCache(features[0], renderer).geometry).to.be(features[0].getGeometry());
|
||||
expect(getCache(features[0], renderer).properties['test']).to.be(features[0].get('test'));
|
||||
expect(getCache(features[2], renderer).feature).to.be(features[2]);
|
||||
expect(getCache(features[2], renderer).geometry).to.be(features[2].getGeometry());
|
||||
expect(getCache(features[2], renderer).properties['test']).to.be(features[2].get('test'));
|
||||
});
|
||||
|
||||
it('contains up to date properties and geometry', function() {
|
||||
const renderer = new WebGLPointsLayerRenderer(layer, {
|
||||
vertexShader: simpleVertexShader,
|
||||
fragmentShader: simpleFragmentShader
|
||||
});
|
||||
|
||||
source.addFeatures(features);
|
||||
features[0].set('test', 'updated');
|
||||
features[0].set('added', true);
|
||||
features[0].getGeometry().setCoordinates([10, 20]);
|
||||
expect(renderer.featureCount_).to.be(3);
|
||||
|
||||
expect(getCache(features[0], renderer).feature).to.be(features[0]);
|
||||
expect(getCache(features[0], renderer).geometry.getCoordinates()).to.eql([10, 20]);
|
||||
expect(getCache(features[0], renderer).properties['test']).to.be(features[0].get('test'));
|
||||
expect(getCache(features[0], renderer).properties['added']).to.be(features[0].get('added'));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -408,7 +408,8 @@ describe('ol.source.ImageWMS', function() {
|
||||
source.loading = false;
|
||||
});
|
||||
const target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
map = new Map({
|
||||
target: target,
|
||||
|
||||
@@ -158,7 +158,8 @@ describe('ol.source.Vector', function() {
|
||||
url: 'spec/ol/source/vectorsource/single-feature.json'
|
||||
});
|
||||
const target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
map = new Map({
|
||||
target: target,
|
||||
@@ -592,7 +593,8 @@ describe('ol.source.Vector', function() {
|
||||
}
|
||||
});
|
||||
const div = document.createElement('div');
|
||||
div.style.width = div.style.height = '100px';
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
document.body.appendChild(div);
|
||||
const map = new Map({
|
||||
target: div,
|
||||
|
||||
@@ -198,7 +198,8 @@ describe('ol.source.VectorTile', function() {
|
||||
});
|
||||
|
||||
target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
|
||||
map = new Map({
|
||||
|
||||
@@ -206,7 +206,8 @@ describe('ol.source.XYZ', function() {
|
||||
}
|
||||
});
|
||||
const target = document.createElement('div');
|
||||
target.style.width = target.style.height = '100px';
|
||||
target.style.width = '100px';
|
||||
target.style.height = '100px';
|
||||
document.body.appendChild(target);
|
||||
map = new Map({
|
||||
target: target,
|
||||
|
||||
@@ -123,6 +123,26 @@ describe('ol.webgl.RenderTarget', function() {
|
||||
expect(spy.callCount).to.eql(2);
|
||||
});
|
||||
|
||||
it('returns an array filled with 0 if outside of range', function() {
|
||||
const rt = new WebGLRenderTarget(helper, [4, 4]);
|
||||
helper.createTexture([4, 4], testImage_4x4, rt.getTexture());
|
||||
|
||||
let data = rt.readPixel(-1, 0);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(3, -1);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(6, 2);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(2, 7);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(2, 3);
|
||||
expect(data).not.to.eql([0, 0, 0, 0]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user