Compare commits

..

1 Commits

Author SHA1 Message Date
ahocevar
fbe815853d Publish with beta tag 2019-05-30 15:58:19 +02:00
79 changed files with 856 additions and 1172 deletions

View File

@@ -4,19 +4,9 @@
#### Backwards incompatible changes
#### Removal of `TOUCH` constant from `ol/has`
If you were previously using this constant, you can check if `'ontouchstart'` is defined in `window` instead.
```js
if ('ontouchstart' in window) {
// ...
}
```
#### Removal of `GEOLOCATION` constant from `ol/has`
If you were previously using this constant, you can check if `'geolocation'` is defined in `navigator` instead.
If you were previously using this constant, you can check if `'geolocation'` is define in `navigator` instead.
```js
if ('geolocation' in navigator) {

View File

@@ -59,9 +59,7 @@ function includeAugments(doclet) {
});
}
cls._hideConstructor = true;
if (!cls.undocumented) {
cls._documented = true;
}
delete cls.undocumented;
}
}
}
@@ -152,9 +150,6 @@ exports.handlers = {
// Remove all other undocumented symbols
doclet.undocumented = true;
}
if (doclet._documented) {
delete doclet.undocumented;
}
}
}

View File

@@ -214,39 +214,55 @@ function buildNav(members) {
}
return 0;
});
function createEntry(type, v) {
return {
type: type,
longname: v.longname,
name: v.name,
classes: find({
kind: 'class',
memberof: v.longname
}).map(createEntry.bind(this, 'class')),
members: find({
kind: 'member',
memberof: v.longname
}),
methods: find({
kind: 'function',
memberof: v.longname
}),
typedefs: find({
kind: 'typedef',
memberof: v.longname
}),
events: find({
kind: 'event',
memberof: v.longname
})
};
}
_.each(merged, function(v) {
// exclude interfaces from sidebar
if (v.interface !== true) {
if (v.kind == 'module') {
nav.push(createEntry('module', v));
nav.push({
type: 'module',
longname: v.longname,
name: v.name,
members: find({
kind: 'member',
memberof: v.longname
}),
methods: find({
kind: 'function',
memberof: v.longname
}),
typedefs: find({
kind: 'typedef',
memberof: v.longname
}),
events: find({
kind: 'event',
memberof: v.longname
})
});
}
if (v.kind == 'class') {
nav.push({
type: 'class',
longname: v.longname,
name: v.name,
members: find({
kind: 'member',
memberof: v.longname
}),
methods: find({
kind: 'function',
memberof: v.longname
}),
typedefs: find({
kind: 'typedef',
memberof: v.longname
}),
fires: v.fires,
events: find({
kind: 'event',
memberof: v.longname
})
});
}
}
});

View File

@@ -12,18 +12,13 @@ $(function () {
var $item = $(v);
if ($item.data('name') && regexp.test($item.data('name'))) {
const container = $item.parent().parent().parent();
container.show();
container.closest('.itemMembers').show();
container.closest('.item').show();
$item.show();
$item.closest('.itemMembers').show();
$item.closest('.item').show();
}
});
} else {
$el.find('.item, .itemMembers').hide();
$('.navigation>ul>li').show();
$el.find('.item, .itemMembers').show();
}
$el.find('.list').scrollTop(0);

View File

@@ -18,7 +18,7 @@
<sup class="variation"><?js= doc.variation ?></sup>
<?js } ?></h2>
<br>
<?js if (doc.stability || doc.kind == 'namespace' || doc.kind == 'module') {
<?js if (doc.stability || doc.kind == 'namespace') {
var ancestors = doc.ancestors.map(a => a.replace(/>\./g, '>').replace(/\.</g, '<')).join('/');
var parts = [];
if (ancestors) {
@@ -26,20 +26,7 @@
}
var importPath = parts.join('/');
?>
<?js
var nameParts = doc.name.split('/');
var moduleName = nameParts[nameParts.length - 1];
if(moduleName) {
var firstChar = moduleName.charAt(0);
moduleName = firstChar.toUpperCase() + moduleName.slice(1);
var isClassModule = firstChar.toUpperCase() === firstChar;
}
?>
<?js if (doc.kind == 'module' && !isClassModule && nameParts.length < 3) {?>
<pre class="prettyprint source"><code>import * as ol<?js= moduleName ?> from '<?js= doc.name ?>';</code></pre>
<?js } else if(doc.kind !== 'module') { ?>
<pre class="prettyprint source"><code>import <?js= doc.name ?> from '<?js= importPath ?>';</code></pre>
<?js } ?>
<pre class="prettyprint source"><code>import <?js= doc.name ?> from '<?js= importPath ?>';</code></pre>
<?js } ?>
<?js if (doc.classdesc) { ?>
<div class="class-description"><?js= doc.classdesc ?></div>
@@ -156,7 +143,6 @@
<h3 class="subsection-title">Methods</h3>
<dl><?js methods.forEach(function(m) { ?>
<?js m.parent = doc ?>
<?js= self.partial('method.tmpl', m) ?>
<?js }); ?></dl>
<?js } ?>

View File

@@ -27,10 +27,6 @@ var self = this;
</dt>
<dd class="<?js= (data.stability && data.stability !== 'stable') ? 'unstable' : '' ?>">
<?js if (data.parent && data.parent.kind == 'module' && data.parent.name.split('ol/').length < 3) { ?>
<pre class="prettyprint source"><code>import {<?js= data.name ?>} from '<?js= data.parent.name ?>';</code></pre>
<?js } ?>
<?js if (data.description) { ?>
<div class="description">
<?js= data.description ?>

View File

@@ -10,12 +10,11 @@ function toShortName(name) {
</div>
<ul class="list">
<?js
let navbuilder;
this.nav.forEach(navbuilder = function (item) {
this.nav.forEach(function (item) {
?>
<li class="item" data-name="<?js= item.longname ?>">
<span class="title">
<?js= self.linkto(item.longname, item.type === 'module' ? item.longname.replace('module:', '') : item.name) ?>
<?js= self.linkto(item.longname, item.longname.replace('module:', '')) ?>
<?js if (item.type === 'namespace' &&
(item.members.length + item.typedefs.length + item.methods.length +
item.events.length > 0)) { ?>
@@ -23,18 +22,6 @@ function toShortName(name) {
</span>
<ul class="members itemMembers">
<?js
if (item.classes.length) {
?>
<span class="subtitle">Classes</span>
<?js
item.classes.forEach(function (v) {
navbuilder(v);
});
}
?>
</ul>
<ul class="members itemMembers">
<?js
if (item.members.length) {
?>
<span class="subtitle">Members</span>

View File

@@ -228,11 +228,3 @@ Missing or invalid `size`.
### 61
Cannot determine IIIF Image API version from provided image information JSON.
### 62
A `WebGLArrayBuffer` must either be of type `ELEMENT_ARRAY_BUFFER` or `ARRAY_BUFFER`.
### 63
Support for the `OES_element_index_uint` WebGL extension is mandatory for WebGL layers.

View File

@@ -129,7 +129,7 @@ const map = new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json'
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure'
})
}),
new VectorLayer({

View File

@@ -6,7 +6,7 @@ import VectorTileSource from '../src/ol/source/VectorTile.js';
import {Tile as TileLayer, VectorTile as VectorTileLayer} from '../src/ol/layer.js';
import Projection from '../src/ol/proj/Projection.js';
// Converts geojson-vt data to GeoJSON
const replacer = function(key, value) {
if (value.geometry) {
let type;
@@ -46,6 +46,11 @@ const replacer = function(key, value) {
}
};
const tilePixels = new Projection({
code: 'TILE_PIXELS',
units: 'tile-pixels'
});
const map = new Map({
layers: [
new TileLayer({
@@ -68,22 +73,23 @@ fetch(url).then(function(response) {
debug: 1
});
const vectorSource = new VectorTileSource({
format: new GeoJSON({
// Data returned from geojson-vt is in tile pixel units
dataProjection: new Projection({
code: 'TILE_PIXELS',
units: 'tile-pixels',
extent: [0, 0, 4096, 4096]
})
}),
tileUrlFunction: function(tileCoord) {
format: new GeoJSON(),
tileLoadFunction: function(tile) {
const format = tile.getFormat();
const tileCoord = tile.getTileCoord();
const data = tileIndex.getTile(tileCoord[0], tileCoord[1], tileCoord[2]);
const geojson = JSON.stringify({
type: 'FeatureCollection',
features: data ? data.features : []
}, replacer);
return 'data:application/json;charset=UTF-8,' + geojson;
}
const features = format.readFeatures(
JSON.stringify({
type: 'FeatureCollection',
features: data ? data.features : []
}, replacer));
tile.setLoader(function() {
tile.setFeatures(features);
tile.setProjection(tilePixels);
});
},
url: 'data:' // arbitrary url, we don't use it in the tileLoadFunction
});
const vectorLayer = new VectorTileLayer({
source: vectorSource

View File

@@ -56,7 +56,7 @@ const vectorLayer = new VectorLayer({
const rasterLayer = new TileLayer({
source: new TileJSON({
url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
crossOrigin: ''
})
});

View File

@@ -13,8 +13,5 @@ docs: >
The dataset contains around 80k points and can be found here: https://www.kaggle.com/NUFORC/ufo-sightings
tags: "webgl, icon, sprite, point, ufo"
cloak:
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>

View File

@@ -10,8 +10,6 @@ import {fromLonLat} from '../src/ol/proj.js';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
import {lerp} from '../src/ol/math.js';
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
const vectorSource = new Vector({
features: [],
attributions: 'National UFO Reporting Center'
@@ -107,7 +105,7 @@ new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?access_token=' + key,
url: 'https://api.tiles.mapbox.com/v3/mapbox.world-dark.json?secure',
crossOrigin: 'anonymous'
})
}),

View File

@@ -37,7 +37,7 @@ const vectorLayer = new VectorLayer({
const rasterLayer = new TileLayer({
source: new TileJSON({
url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
crossOrigin: ''
})
});

View File

@@ -3,13 +3,13 @@ layout: example.html
title: Mapbox-gl Layer
shortdesc: Example of a Mapbox-gl-js layer integration.
docs: >
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own API key at https://www.maptiler.com/cloud/ when using this example. No map will be visible when the API key has expired.
tags: "simple, mapbox, vector, tiles, maptiler"
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
tags: "simple, mapbox, vector, tiles"
resources:
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.js
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.css
cloak:
- key: ER67WIiPdCQvhgsUjoWK
value: Get your own API key at https://www.maptiler.com/cloud/
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>

View File

@@ -11,7 +11,7 @@ const center = [-98.8, 37.9];
const key = 'ER67WIiPdCQvhgsUjoWK';
const mbMap = new mapboxgl.Map({
style: 'https://api.maptiler.com/maps/bright/style.json?key=' + key,
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key,
attributionControl: false,
boxZoom: false,
center: center,

View File

@@ -2,10 +2,10 @@
layout: example-verbatim.html
title: Vector tiles created from a Mapbox Style object
shortdesc: Example of using ol-mapbox-style with tiles from tilehosting.com.
tags: "vector tiles, mapbox style, ol-mapbox-style, maptiler"
tags: "vector tiles, mapbox style, ol-mapbox-style"
cloak:
- key: ER67WIiPdCQvhgsUjoWK
value: Get your own API key at https://www.maptiler.com/cloud/
- key: lirfd6Fegsjkvs0lshxe
value: Your API key from http://tilehosting.com/ here
---
<!doctype html>
<html lang="en">

View File

@@ -1,3 +1,3 @@
import apply from 'ol-mapbox-style';
apply('map', 'https://api.maptiler.com/maps/topo/style.json?key=ER67WIiPdCQvhgsUjoWK');
apply('map', 'https://maps.tilehosting.com/styles/topo/style.json?key=ER67WIiPdCQvhgsUjoWK');

View File

@@ -7,9 +7,6 @@ docs: >
Click on the map to get a popup. The popup is composed of a few basic elements: a container, a close button, and a place for the content. To anchor the popup to the map, an <code>ol/Overlay</code> is created with the popup container. A listener is registered for the map's <code>click</code> event to display the popup, and another listener is set as the <code>click</code> handler for the close button to hide the popup.
</p>
tags: "overlay, popup"
cloak:
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
value: Your Mapbox access token from https://mapbox.com/ here
---
<div id="map" class="map"></div>
<div id="popup" class="ol-popup">

View File

@@ -6,7 +6,6 @@ import TileLayer from '../src/ol/layer/Tile.js';
import {toLonLat} from '../src/ol/proj.js';
import TileJSON from '../src/ol/source/TileJSON.js';
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
/**
* Elements that make up the popup.
@@ -46,7 +45,7 @@ const map = new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v4/mapbox.natural-earth-hypso-bathy.json?access_token=' + key,
url: 'https://api.tiles.mapbox.com/v3/mapbox.natural-earth-hypso-bathy.json?secure',
crossOrigin: 'anonymous'
})
})

View File

@@ -8,7 +8,7 @@ const map = new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
crossOrigin: 'anonymous'
})
})

View File

@@ -4,7 +4,7 @@ title: UTFGrid
shortdesc: This example shows how to read data from a UTFGrid source.
docs: >
<p>Point to a country to see its name and flag.</p>
Tiles made with <a href="http://tilemill.com">TileMill</a>. Hosting on <a href="mapbox.com">mapbox.com</a> or with open-source <a href="https://github.com/klokantech/tileserver-php/">TileServer</a>.
Tiles made with [TileMill](http://tilemill.com). Hosting on MapBox.com or with open-source [TileServer](https://github.com/klokantech/tileserver-php/).
tags: "utfgrid, tilejson"
cloak:
- key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.0-beta.10",
"version": "6.0.0-beta.9",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -54,8 +54,8 @@
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.3",
"coveralls": "3.0.4",
"eslint": "^6.0.0",
"coveralls": "3.0.3",
"eslint": "^5.16.0",
"eslint-config-openlayers": "^12.0.0",
"expect.js": "0.3.1",
"front-matter": "^3.0.2",
@@ -81,10 +81,10 @@
"marked": "0.6.2",
"mocha": "6.1.4",
"ol-mapbox-style": "^5.0.0-beta.2",
"pixelmatch": "^5.0.0",
"pixelmatch": "^4.0.2",
"pngjs": "^3.4.0",
"proj4": "2.5.0",
"puppeteer": "~1.18.0",
"puppeteer": "~1.17.0",
"rollup": "^1.12.0",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^10.0.0",
@@ -97,7 +97,7 @@
"typescript": "^3.4.5",
"url-polyfill": "^1.1.5",
"walk": "^2.3.9",
"webpack": "4.35.0",
"webpack": "4.32.2",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",

View File

@@ -22,16 +22,5 @@ module.exports = {
context: __dirname,
target: 'web',
entry: entry,
devtool: 'source-map',
module: {
rules: [{
test: /\.js$/,
use: {
loader: path.join(__dirname, '../examples/webpack/worker-loader.js')
},
include: [
path.join(__dirname, '../src/ol/worker')
]
}]
}
devtool: 'source-map'
};

View File

@@ -6,7 +6,6 @@ import ImageState from './ImageState.js';
import {listenOnce, unlistenByKey} from './events.js';
import EventType from './events/EventType.js';
import {getHeight} from './extent.js';
import {IMAGE_DECODE} from './has.js';
/**
@@ -158,8 +157,7 @@ class ImageWrapper extends ImageBase {
*/
export function listenImage(image, loadHandler, errorHandler) {
const img = /** @type {HTMLImageElement} */ (image);
if (IMAGE_DECODE) {
if (img.decode) {
const promise = img.decode();
let listening = true;
const unlisten = function() {
@@ -171,13 +169,7 @@ export function listenImage(image, loadHandler, errorHandler) {
}
}).catch(function(error) {
if (listening) {
// FIXME: Unconditionally call errorHandler() when this bug is fixed upstream:
// https://bugs.webkit.org/show_bug.cgi?id=198527
if (error.name === 'EncodingError' && error.message === 'Invalid image type.') {
loadHandler();
} else {
errorHandler();
}
errorHandler();
}
});
return unlisten;

View File

@@ -260,6 +260,12 @@ class MapBrowserEventHandler extends EventTarget {
this.dragging_);
this.dispatchEvent(newEvent);
}
// Some native android browser triggers mousemove events during small period
// of time. See: https://code.google.com/p/android/issues/detail?id=5491 or
// https://code.google.com/p/android/issues/detail?id=19827
// ex: Galaxy Tab P3110 + Android 4.1.1
pointerEvent.preventDefault();
}
/**

View File

@@ -22,7 +22,7 @@ import {listen, unlistenByKey, unlisten} from './events.js';
import EventType from './events/EventType.js';
import {createEmpty, clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js';
import {TRUE} from './functions.js';
import {DEVICE_PIXEL_RATIO, IMAGE_DECODE} from './has.js';
import {DEVICE_PIXEL_RATIO, TOUCH} from './has.js';
import LayerGroup from './layer/Group.js';
import {hasArea} from './size.js';
import {DROP} from './structs/PriorityQueue.js';
@@ -230,7 +230,7 @@ class PluggableMap extends BaseObject {
* @type {!HTMLElement}
*/
this.viewport_ = document.createElement('div');
this.viewport_.className = 'ol-viewport' + ('ontouchstart' in window ? ' ol-touch' : '');
this.viewport_.className = 'ol-viewport' + (TOUCH ? ' ol-touch' : '');
this.viewport_.style.position = 'relative';
this.viewport_.style.overflow = 'hidden';
this.viewport_.style.width = '100%';
@@ -301,11 +301,6 @@ class PluggableMap extends BaseObject {
*/
this.interactions = optionsInternal.interactions || new Collection();
/**
* @type {import("./events/Target.js").default}
*/
this.labelCache_ = null;
/**
* @type {import("./events.js").EventsKey}
*/
@@ -328,7 +323,7 @@ class PluggableMap extends BaseObject {
* @type {import("./renderer/Map.js").default}
* @private
*/
this.renderer_ = null;
this.renderer_ = this.createRenderer();
/**
* @type {function(Event): void|undefined}
@@ -516,6 +511,24 @@ class PluggableMap extends BaseObject {
overlay.setMap(this);
}
/**
* Attach a label cache for listening to font changes.
* @param {import("./events/Target.js").default} labelCache Label cache.
*/
attachLabelCache(labelCache) {
this.detachLabelCache();
this.labelCacheListenerKey_ = listen(labelCache, EventType.CLEAR, this.redrawText.bind(this));
}
/**
* Detach the label cache, i.e. no longer listen to font changes.
*/
detachLabelCache() {
if (this.labelCacheListenerKey_) {
unlistenByKey(this.labelCacheListenerKey_);
}
}
/**
*
* @inheritDoc
@@ -529,6 +542,11 @@ class PluggableMap extends BaseObject {
removeEventListener(EventType.RESIZE, this.handleResize_, false);
this.handleResize_ = undefined;
}
if (this.animationDelayKey_) {
cancelAnimationFrame(this.animationDelayKey_);
this.animationDelayKey_ = undefined;
}
this.detachLabelCache();
this.setTarget(null);
super.disposeInternal();
}
@@ -967,7 +985,7 @@ class PluggableMap extends BaseObject {
if (frameState) {
const hints = frameState.viewHints;
if (hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING]) {
const lowOnFrameBudget = !IMAGE_DECODE && Date.now() - frameState.time > 8;
const lowOnFrameBudget = Date.now() - frameState.time > 8;
maxTotalLoading = lowOnFrameBudget ? 0 : 8;
maxNewLoads = lowOnFrameBudget ? 0 : 2;
}
@@ -1023,14 +1041,6 @@ class PluggableMap extends BaseObject {
}
if (!targetElement) {
if (this.renderer_) {
this.renderer_.dispose();
this.renderer_ = null;
}
if (this.animationDelayKey_) {
cancelAnimationFrame(this.animationDelayKey_);
this.animationDelayKey_ = undefined;
}
removeNode(this.viewport_);
if (this.handleResize_ !== undefined) {
removeEventListener(EventType.RESIZE, this.handleResize_, false);
@@ -1038,9 +1048,6 @@ class PluggableMap extends BaseObject {
}
} else {
targetElement.appendChild(this.viewport_);
if (!this.renderer_) {
this.renderer_ = this.createRenderer();
}
const keyboardEventTarget = !this.keyboardEventTarget_ ?
targetElement : this.keyboardEventTarget_;
@@ -1159,7 +1166,7 @@ class PluggableMap extends BaseObject {
* @api
*/
render() {
if (this.renderer_ && this.animationDelayKey_ === undefined) {
if (this.animationDelayKey_ === undefined) {
this.animationDelayKey_ = requestAnimationFrame(this.animationDelay_);
}
}

View File

@@ -51,8 +51,8 @@ class ControlledMap extends PluggableMap {
* @property {boolean} [collapsible=true] Whether the control can be collapsed or not.
* @property {string|HTMLElement} [label='»'] Text label to use for the collapsed
* overviewmap button. Instead of text, also an element (e.g. a `span` element) can be used.
* @property {Array<import("../layer/Layer.js").default>|import("../Collection.js").default<import("../layer/Layer.js").default>} [layers]
* Layers for the overview map.
* @property {Array<import("../layer/Layer.js").default>|import("../Collection.js").default<import("../layer/Layer.js").default>} layers
* Layers for the overview map (mandatory).
* @property {function(import("../MapEvent.js").default)} [render] Function called when the control
* should be re-rendered. This is called in a `requestAnimationFrame` callback.
* @property {HTMLElement|string} [target] Specify a target if you want the control
@@ -159,9 +159,13 @@ class OverviewMap extends Control {
const ovmap = this.ovmap_;
if (options.layers) {
options.layers.forEach(function(layer) {
ovmap.addLayer(layer);
});
/** @type {Array<import("../layer/Layer.js").default>} */ (options.layers).forEach(
/**
* @param {import("../layer/Layer.js").default} layer Layer.
*/
(function(layer) {
ovmap.addLayer(layer);
}).bind(this));
}
const box = document.createElement('div');

View File

@@ -13,10 +13,8 @@ import {get as getProjection, equivalent as equivalentProjection, transformExten
* the `dataProjection` of the format is assigned (where set). If the projection
* can not be derived from the data and if no `dataProjection` is set for a format,
* the features will not be reprojected.
* @property {import("../extent.js").Extent} [extent] Tile extent in map units of the tile being read.
* This is only required when reading data with tile pixels as geometry units. When configured,
* a `dataProjection` with `TILE_PIXELS` as `units` and the tile's pixel extent as `extent` needs to be
* provided.
* @property {import("../extent.js").Extent} [extent] Tile extent of the tile being read. This is only used and
* required for {@link module:ol/format/MVT}.
* @property {import("../proj.js").ProjectionLike} [featureProjection] Projection of the feature geometries
* created by the format reader. If not provided, features will be returned in the
* `dataProjection`.
@@ -88,14 +86,9 @@ class FeatureFormat {
getReadOptions(source, opt_options) {
let options;
if (opt_options) {
let dataProjection = opt_options.dataProjection ?
opt_options.dataProjection : this.readProjection(source);
if (opt_options.extent) {
dataProjection = getProjection(dataProjection);
dataProjection.setWorldExtent(opt_options.extent);
}
options = {
dataProjection: dataProjection,
dataProjection: opt_options.dataProjection ?
opt_options.dataProjection : this.readProjection(source),
featureProjection: opt_options.featureProjection
};
}

View File

@@ -39,8 +39,30 @@ export const MAC = ua.indexOf('macintosh') !== -1;
*/
export const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
/**
* Image.prototype.decode() is supported.
* True if browser supports touch events.
* @const
* @type {boolean}
* @api
*/
export const TOUCH = 'ontouchstart' in window;
/**
* True if browser supports pointer events.
* @const
* @type {boolean}
*/
export const IMAGE_DECODE = typeof Image !== 'undefined' && Image.prototype.decode;
export const POINTER = 'PointerEvent' in window;
/**
* True if browser supports ms pointer events (IE 10).
* @const
* @type {boolean}
*/
export const MSPOINTER = !!(navigator.msPointerEnabled);
export {HAS as WEBGL} from './webgl.js';

View File

@@ -167,7 +167,7 @@ class DragPan extends PointerInteraction {
}
/**
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Browser event.
* @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
* @return {boolean} Combined condition result.
*/
function defaultCondition(mapBrowserEvent) {

View File

@@ -35,13 +35,6 @@ const TranslateEventType = {
TRANSLATEEND: 'translateend'
};
/**
* A function that takes an {@link module:ol/Feature} or
* {@link module:ol/render/Feature} and an
* {@link module:ol/layer/Layer} and returns `true` if the feature may be
* translated or `false` otherwise.
* @typedef {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default):boolean} FilterFunction
*/
/**
* @typedef {Object} Options
@@ -52,10 +45,6 @@ const TranslateEventType = {
* function will be called for each layer in the map and should return
* `true` for layers that you want to be translatable. If the option is
* absent, all visible layers will be considered translatable.
* @property {FilterFunction} [filter] A function
* that takes an {@link module:ol/Feature} and an
* {@link module:ol/layer/Layer} and returns `true` if the feature may be
* translated or `false` otherwise.
* @property {number} [hitTolerance=0] Hit-detection tolerance. Pixels inside the radius around the given position
* will be checked for features.
*/
@@ -147,12 +136,6 @@ class Translate extends PointerInteraction {
*/
this.layerFilter_ = layerFilter;
/**
* @private
* @type {FilterFunction}
*/
this.filter_ = options.filter ? options.filter : TRUE;
/**
* @private
* @type {number}
@@ -262,11 +245,9 @@ class Translate extends PointerInteraction {
*/
featuresAtPixel_(pixel, map) {
return map.forEachFeatureAtPixel(pixel,
function(feature, layer) {
if (this.filter_(feature, layer)) {
if (!this.features_ || includes(this.features_.getArray(), feature)) {
return feature;
}
function(feature) {
if (!this.features_ || includes(this.features_.getArray(), feature)) {
return feature;
}
}.bind(this), {
layerFilter: this.layerFilter_,

View File

@@ -93,8 +93,7 @@ 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
});
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
state.sourceState = this.getSourceState();

View File

@@ -72,7 +72,8 @@ class BaseVectorLayer extends Layer {
* @param {Options=} opt_options Options.
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options ?
opt_options : /** @type {Options} */ ({});
const baseOptions = assign({}, options);

View File

@@ -45,7 +45,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

View File

@@ -5,6 +5,11 @@ import BaseTileLayer from './BaseTile.js';
import CanvasTileLayerRenderer from '../renderer/canvas/TileLayer.js';
/**
* @typedef {import("./BaseTile.js").Options} Options
*/
/**
* @classdesc
* For layer sources that provide pre-rendered, tiled images in grids that are
@@ -18,7 +23,7 @@ import CanvasTileLayerRenderer from '../renderer/canvas/TileLayer.js';
class TileLayer extends BaseTileLayer {
/**
* @param {import("./BaseTile.js").Options=} opt_options Tile layer options.
* @param {Options=} opt_options Tile layer options.
*/
constructor(opt_options) {
super(opt_options);

View File

@@ -5,6 +5,11 @@ import BaseVectorLayer from './BaseVector.js';
import CanvasVectorLayerRenderer from '../renderer/canvas/VectorLayer.js';
/**
* @typedef {import("./BaseVector.js").Options} Options
*/
/**
* @classdesc
* Vector data that is rendered client-side.
@@ -17,7 +22,7 @@ import CanvasVectorLayerRenderer from '../renderer/canvas/VectorLayer.js';
*/
class VectorLayer extends BaseVectorLayer {
/**
* @param {import("./BaseVector.js").Options=} opt_options Options.
* @param {Options=} opt_options Options.
*/
constructor(opt_options) {
super(opt_options);

View File

@@ -60,7 +60,7 @@ class VectorImageLayer extends BaseVectorLayer {
* @param {Options=} opt_options Options.
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options ? opt_options : /** @type {Options} */ ({});
const baseOptions = assign({}, options);
delete baseOptions.imageRatio;

View File

@@ -86,12 +86,12 @@ class VectorTileLayer extends BaseVectorLayer {
delete baseOptions.preload;
delete baseOptions.useInterimTilesOnError;
super(/** @type {import("./BaseVector.js").Options} */ (baseOptions));
super(/** @type {import("./Vector.js").Options} */ (baseOptions));
const renderMode = options.renderMode || VectorTileRenderType.HYBRID;
assert(renderMode == undefined ||
renderMode == VectorTileRenderType.IMAGE ||
renderMode == VectorTileRenderType.HYBRID,
renderMode == VectorTileRenderType.IMAGE ||
renderMode == VectorTileRenderType.HYBRID,
28); // `renderMode` must be `'image'` or `'hybrid'`
/**

View File

@@ -63,6 +63,10 @@
border: 1px solid black;
}
.ol-overlay-container {
will-change: left,right,top,bottom;
}
.ol-unsupported {
display: none;
}

View File

@@ -34,6 +34,7 @@
import {listen, unlisten} from '../events.js';
import EventTarget from '../events/Target.js';
import {POINTER, MSPOINTER, TOUCH} from '../has.js';
import PointerEventType from './EventType.js';
import MouseSource, {prepareEvent as prepareMouseEvent} from './MouseSource.js';
import MsSource from './MsSource.js';
@@ -123,15 +124,15 @@ class PointerEventHandler extends EventTarget {
* that generate pointer events.
*/
registerSources() {
if ('PointerEvent' in window) {
if (POINTER) {
this.registerSource('native', new NativeSource(this));
} else if (window.navigator.msPointerEnabled) {
} else if (MSPOINTER) {
this.registerSource('ms', new MsSource(this));
} else {
const mouseSource = new MouseSource(this);
this.registerSource('mouse', mouseSource);
if ('ontouchstart' in window) {
if (TOUCH) {
this.registerSource('touch', new TouchSource(this, mouseSource));
}
}

View File

@@ -60,8 +60,8 @@ import {toEPSG4326, fromEPSG4326, PROJECTIONS as EPSG3857_PROJECTIONS} from './p
import {PROJECTIONS as EPSG4326_PROJECTIONS} from './proj/epsg4326.js';
import Projection from './proj/Projection.js';
import Units, {METERS_PER_UNIT} from './proj/Units.js';
import * as projections from './proj/projections.js';
import {add as addTransformFunc, clear as clearTransformFuncs, get as getTransformFunc} from './proj/transforms.js';
import {add as addProj, clear as clearProj, get as getProj} from './proj/projections.js';
/**
@@ -133,7 +133,7 @@ export function identityTransform(input, opt_output, opt_dimension) {
* @api
*/
export function addProjection(projection) {
addProj(projection.getCode(), projection);
projections.add(projection.getCode(), projection);
addTransformFunc(projection, projection, cloneTransform);
}
@@ -157,7 +157,7 @@ export function addProjections(projections) {
*/
export function get(projectionLike) {
return typeof projectionLike === 'string' ?
getProj(/** @type {string} */ (projectionLike)) :
projections.get(/** @type {string} */ (projectionLike)) :
(/** @type {Projection} */ (projectionLike) || null);
}
@@ -271,7 +271,7 @@ export function addEquivalentTransforms(projections1, projections2, forwardTrans
* Clear all cached projections and transforms.
*/
export function clearAllProjections() {
clearProj();
projections.clear();
clearTransformFuncs();
}

View File

@@ -12,8 +12,9 @@ class RenderEvent extends Event {
* CSS pixels to rendered pixels.
* @param {import("../PluggableMap.js").FrameState=} opt_frameState Frame state.
* @param {?CanvasRenderingContext2D=} opt_context Context.
* @param {?import("../webgl/Helper.js").default=} opt_glContext WebGL Context.
*/
constructor(type, opt_inversePixelTransform, opt_frameState, opt_context) {
constructor(type, opt_inversePixelTransform, opt_frameState, opt_context, opt_glContext) {
super(type);
@@ -40,6 +41,14 @@ class RenderEvent extends Event {
*/
this.context = opt_context;
/**
* WebGL context. Only available when a WebGL renderer is used, null
* otherwise.
* @type {import("../webgl/Helper.js").default|null|undefined}
* @api
*/
this.glContext = opt_glContext;
}
}

View File

@@ -9,8 +9,6 @@ import MapRenderer from './Map.js';
import SourceState from '../source/State.js';
import {replaceChildren} from '../dom.js';
import {labelCache} from '../render/canvas.js';
import EventType from '../events/EventType.js';
import {listen, unlistenByKey} from '../events.js';
/**
@@ -25,11 +23,7 @@ class CompositeMapRenderer extends MapRenderer {
*/
constructor(map) {
super(map);
/**
* @type {import("../events.js").EventsKey}
*/
this.labelCacheKey_ = listen(labelCache, EventType.CLEAR, map.redrawText.bind(map));
map.attachLabelCache(labelCache);
/**
* @private
@@ -72,11 +66,6 @@ class CompositeMapRenderer extends MapRenderer {
}
}
disposeInternal() {
unlistenByKey(this.labelCacheKey_);
super.disposeInternal();
}
/**
* @inheritDoc
*/
@@ -98,11 +87,9 @@ class CompositeMapRenderer extends MapRenderer {
const viewResolution = frameState.viewState.resolution;
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 (!visibleAtResolution(layerState, viewResolution) ||
(layerState.sourceState != SourceState.READY && layerState.sourceState != SourceState.UNDEFINED)) {
@@ -111,15 +98,8 @@ class CompositeMapRenderer extends MapRenderer {
const layer = layerState.layer;
const element = layer.render(frameState, previousElement);
if (!element) {
continue;
}
if ((element !== previousElement || i == ii - 1) && element.childElementCount === 2 && !hasOverlay) {
element.removeChild(element.lastElementChild);
}
if (element !== previousElement) {
this.children_.push(element);
hasOverlay = false;
previousElement = element;
}
}

View File

@@ -95,15 +95,15 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
}
// set forward and inverse pixel transforms
composeTransform(this.pixelTransform,
composeTransform(this.pixelTransform_,
frameState.size[0] / 2, frameState.size[1] / 2,
1 / pixelRatio, 1 / pixelRatio,
rotation,
-width / 2, -height / 2
);
makeInverse(this.inversePixelTransform, this.pixelTransform);
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
this.useContainer(target, this.pixelTransform, layerState.opacity);
this.useContainer(target, this.pixelTransform_, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
@@ -160,7 +160,7 @@ class CanvasImageLayerRenderer extends CanvasLayerRenderer {
context.restore();
}
const canvasTransform = transformToString(this.pixelTransform);
const canvasTransform = transformToString(this.pixelTransform_);
if (canvasTransform !== canvas.style.transform) {
canvas.style.transform = canvasTransform;
}

View File

@@ -44,18 +44,18 @@ class CanvasLayerRenderer extends LayerRenderer {
/**
* The transform for rendered pixels to viewport CSS pixels. This transform must
* be set when rendering a frame and may be used by other functions after rendering.
* @protected
* @private
* @type {import("../../transform.js").Transform}
*/
this.pixelTransform = createTransform();
this.pixelTransform_ = createTransform();
/**
* The transform for viewport CSS pixels to rendered pixels. This transform must
* be set when rendering a frame and may be used by other functions after rendering.
* @protected
* @private
* @type {import("../../transform.js").Transform}
*/
this.inversePixelTransform = createTransform();
this.inversePixelTransform_ = createTransform();
/**
* @protected
@@ -163,7 +163,7 @@ class CanvasLayerRenderer extends LayerRenderer {
applyTransform(frameState.coordinateToPixelTransform, bottomRight);
applyTransform(frameState.coordinateToPixelTransform, bottomLeft);
const inverted = this.inversePixelTransform;
const inverted = this.inversePixelTransform_;
applyTransform(inverted, topLeft);
applyTransform(inverted, topRight);
applyTransform(inverted, bottomRight);
@@ -187,7 +187,7 @@ class CanvasLayerRenderer extends LayerRenderer {
dispatchRenderEvent_(type, context, frameState) {
const layer = this.getLayer();
if (layer.hasListener(type)) {
const event = new RenderEvent(type, this.inversePixelTransform, frameState, context);
const event = new RenderEvent(type, this.inversePixelTransform_, frameState, context, null);
layer.dispatchEvent(event);
}
}
@@ -240,7 +240,7 @@ class CanvasLayerRenderer extends LayerRenderer {
* returned, and empty array will be returned.
*/
getDataAtPixel(pixel, frameState, hitTolerance) {
const renderPixel = applyTransform(this.inversePixelTransform, pixel.slice());
const renderPixel = applyTransform(this.inversePixelTransform_, pixel.slice());
const context = this.context;
let data;

View File

@@ -7,7 +7,6 @@ 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 {numberSafeCompareFunction} from '../../array.js';
/**
* @classdesc
@@ -228,18 +227,18 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
const canvasScale = tileResolution / viewResolution;
// set forward and inverse pixel transforms
composeTransform(this.pixelTransform,
composeTransform(this.pixelTransform_,
frameState.size[0] / 2, frameState.size[1] / 2,
1 / tilePixelRatio, 1 / tilePixelRatio,
rotation,
-width / 2, -height / 2
);
this.useContainer(target, this.pixelTransform, layerState.opacity);
this.useContainer(target, this.pixelTransform_, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
makeInverse(this.inversePixelTransform, this.pixelTransform);
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
// set scale transform for calculating tile positions on the canvas
composeTransform(this.tempTransform_,
@@ -265,7 +264,15 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
this.renderedTiles.length = 0;
/** @type {Array<number>} */
let zs = Object.keys(tilesToDrawByZ).map(Number);
zs.sort(numberSafeCompareFunction);
zs.sort(function(a, b) {
if (a === z) {
return 1;
} else if (b === z) {
return -1;
} else {
return a > b ? 1 : a < b ? -1 : 0;
}
});
let clips, clipZs, currentClip;
if (layerState.opacity === 1 && (!this.containerReused || tileSource.getOpaque(frameState.viewState.projection))) {
@@ -304,37 +311,32 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
const h = nextY - y;
const transition = z === currentZ;
const inTransition = transition && tile.getAlpha(getUid(this), frameState.time) !== 1;
if (!inTransition) {
if (clips) {
// Clip mask for regions in this tile that already filled by a higher z tile
context.save();
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
for (let i = 0, ii = clips.length; i < ii; ++i) {
if (z !== currentZ && currentZ < clipZs[i]) {
const clip = clips[i];
context.beginPath();
// counter-clockwise (outer ring) for current tile
context.moveTo(currentClip[0], currentClip[1]);
context.lineTo(currentClip[2], currentClip[3]);
context.lineTo(currentClip[4], currentClip[5]);
context.lineTo(currentClip[6], currentClip[7]);
// clockwise (inner ring) for higher z tile
context.moveTo(clip[6], clip[7]);
context.lineTo(clip[4], clip[5]);
context.lineTo(clip[2], clip[3]);
context.lineTo(clip[0], clip[1]);
context.clip();
}
if (clips && (!transition || tile.getAlpha(getUid(this), frameState.time) === 1)) {
// Clip mask for regions in this tile that already filled by a higher z tile
context.save();
currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
for (let i = 0, ii = clips.length; i < ii; ++i) {
if (z !== currentZ && currentZ < clipZs[i]) {
const clip = clips[i];
context.beginPath();
// counter-clockwise (outer ring) for current tile
context.moveTo(currentClip[0], currentClip[1]);
context.lineTo(currentClip[2], currentClip[3]);
context.lineTo(currentClip[4], currentClip[5]);
context.lineTo(currentClip[6], currentClip[7]);
// clockwise (inner ring) for higher z tile
context.moveTo(clip[6], clip[7]);
context.lineTo(clip[4], clip[5]);
context.lineTo(clip[2], clip[3]);
context.lineTo(clip[0], clip[1]);
context.clip();
}
clips.push(currentClip);
clipZs.push(currentZ);
} else {
context.clearRect(x, y, w, h);
}
clips.push(currentClip);
clipZs.push(currentZ);
}
this.drawTileImage(tile, frameState, x, y, w, h, tileGutter, transition, layerState.opacity);
if (clips && !inTransition) {
if (clips) {
context.restore();
}
this.renderedTiles.push(tile);
@@ -359,7 +361,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
context.restore();
}
const canvasTransform = transformToString(this.pixelTransform);
const canvasTransform = transformToString(this.pixelTransform_);
if (canvasTransform !== canvas.style.transform) {
canvas.style.transform = canvasTransform;
}

View File

@@ -86,10 +86,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const layerState = frameState.layerStatesArray[frameState.layerIndex];
// set forward and inverse pixel transforms
makeScale(this.pixelTransform, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inversePixelTransform, this.pixelTransform);
makeScale(this.pixelTransform_, 1 / pixelRatio, 1 / pixelRatio);
makeInverse(this.inversePixelTransform_, this.pixelTransform_);
this.useContainer(target, this.pixelTransform, layerState.opacity);
this.useContainer(target, this.pixelTransform_, layerState.opacity);
const context = this.context;
const canvas = context.canvas;
@@ -107,7 +107,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (canvas.width != width || canvas.height != height) {
canvas.width = width;
canvas.height = height;
const canvasTransform = transformToString(this.pixelTransform);
const canvasTransform = transformToString(this.pixelTransform_);
if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform;
}

View File

@@ -64,11 +64,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
*/
this.overlayContext_ = null;
/**
* @type {string}
*/
this.overlayContextUid_;
/**
* The transform for rendered pixels to viewport CSS pixels for the overlay canvas.
* @private
@@ -129,9 +124,11 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
}
const containerReused = this.containerReused;
super.useContainer(target, transform, opacity);
if (containerReused) {
this.overlayContext_ = overlayContext || null;
this.overlayContextUid_ = overlayContext ? getUid(overlayContext) : undefined;
if (containerReused && !this.containerReused && !overlayContext) {
this.overlayContext_ = null;
}
if (this.containerReused && overlayContext) {
this.overlayContext_ = overlayContext;
}
if (!this.overlayContext_) {
const overlayContext = createCanvasContext2D();
@@ -139,7 +136,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
style.position = 'absolute';
style.transformOrigin = 'top left';
this.overlayContext_ = overlayContext;
this.overlayContextUid_ = getUid(overlayContext);
}
if (this.container.childElementCount === 1) {
this.container.appendChild(this.overlayContext_.canvas);
@@ -223,8 +219,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;
@@ -413,7 +407,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
// Unqueue tiles from the image queue when we don't need any more
const usedTiles = frameState.usedTiles[getUid(source)];
for (const tileUid in this.renderTileImageQueue_) {
if (!usedTiles || !(tileUid in usedTiles)) {
if (!(tileUid in usedTiles)) {
delete this.renderTileImageQueue_[tileUid];
}
}
@@ -440,7 +434,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (canvas.style.transform !== canvasTransform) {
canvas.style.transform = canvasTransform;
}
} else if (getUid(context) === this.overlayContextUid_) {
} else if (!this.containerReused) {
context.clearRect(0, 0, width, height);
}

View File

@@ -5,26 +5,6 @@ import LayerRenderer from '../Layer.js';
import WebGLHelper from '../../webgl/Helper.js';
/**
* @enum {string}
*/
export const WebGLWorkerMessageType = {
GENERATE_BUFFERS: 'GENERATE_BUFFERS'
};
/**
* @typedef {Object} WebGLWorkerGenerateBuffersMessage
* This message will trigger the generation of a vertex and an index buffer based on the given render instructions.
* When the buffers are generated, the worked will send a message of the same type to the main thread, with
* the generated buffers in it.
* Note that any addition properties present in the message *will* be sent back to the main thread.
* @property {WebGLWorkerMessageType} type Message type
* @property {ArrayBuffer} renderInstructions Render instructions raw binary buffer.
* @property {ArrayBuffer} [vertexBuffer] Vertices array raw binary buffer (sent by the worker).
* @property {ArrayBuffer} [indexBuffer] Indices array raw binary buffer (sent by the worker).
* @property {number} [customAttributesCount] Amount of custom attributes count in the render instructions.
*/
/**
* @typedef {Object} PostProcessesOptions
* @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than
@@ -56,11 +36,7 @@ class WebGLLayerRenderer extends LayerRenderer {
const options = opt_options || {};
/**
* @type {WebGLHelper}
* @protected
*/
this.helper = new WebGLHelper({
this.helper_ = new WebGLHelper({
postProcesses: options.postProcesses,
uniforms: options.uniforms
});
@@ -79,151 +55,96 @@ class WebGLLayerRenderer extends LayerRenderer {
* @api
*/
getShaderCompileErrors() {
return this.helper.getShaderCompileErrors();
return this.helper_.getShaderCompileErrors();
}
}
/**
* @param {Float32Array} instructions Instructons array in which to write.
* @param {number} elementIndex Index from which render instructions will be written.
* @param {number} x Point center X coordinate
* @param {number} y Point center Y coordinate
* @param {number} u0 Left texture coordinate
* @param {number} v0 Bottom texture coordinate
* @param {number} u1 Right texture coordinate
* @param {number} v1 Top texture coordinate
* @param {number} size Radius of the point
* @param {number} opacity Opacity
* @param {boolean} rotateWithView If true, the point will stay aligned with the view
* @param {Array<number>} color Array holding red, green, blue, alpha values
* @return {number} Index from which the next element should be written
* @private
* Pushes vertices and indices to the given buffers using the geometry coordinates and the following properties
* from the feature:
* - `color`
* - `opacity`
* - `size` (for points)
* - `u0`, `v0`, `u1`, `v1` (for points)
* - `rotateWithView` (for points)
* - `width` (for lines)
* Custom attributes can be designated using the `opt_attributes` argument, otherwise other properties on the
* feature will be ignored.
* @param {import("../../webgl/Buffer").default} vertexBuffer WebGL buffer in which new vertices will be pushed.
* @param {import("../../webgl/Buffer").default} indexBuffer WebGL buffer in which new indices will be pushed.
* @param {import("../../format/GeoJSON").GeoJSONFeature} geojsonFeature Feature in geojson format, coordinates
* expressed in EPSG:4326.
* @param {Array<string>} [opt_attributes] Custom attributes. An array of properties which will be read from the
* feature and pushed in the buffer in the given order. Note: attributes can only be numerical! Any other type or
* NaN will result in `0` being pushed in the buffer.
*/
export function writePointFeatureInstructions(instructions, elementIndex, x, y, u0, v0, u1, v1, size, opacity, rotateWithView, color) {
let i = elementIndex;
instructions[i++] = x;
instructions[i++] = y;
instructions[i++] = u0;
instructions[i++] = v0;
instructions[i++] = u1;
instructions[i++] = v1;
instructions[i++] = size;
instructions[i++] = opacity;
instructions[i++] = rotateWithView ? 1 : 0;
instructions[i++] = color[0];
instructions[i++] = color[1];
instructions[i++] = color[2];
instructions[i++] = color[3];
return i;
export function pushFeatureToBuffer(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes) {
if (!geojsonFeature.geometry) {
return;
}
switch (geojsonFeature.geometry.type) {
case 'Point':
pushPointFeatureToBuffer_(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes);
return;
default:
return;
}
}
const tmpArray_ = [];
const bufferPositions_ = {vertexPosition: 0, indexPosition: 0};
export const POINT_INSTRUCTIONS_COUNT = 13;
export const POINT_VERTEX_STRIDE = 12;
function writePointVertex(buffer, pos, x, y, offsetX, offsetY, u, v, opacity, rotateWithView, red, green, blue, alpha) {
buffer[pos + 0] = x;
buffer[pos + 1] = y;
buffer[pos + 2] = offsetX;
buffer[pos + 3] = offsetY;
buffer[pos + 4] = u;
buffer[pos + 5] = v;
buffer[pos + 6] = opacity;
buffer[pos + 7] = rotateWithView;
buffer[pos + 8] = red;
buffer[pos + 9] = green;
buffer[pos + 10] = blue;
buffer[pos + 11] = alpha;
}
function writeCustomAttrs(buffer, pos, customAttrs) {
if (customAttrs.length) {
buffer.set(customAttrs, pos);
}
}
/**
* An object holding positions both in an index and a vertex buffer.
* @typedef {Object} BufferPositions
* @property {number} vertexPosition Position in the vertex buffer
* @property {number} indexPosition Position in the index buffer
*/
/**
* Pushes a quad (two triangles) based on a point geometry
* @param {Float32Array} instructions Array of render instructions for points.
* @param {number} elementIndex Index from which render instructions will be read.
* @param {Float32Array} vertexBuffer Buffer in the form of a typed array.
* @param {Uint32Array} indexBuffer Buffer in the form of a typed array.
* @param {BufferPositions} [bufferPositions] Buffer write positions; if not specified, positions will be set at 0.
* @param {number} [count] Amount of render instructions that will be read. Default value is POINT_INSTRUCTIONS_COUNT
* but a higher value can be provided; all values beyond the default count will be put in the vertices buffer as
* is, thus allowing specifying custom attributes. Please note: this value should not vary inside the same buffer or
* rendering will break.
* @return {BufferPositions} New buffer positions where to write next
* @property {number} vertexPosition New position in the vertex buffer where future writes should start.
* @property {number} indexPosition New position in the index buffer where future writes should start.
* @param {import("../../webgl/Buffer").default} vertexBuffer WebGL buffer
* @param {import("../../webgl/Buffer").default} indexBuffer WebGL buffer
* @param {import("../../format/GeoJSON").GeoJSONFeature} geojsonFeature Feature
* @param {Array<string>} [opt_attributes] Custom attributes
* @private
*/
export function writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer, bufferPositions, count) {
const count_ = count > POINT_INSTRUCTIONS_COUNT ? count : POINT_INSTRUCTIONS_COUNT;
function pushPointFeatureToBuffer_(vertexBuffer, indexBuffer, geojsonFeature, opt_attributes) {
const stride = 12 + (opt_attributes !== undefined ? opt_attributes.length : 0);
const x = instructions[elementIndex + 0];
const y = instructions[elementIndex + 1];
const u0 = instructions[elementIndex + 2];
const v0 = instructions[elementIndex + 3];
const u1 = instructions[elementIndex + 4];
const v1 = instructions[elementIndex + 5];
const size = instructions[elementIndex + 6];
const opacity = instructions[elementIndex + 7];
const rotateWithView = instructions[elementIndex + 8];
const red = instructions[elementIndex + 9];
const green = instructions[elementIndex + 10];
const blue = instructions[elementIndex + 11];
const alpha = instructions[elementIndex + 12];
// the default vertex buffer stride is 12, plus additional custom values if any
const baseStride = POINT_VERTEX_STRIDE;
const stride = baseStride + count_ - POINT_INSTRUCTIONS_COUNT;
const x = geojsonFeature.geometry.coordinates[0];
const y = geojsonFeature.geometry.coordinates[1];
const u0 = geojsonFeature.properties.u0;
const v0 = geojsonFeature.properties.v0;
const u1 = geojsonFeature.properties.u1;
const v1 = geojsonFeature.properties.v1;
const size = geojsonFeature.properties.size;
const opacity = geojsonFeature.properties.opacity;
const rotateWithView = geojsonFeature.properties.rotateWithView;
const color = geojsonFeature.properties.color;
const red = color[0];
const green = color[1];
const blue = color[2];
const alpha = color[3];
const baseIndex = vertexBuffer.getArray().length / stride;
// read custom numerical attributes on the feature
const customAttrs = tmpArray_;
customAttrs.length = count_ - POINT_INSTRUCTIONS_COUNT;
for (let i = 0; i < customAttrs.length; i++) {
customAttrs[i] = instructions[elementIndex + POINT_INSTRUCTIONS_COUNT + i];
const customAttributeValues = tmpArray_;
customAttributeValues.length = opt_attributes ? opt_attributes.length : 0;
for (let i = 0; i < customAttributeValues.length; i++) {
customAttributeValues[i] = parseFloat(geojsonFeature.properties[opt_attributes[i]]) || 0;
}
let vPos = bufferPositions ? bufferPositions.vertexPosition : 0;
let iPos = bufferPositions ? bufferPositions.indexPosition : 0;
const baseIndex = vPos / stride;
// push vertices for each of the four quad corners (first standard then custom attributes)
writePointVertex(vertexBuffer, vPos, x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha);
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
writePointVertex(vertexBuffer, vPos, x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha);
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
writePointVertex(vertexBuffer, vPos, x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha);
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
writePointVertex(vertexBuffer, vPos, x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha);
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
vPos += stride;
vertexBuffer.getArray().push(x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha);
Array.prototype.push.apply(vertexBuffer.getArray(), customAttributeValues);
indexBuffer[iPos++] = baseIndex; indexBuffer[iPos++] = baseIndex + 1; indexBuffer[iPos++] = baseIndex + 3;
indexBuffer[iPos++] = baseIndex + 1; indexBuffer[iPos++] = baseIndex + 2; indexBuffer[iPos++] = baseIndex + 3;
bufferPositions_.vertexPosition = vPos;
bufferPositions_.indexPosition = iPos;
return bufferPositions_;
indexBuffer.getArray().push(
baseIndex, baseIndex + 1, baseIndex + 3,
baseIndex + 1, baseIndex + 2, baseIndex + 3
);
}
/**

View File

@@ -5,11 +5,9 @@ import WebGLArrayBuffer from '../../webgl/Buffer.js';
import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl.js';
import {DefaultAttrib, DefaultUniform} from '../../webgl/Helper.js';
import GeometryType from '../../geom/GeometryType.js';
import WebGLLayerRenderer, {
getBlankTexture,
POINT_INSTRUCTIONS_COUNT, POINT_VERTEX_STRIDE, WebGLWorkerMessageType,
writePointFeatureInstructions
} from './Layer.js';
import WebGLLayerRenderer, {getBlankTexture, pushFeatureToBuffer} from './Layer.js';
import GeoJSON from '../../format/GeoJSON.js';
import {getUid} from '../../util.js';
import ViewHint from '../../ViewHint.js';
import {createEmpty, equals} from '../../extent.js';
import {
@@ -18,7 +16,6 @@ import {
multiply as multiplyTransform,
apply as applyTransform
} from '../../transform.js';
import {create as createWebGLWorker} from '../../worker/webgl.js';
const VERTEX_SHADER = `
precision mediump float;
@@ -211,15 +208,15 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
this.sourceRevision_ = -1;
this.verticesBuffer_ = new WebGLArrayBuffer(ARRAY_BUFFER, DYNAMIC_DRAW);
this.indicesBuffer_ = new WebGLArrayBuffer(ELEMENT_ARRAY_BUFFER, DYNAMIC_DRAW);
this.verticesBuffer_ = new WebGLArrayBuffer([], DYNAMIC_DRAW);
this.indicesBuffer_ = new WebGLArrayBuffer([], DYNAMIC_DRAW);
this.program_ = this.helper.getProgram(
this.program_ = this.helper_.getProgram(
options.fragmentShader || FRAGMENT_SHADER,
options.vertexShader || VERTEX_SHADER
);
this.helper.useProgram(this.program_);
this.helper_.useProgram(this.program_);
this.sizeCallback_ = options.sizeCallback || function() {
return 1;
@@ -244,6 +241,14 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
return false;
};
this.geojsonFormat_ = new GeoJSON();
/**
* @type {Object<string, import("../../format/GeoJSON").GeoJSONFeature>}
* @private
*/
this.geojsonFeatureCache_ = {};
this.previousExtent_ = createEmpty();
/**
@@ -267,30 +272,6 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
* @private
*/
this.invertRenderTransform_ = createTransform();
/**
* @type {Float32Array}
* @private
*/
this.renderInstructions_ = new Float32Array(0);
this.worker_ = createWebGLWorker();
this.worker_.addEventListener('message', function(event) {
const received = event.data;
if (received.type === WebGLWorkerMessageType.GENERATE_BUFFERS) {
const projectionTransform = received.projectionTransform;
this.verticesBuffer_.fromArrayBuffer(received.vertexBuffer);
this.indicesBuffer_.fromArrayBuffer(received.indexBuffer);
this.helper.flushBufferData(this.verticesBuffer_);
this.helper.flushBufferData(this.indicesBuffer_);
// saves the projection transform for the current frame state
this.renderTransform_ = projectionTransform;
makeInverseTransform(this.invertRenderTransform_, this.renderTransform_);
this.renderInstructions_ = new Float32Array(event.data.renderInstructions);
}
}.bind(this));
}
/**
@@ -304,12 +285,11 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
* @inheritDoc
*/
renderFrame(frameState) {
const renderCount = this.indicesBuffer_.getArray() ? this.indicesBuffer_.getArray().length : 0;
this.helper.drawElements(0, renderCount);
this.helper.finalizeDraw(frameState);
const canvas = this.helper.getCanvas();
const layerState = frameState.layerStatesArray[frameState.layerIndex];
this.helper_.drawElements(0, this.indicesBuffer_.getArray().length);
this.helper_.finalizeDraw(frameState);
const canvas = this.helper_.getCanvas();
const opacity = layerState.opacity;
if (opacity !== parseFloat(canvas.style.opacity)) {
canvas.style.opacity = opacity;
@@ -326,7 +306,8 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
const vectorSource = vectorLayer.getSource();
const viewState = frameState.viewState;
const stride = POINT_VERTEX_STRIDE;
// TODO: get this from somewhere...
const stride = 12;
// the source has changed: clear the feature cache & reload features
const sourceChanged = this.sourceRevision_ < vectorSource.getRevision();
@@ -347,22 +328,22 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
}
// apply the current projection transform with the invert of the one used to fill buffers
this.helper.makeProjectionTransform(frameState, this.currentTransform_);
this.helper_.makeProjectionTransform(frameState, this.currentTransform_);
multiplyTransform(this.currentTransform_, this.invertRenderTransform_);
this.helper.prepareDraw(frameState);
this.helper_.prepareDraw(frameState);
// write new data
this.helper.bindBuffer(this.verticesBuffer_);
this.helper.bindBuffer(this.indicesBuffer_);
this.helper_.bindBuffer(ARRAY_BUFFER, this.verticesBuffer_);
this.helper_.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
const bytesPerFloat = Float32Array.BYTES_PER_ELEMENT;
this.helper.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * stride, 0);
this.helper.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 2);
this.helper.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 4);
this.helper.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 6);
this.helper.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 7);
this.helper.enableAttributeArray(DefaultAttrib.COLOR, 4, FLOAT, bytesPerFloat * stride, bytesPerFloat * 8);
this.helper_.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * stride, 0);
this.helper_.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 2);
this.helper_.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 4);
this.helper_.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 6);
this.helper_.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 7);
this.helper_.enableAttributeArray(DefaultAttrib.COLOR, 4, FLOAT, bytesPerFloat * stride, bytesPerFloat * 8);
return true;
}
@@ -376,59 +357,47 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
const vectorSource = vectorLayer.getSource();
// saves the projection transform for the current frame state
const projectionTransform = createTransform();
this.helper.makeProjectionTransform(frameState, projectionTransform);
this.verticesBuffer_.getArray().length = 0;
this.indicesBuffer_.getArray().length = 0;
const features = vectorSource.getFeatures();
const totalInstructionsCount = POINT_INSTRUCTIONS_COUNT * features.length;
if (!this.renderInstructions_ || this.renderInstructions_.length !== totalInstructionsCount) {
this.renderInstructions_ = new Float32Array(totalInstructionsCount);
}
// saves the projection transform for the current frame state
this.helper_.makeProjectionTransform(frameState, this.renderTransform_);
makeInverseTransform(this.invertRenderTransform_, this.renderTransform_);
// loop on features to fill the buffer
const features = vectorSource.getFeatures();
let feature;
const tmpCoords = [];
let elementIndex = 0;
for (let i = 0; i < features.length; i++) {
feature = features[i];
if (!feature.getGeometry() || feature.getGeometry().getType() !== GeometryType.POINT) {
continue;
}
tmpCoords[0] = this.coordCallback_(feature, 0);
tmpCoords[1] = this.coordCallback_(feature, 1);
applyTransform(projectionTransform, tmpCoords);
let geojsonFeature = this.geojsonFeatureCache_[getUid(feature)];
if (!geojsonFeature) {
geojsonFeature = this.geojsonFormat_.writeFeatureObject(feature);
this.geojsonFeatureCache_[getUid(feature)] = geojsonFeature;
}
elementIndex = writePointFeatureInstructions(
this.renderInstructions_,
elementIndex,
tmpCoords[0],
tmpCoords[1],
this.texCoordCallback_(feature, 0),
this.texCoordCallback_(feature, 1),
this.texCoordCallback_(feature, 2),
this.texCoordCallback_(feature, 3),
this.sizeCallback_(feature),
this.opacityCallback_(feature),
this.rotateWithViewCallback_(feature),
this.colorCallback_(feature, this.colorArray_)
);
geojsonFeature.geometry.coordinates[0] = this.coordCallback_(feature, 0);
geojsonFeature.geometry.coordinates[1] = this.coordCallback_(feature, 1);
applyTransform(this.renderTransform_, geojsonFeature.geometry.coordinates);
geojsonFeature.properties = geojsonFeature.properties || {};
geojsonFeature.properties.color = this.colorCallback_(feature, this.colorArray_);
geojsonFeature.properties.u0 = this.texCoordCallback_(feature, 0);
geojsonFeature.properties.v0 = this.texCoordCallback_(feature, 1);
geojsonFeature.properties.u1 = this.texCoordCallback_(feature, 2);
geojsonFeature.properties.v1 = this.texCoordCallback_(feature, 3);
geojsonFeature.properties.size = this.sizeCallback_(feature);
geojsonFeature.properties.opacity = this.opacityCallback_(feature);
geojsonFeature.properties.rotateWithView = this.rotateWithViewCallback_(feature) ? 1 : 0;
pushFeatureToBuffer(this.verticesBuffer_, this.indicesBuffer_, geojsonFeature);
}
/** @type import('./Layer').WebGLWorkerGenerateBuffersMessage */
const message = {
type: WebGLWorkerMessageType.GENERATE_BUFFERS,
renderInstructions: this.renderInstructions_.buffer
};
// additional properties will be sent back as-is by the worker
message['projectionTransform'] = projectionTransform;
this.worker_.postMessage(message, [this.renderInstructions_.buffer]);
this.renderInstructions_ = null;
this.helper_.flushBufferData(ARRAY_BUFFER, this.verticesBuffer_);
this.helper_.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
}
}
export default WebGLPointsLayerRenderer;

View File

@@ -23,7 +23,6 @@ import TileImage from './TileImage.js';
* for version 1, 'default' for versions 2 and 3.
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
* Higher values can increase reprojection performance, but decrease precision.
* @property {Array<number>} [resolutions] Supported resolutions as given in IIIF 'scaleFactors'
* @property {import("../size.js").Size} size Size of the image [width, height].
* @property {import("../size.js").Size[]} [sizes] Supported scaled image sizes.
* Content of the IIIF info.json 'sizes' property, but as array of Size objects.
@@ -38,7 +37,7 @@ import TileImage from './TileImage.js';
* are supported), the default tilesize is 256.
* @property {number} [transition]
* @property {string} [url] Base URL of the IIIF Image service.
* This should be the same as the IIIF Image ID.
* This should be the same as the IIIF Image @id.
* @property {Versions} [version=Versions.VERSION2] Service's IIIF Image API version.
* @property {number} [zDirection] Indicate which resolution should be used
* by a renderer if the views resolution does not match any resolution of the tile source.
@@ -64,9 +63,6 @@ class IIIF extends TileImage {
*/
constructor(opt_options) {
/**
* @type {Partial<Options>} options
*/
const options = opt_options || {};
let baseUrl = options.url || '';
@@ -87,7 +83,7 @@ class IIIF extends TileImage {
const extent = options.extent || [0, -height, width, 0];
const supportsListedSizes = sizes != undefined && Array.isArray(sizes) && sizes.length > 0;
const supportsListedTiles = tileSize != undefined && (typeof tileSize === 'number' && Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0);
const supportsListedTiles = tileSize != undefined && (Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0);
const supportsArbitraryTiling = supports != undefined && Array.isArray(supports) &&
(supports.includes('regionByPx') || supports.includes('regionByPct')) &&
(supports.includes('sizeByWh') || supports.includes('sizeByH') ||
@@ -103,7 +99,7 @@ class IIIF extends TileImage {
if (supportsListedTiles || supportsArbitraryTiling) {
if (tileSize != undefined) {
if (typeof tileSize === 'number' && Number.isInteger(tileSize) && tileSize > 0) {
if (Number.isInteger(tileSize) && tileSize > 0) {
tileWidth = tileSize;
tileHeight = tileSize;
} else if (Array.isArray(tileSize) && tileSize.length > 0) {
@@ -135,7 +131,7 @@ class IIIF extends TileImage {
resolutions.push(Math.pow(2, i));
}
} else {
const maxScaleFactor = Math.max(...resolutions);
const maxScaleFactor = Math.max([...resolutions]);
// TODO maxScaleFactor might not be a power to 2
maxZoom = Math.round(Math.log(maxScaleFactor) / Math.LN2);
}

View File

@@ -56,7 +56,7 @@ class ImageArcGISRest extends ImageSource {
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options || /** @type {Options} */ ({});
super({
attributions: options.attributions,

View File

@@ -53,7 +53,7 @@ class ImageCanvasSource extends ImageSource {
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options || /** @type {Options} */ ({});
super({
attributions: options.attributions,

View File

@@ -63,7 +63,7 @@ class ImageWMS extends ImageSource {
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options || /** @type {Options} */ ({});
super({
attributions: options.attributions,

View File

@@ -75,7 +75,7 @@ class TileSource extends Source {
if (tileGrid) {
toSize(tileGrid.getTileSize(tileGrid.getMinZoom()), tileSize);
}
const canUseScreen = typeof screen !== 'undefined';
const canUseScreen = 'screen' in self;
const width = canUseScreen ? (screen.availWidth || screen.width) : 1920;
const height = canUseScreen ? (screen.availHeight || screen.height) : 1080;
cacheSize = 4 * Math.ceil(width / tileSize[0]) * Math.ceil(height / tileSize[1]);

View File

@@ -64,7 +64,7 @@ class TileArcGISRest extends TileImage {
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options || /** @type {Options} */ ({});
super({
attributions: options.attributions,

View File

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

View File

@@ -670,7 +670,7 @@ class VectorSource extends Source {
/**
* Get all features whose bounding box intersects the provided extent. Note that this returns an array of
* Get all features in the provided extent. Note that this returns an array of
* all features intersecting the given extent in random order (so it may include
* features whose geometries do not intersect the extent).
*

View File

@@ -24,7 +24,7 @@ class CircleStyle extends RegularShape {
*/
constructor(opt_options) {
const options = opt_options ? opt_options : {};
const options = opt_options || /** @type {Options} */ ({});
super({
points: Infinity,

View File

@@ -4,7 +4,7 @@
/**
* @return {Array<number>} "4x4 matrix representing a 3D identity transform."
* @return {Array<number>} 4x4 matrix representing a 3D identity transform.
*/
export function create() {
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
@@ -14,7 +14,7 @@ export function create() {
/**
* @param {Array<number>} mat4 Flattened 4x4 matrix receiving the result.
* @param {import("../transform.js").Transform} transform Transformation matrix.
* @return {Array<number>} "2D transformation matrix as flattened 4x4 matrix."
* @return {Array<number>} 2D transformation matrix as flattened 4x4 matrix.
*/
export function fromTransform(mat4, transform) {
mat4[0] = transform[0];

View File

@@ -7,6 +7,56 @@
* Constants taken from goog.webgl
*/
/**
* @const
* @type {number}
*/
export const ONE = 1;
/**
* @const
* @type {number}
*/
export const SRC_ALPHA = 0x0302;
/**
* @const
* @type {number}
*/
export const COLOR_ATTACHMENT0 = 0x8CE0;
/**
* @const
* @type {number}
*/
export const COLOR_BUFFER_BIT = 0x00004000;
/**
* @const
* @type {number}
*/
export const TRIANGLES = 0x0004;
/**
* @const
* @type {number}
*/
export const TRIANGLE_STRIP = 0x0005;
/**
* @const
* @type {number}
*/
export const ONE_MINUS_SRC_ALPHA = 0x0303;
/**
* Used by {@link module:ol/webgl/Helper~WebGLHelper} for buffers containing vertices data, such as
* position, color, texture coordinate, etc. These vertices are then referenced by an index buffer
@@ -56,6 +106,41 @@ export const STATIC_DRAW = 0x88E4;
export const DYNAMIC_DRAW = 0x88E8;
/**
* @const
* @type {number}
*/
export const CULL_FACE = 0x0B44;
/**
* @const
* @type {number}
*/
export const BLEND = 0x0BE2;
/**
* @const
* @type {number}
*/
export const STENCIL_TEST = 0x0B90;
/**
* @const
* @type {number}
*/
export const DEPTH_TEST = 0x0B71;
/**
* @const
* @type {number}
*/
export const SCISSOR_TEST = 0x0C11;
/**
* @const
* @type {number}
@@ -83,6 +168,105 @@ export const UNSIGNED_INT = 0x1405;
*/
export const FLOAT = 0x1406;
/**
* @const
* @type {number}
*/
export const RGBA = 0x1908;
/**
* @const
* @type {number}
*/
export const FRAGMENT_SHADER = 0x8B30;
/**
* @const
* @type {number}
*/
export const VERTEX_SHADER = 0x8B31;
/**
* @const
* @type {number}
*/
export const LINK_STATUS = 0x8B82;
/**
* @const
* @type {number}
*/
export const LINEAR = 0x2601;
/**
* @const
* @type {number}
*/
export const TEXTURE_MAG_FILTER = 0x2800;
/**
* @const
* @type {number}
*/
export const TEXTURE_MIN_FILTER = 0x2801;
/**
* @const
* @type {number}
*/
export const TEXTURE_WRAP_S = 0x2802;
/**
* @const
* @type {number}
*/
export const TEXTURE_WRAP_T = 0x2803;
/**
* @const
* @type {number}
*/
export const TEXTURE_2D = 0x0DE1;
/**
* @const
* @type {number}
*/
export const TEXTURE0 = 0x84C0;
/**
* @const
* @type {number}
*/
export const CLAMP_TO_EDGE = 0x812F;
/**
* @const
* @type {number}
*/
export const COMPILE_STATUS = 0x8B81;
/**
* @const
* @type {number}
*/
export const FRAMEBUFFER = 0x8D40;
/** end of goog.webgl constants
*/
@@ -119,21 +303,50 @@ export function getContext(canvas, opt_attributes) {
return null;
}
/**
* @type {Array<string>}
*/
let supportedExtensions;
/**
* @return {Array<string>} List of supported WebGL extensions.
* Include debuggable shader sources. Default is `true`. This should be set to
* `false` for production builds.
* @type {boolean}
*/
export function getSupportedExtensions() {
if (!supportedExtensions) {
export const DEBUG = true;
/**
* The maximum supported WebGL texture size in pixels. If WebGL is not
* supported, the value is set to `undefined`.
* @type {number|undefined}
*/
let MAX_TEXTURE_SIZE; // value is set below
/**
* List of supported WebGL extensions.
* @type {Array<string>}
*/
let EXTENSIONS; // value is set below
/**
* True if both OpenLayers and browser support WebGL.
* @type {boolean}
* @api
*/
let HAS = false;
//TODO Remove side effects
if (typeof window !== 'undefined' && 'WebGLRenderingContext' in window) {
try {
const canvas = document.createElement('canvas');
const gl = getContext(canvas);
if (gl) {
supportedExtensions = gl.getSupportedExtensions();
HAS = true;
MAX_TEXTURE_SIZE = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_SIZE));
EXTENSIONS = gl.getSupportedExtensions();
}
} catch (e) {
// pass
}
return supportedExtensions;
}
export {HAS, MAX_TEXTURE_SIZE, EXTENSIONS};

View File

@@ -2,8 +2,6 @@
* @module ol/webgl/Buffer
*/
import {STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW} from '../webgl.js';
import {ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER} from '../webgl.js';
import {assert} from '../asserts.js';
/**
* Used to describe the intended usage for the data: `STATIC_DRAW`, `STREAM_DRAW`
@@ -19,109 +17,43 @@ export const BufferUsage = {
/**
* @classdesc
* Object used to store an array of data as well as usage information for that data.
* Stores typed arrays internally, either Float32Array or Uint16/32Array depending on
* the buffer type (ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER) and available extensions.
*
* To populate the array, you can either use:
* * A size using `#ofSize(buffer)`
* * An `ArrayBuffer` object using `#fromArrayBuffer(buffer)`
* * A plain array using `#fromArray(array)`
*
* Note:
* See the documentation of [WebGLRenderingContext.bufferData](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData)
* for more info on buffer usage.
* See the documentation of [WebGLRenderingContext.bufferData](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData) for more info.
* @api
*/
class WebGLArrayBuffer {
/**
* @param {number} type Buffer type, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.
* @param {number=} opt_usage Intended usage, either `STATIC_DRAW`, `STREAM_DRAW` or `DYNAMIC_DRAW`.
* Default is `DYNAMIC_DRAW`.
* @param {Array<number>=} opt_arr Array.
* @param {number=} opt_usage Usage, either `STATIC_DRAW`, `STREAM_DRAW` or `DYNAMIC_DRAW`. Default is `DYNAMIC_DRAW`.
*/
constructor(type, opt_usage) {
constructor(opt_arr, opt_usage) {
/**
* @private
* @type {Float32Array|Uint32Array}
* @type {Array<number>}
*/
this.array = null;
this.arr_ = opt_arr !== undefined ? opt_arr : [];
/**
* @private
* @type {number}
*/
this.type = type;
this.usage_ = opt_usage !== undefined ? opt_usage : BufferUsage.STATIC_DRAW;
assert(type === ARRAY_BUFFER || type === ELEMENT_ARRAY_BUFFER, 62);
/**
* @private
* @type {number}
*/
this.usage = opt_usage !== undefined ? opt_usage : BufferUsage.STATIC_DRAW;
}
/**
* Populates the buffer with an array of the given size (all values will be zeroes).
* @param {number} size Array size
*/
ofSize(size) {
this.array = new (getArrayClassForType(this.type))(size);
}
/**
* Populates the buffer with an array of the given size (all values will be zeroes).
* @param {Array<number>} array Numerical array
*/
fromArray(array) {
this.array = (getArrayClassForType(this.type)).from(array);
}
/**
* Populates the buffer with a raw binary array buffer.
* @param {ArrayBuffer} buffer Raw binary buffer to populate the array with. Note that this buffer must have been
* initialized for the same typed array class.
*/
fromArrayBuffer(buffer) {
this.array = new (getArrayClassForType(this.type))(buffer);
}
/**
* @return {number} Buffer type.
*/
getType() {
return this.type;
}
/**
* @return {Float32Array|Uint32Array} Array.
* @return {Array<number>} Array.
*/
getArray() {
return this.array;
return this.arr_;
}
/**
* @return {number} Usage.
*/
getUsage() {
return this.usage;
}
}
/**
* Returns a typed array constructor based on the given buffer type
* @param {number} type Buffer type, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.
* @returns {Float32ArrayConstructor|Uint32ArrayConstructor} The typed array class to use for this buffer.
*/
export function getArrayClassForType(type) {
switch (type) {
case ARRAY_BUFFER:
return Float32Array;
case ELEMENT_ARRAY_BUFFER:
return Uint32Array;
default:
return Float32Array;
return this.usage_;
}
}

View File

@@ -2,22 +2,23 @@
* @module ol/webgl/Helper
*/
import {getUid} from '../util.js';
import {EXTENSIONS as WEBGL_EXTENSIONS} from '../webgl.js';
import Disposable from '../Disposable.js';
import {includes} from '../array.js';
import {listen, unlistenAll} from '../events.js';
import {clear} from '../obj.js';
import {ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, TEXTURE_2D, TEXTURE_WRAP_S, TEXTURE_WRAP_T} from '../webgl.js';
import ContextEventType from '../webgl/ContextEventType.js';
import {
compose as composeTransform,
create as createTransform,
reset as resetTransform,
rotate as rotateTransform,
scale as scaleTransform
scale as scaleTransform,
translate as translateTransform
} from '../transform.js';
import {create, fromTransform} from '../vec/mat4.js';
import WebGLPostProcessingPass from './PostProcessingPass.js';
import {getContext, getSupportedExtensions} from '../webgl.js';
import {includes} from '../array.js';
import {assert} from '../asserts.js';
import {getContext} from '../webgl.js';
/**
@@ -257,8 +258,15 @@ class WebGLHelper extends Disposable {
*/
this.currentProgram_ = null;
assert(includes(getSupportedExtensions(), 'OES_element_index_uint'), 63);
gl.getExtension('OES_element_index_uint');
/**
* @type {boolean}
*/
this.hasOESElementIndexUint = includes(WEBGL_EXTENSIONS, 'OES_element_index_uint');
// use the OES_element_index_uint extension if available
if (this.hasOESElementIndexUint) {
gl.getExtension('OES_element_index_uint');
}
listen(this.canvas_, ContextEventType.LOST,
this.handleWebGLContextLost, this);
@@ -339,10 +347,11 @@ class WebGLHelper extends Disposable {
* Just bind the buffer if it's in the cache. Otherwise create
* the WebGL buffer, bind it, populate it, and add an entry to
* the cache.
* @param {number} target Target, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.
* @param {import("./Buffer").default} buffer Buffer.
* @api
*/
bindBuffer(buffer) {
bindBuffer(target, buffer) {
const gl = this.getGL();
const bufferKey = getUid(buffer);
let bufferCache = this.bufferCache_[bufferKey];
@@ -353,19 +362,28 @@ class WebGLHelper extends Disposable {
webGlBuffer: webGlBuffer
};
}
gl.bindBuffer(buffer.getType(), bufferCache.webGlBuffer);
gl.bindBuffer(target, bufferCache.webGlBuffer);
}
/**
* Update the data contained in the buffer array; this is required for the
* new data to be rendered
* @param {number} target Target, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.
* @param {import("./Buffer").default} buffer Buffer.
* @api
*/
flushBufferData(buffer) {
flushBufferData(target, buffer) {
const gl = this.getGL();
this.bindBuffer(buffer);
gl.bufferData(buffer.getType(), buffer.getArray(), buffer.getUsage());
const arr = buffer.getArray();
this.bindBuffer(target, buffer);
let /** @type {ArrayBufferView} */ arrayBuffer;
if (target == ARRAY_BUFFER) {
arrayBuffer = new Float32Array(arr);
} else if (target == ELEMENT_ARRAY_BUFFER) {
arrayBuffer = this.hasOESElementIndexUint ?
new Uint32Array(arr) : new Uint16Array(arr);
}
gl.bufferData(target, arrayBuffer, buffer.getUsage());
}
/**
@@ -444,8 +462,9 @@ class WebGLHelper extends Disposable {
*/
drawElements(start, end) {
const gl = this.getGL();
const elementType = gl.UNSIGNED_INT;
const elementSize = 4;
const elementType = this.hasOESElementIndexUint ?
gl.UNSIGNED_INT : gl.UNSIGNED_SHORT;
const elementSize = this.hasOESElementIndexUint ? 4 : 2;
const numItems = end - start;
const offsetInBytes = start * elementSize;
@@ -672,12 +691,10 @@ class WebGLHelper extends Disposable {
const center = frameState.viewState.center;
resetTransform(transform);
composeTransform(transform,
0, 0,
2 / (resolution * size[0]), 2 / (resolution * size[1]),
-rotation,
-center[0], -center[1]
);
scaleTransform(transform, 2 / (resolution * size[0]), 2 / (resolution * size[1]));
rotateTransform(transform, -rotation);
translateTransform(transform, -center[0], -center[1]);
return transform;
}
@@ -756,11 +773,11 @@ class WebGLHelper extends Disposable {
if (opt_wrapS !== undefined) {
gl.texParameteri(
gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, opt_wrapS);
TEXTURE_2D, TEXTURE_WRAP_S, opt_wrapS);
}
if (opt_wrapT !== undefined) {
gl.texParameteri(
gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, opt_wrapT);
TEXTURE_2D, TEXTURE_WRAP_T, opt_wrapT);
}
return texture;

View File

@@ -1,48 +0,0 @@
/**
* A worker that does cpu-heavy tasks related to webgl rendering.
* @module ol/worker/webgl
*/
import {
POINT_INSTRUCTIONS_COUNT,
POINT_VERTEX_STRIDE,
WebGLWorkerMessageType,
writePointFeatureToBuffers
} from '../renderer/webgl/Layer.js';
import {assign} from '../obj.js';
onmessage = event => {
const received = event.data;
if (received.type === WebGLWorkerMessageType.GENERATE_BUFFERS) {
const renderInstructions = new Float32Array(received.renderInstructions);
const customAttributesCount = received.customAttributesCount || 0;
const instructionsCount = POINT_INSTRUCTIONS_COUNT + customAttributesCount;
const elementsCount = renderInstructions.length / instructionsCount;
const indicesCount = elementsCount * 6;
const verticesCount = elementsCount * 4 * (POINT_VERTEX_STRIDE + customAttributesCount);
const indexBuffer = new Uint32Array(indicesCount);
const vertexBuffer = new Float32Array(verticesCount);
let bufferPositions = null;
for (let i = 0; i < renderInstructions.length; i += instructionsCount) {
bufferPositions = writePointFeatureToBuffers(
renderInstructions,
i,
vertexBuffer,
indexBuffer,
bufferPositions,
instructionsCount);
}
/** @type {import('../renderer/webgl/Layer').WebGLWorkerGenerateBuffersMessage} */
const message = assign({
vertexBuffer: vertexBuffer.buffer,
indexBuffer: indexBuffer.buffer,
renderInstructions: renderInstructions.buffer
}, received);
postMessage(message, [vertexBuffer.buffer, indexBuffer.buffer, renderInstructions.buffer]);
}
};
export let create;

View File

@@ -20,7 +20,6 @@ async function build(input, {minify = true} = {}) {
common(),
resolve(),
babel({
'externalHelpers': true,
'presets': [
[
'@babel/preset-env',

View File

@@ -5,6 +5,7 @@
"globals": {
"IMAGE_TOLERANCE": false,
"afterLoadText": false,
"assertWebGL": false,
"createMapDiv": true,
"disposeMap": true,
"expect": false,

View File

@@ -8,7 +8,7 @@ import LinearRing from '../../../../src/ol/geom/LinearRing.js';
import MultiPolygon from '../../../../src/ol/geom/MultiPolygon.js';
import Point from '../../../../src/ol/geom/Point.js';
import Polygon from '../../../../src/ol/geom/Polygon.js';
import {fromLonLat, get as getProjection, toLonLat, transform, Projection} from '../../../../src/ol/proj.js';
import {fromLonLat, get as getProjection, toLonLat, transform} from '../../../../src/ol/proj.js';
describe('ol.format.GeoJSON', function() {
@@ -260,28 +260,6 @@ describe('ol.format.GeoJSON', function() {
expect(feature.getGeometry()).to.be.an(Point);
});
it('transforms tile pixel coordinates', function() {
const geojson = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [1024, 1024]
}
};
const format = new GeoJSON({
dataProjection: new Projection({
code: '',
units: 'tile-pixels',
extent: [0, 0, 4096, 4096]
})
});
const feature = format.readFeature(geojson, {
extent: [-180, -90, 180, 90],
featureProjection: 'EPSG:3857'
});
expect(feature.getGeometry().getCoordinates()).to.eql([-135, 45]);
});
});
describe('#readFeatures', function() {

View File

@@ -216,47 +216,6 @@ describe('ol.interaction.Translate', function() {
});
});
describe('moving features, with filter option', function() {
let translate;
beforeEach(function() {
translate = new Translate({
filter: function(feature, layer) {
return feature == features[0];
}
});
map.addInteraction(translate);
});
it('moves a filter-passing feature', function() {
const events = trackEvents(features[0], translate);
simulateEvent('pointermove', 10, 20);
simulateEvent('pointerdown', 10, 20);
simulateEvent('pointerdrag', 50, -40);
simulateEvent('pointerup', 50, -40);
const geometry = features[0].getGeometry();
expect(geometry).to.be.a(Point);
expect(geometry.getCoordinates()).to.eql([50, 40]);
validateEvents(events, [features[0]]);
});
it('does not move a filter-discarded feature', function() {
const events = trackEvents(features[0], translate);
simulateEvent('pointermove', 20, 30);
simulateEvent('pointerdown', 20, 30);
simulateEvent('pointerdrag', 50, -40);
simulateEvent('pointerup', 50, -40);
const geometry = features[1].getGeometry();
expect(geometry).to.be.a(Point);
expect(geometry.getCoordinates()).to.eql([20, -30]);
expect(events).to.be.empty();
});
});
describe('changes css cursor', function() {
let element, translate;

View File

@@ -39,7 +39,6 @@ describe('ol.layer.Group', function() {
opacity: 1,
visible: true,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,
@@ -159,7 +158,6 @@ describe('ol.layer.Group', function() {
opacity: 0.5,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 10,
@@ -201,7 +199,6 @@ describe('ol.layer.Group', function() {
opacity: 0.5,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: groupExtent,
zIndex: 0,
@@ -242,7 +239,6 @@ describe('ol.layer.Group', function() {
opacity: 0.3,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: groupExtent,
zIndex: 10,
@@ -259,7 +255,6 @@ describe('ol.layer.Group', function() {
opacity: 0,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,
@@ -274,7 +269,6 @@ describe('ol.layer.Group', function() {
opacity: 1,
visible: true,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,
@@ -447,7 +441,6 @@ describe('ol.layer.Group', function() {
opacity: 0.25,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,

View File

@@ -49,7 +49,6 @@ describe('ol.layer.Layer', function() {
opacity: 1,
visible: true,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,
@@ -85,7 +84,6 @@ describe('ol.layer.Layer', function() {
opacity: 0.5,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 10,
@@ -184,7 +182,6 @@ describe('ol.layer.Layer', function() {
opacity: 0.33,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 10,
@@ -201,7 +198,6 @@ describe('ol.layer.Layer', function() {
opacity: 0,
visible: false,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,
@@ -216,7 +212,6 @@ describe('ol.layer.Layer', function() {
opacity: 1,
visible: true,
managed: true,
hasOverlay: false,
sourceState: 'ready',
extent: undefined,
zIndex: 0,

View File

@@ -5,6 +5,7 @@ import MapEvent from '../../../src/ol/MapEvent.js';
import Overlay from '../../../src/ol/Overlay.js';
import View from '../../../src/ol/View.js';
import {LineString, Point} from '../../../src/ol/geom.js';
import {TOUCH} from '../../../src/ol/has.js';
import {focus} from '../../../src/ol/events/condition.js';
import {defaults as defaultInteractions} from '../../../src/ol/interaction.js';
import {get as getProjection} from '../../../src/ol/proj.js';
@@ -44,7 +45,7 @@ describe('ol.Map', function() {
it('creates the viewport', function() {
const map = new Map({});
const viewport = map.getViewport();
const className = 'ol-viewport' + ('ontouchstart' in window ? ' ol-touch' : '');
const className = 'ol-viewport' + (TOUCH ? ' ol-touch' : '');
expect(viewport.className).to.be(className);
});

View File

@@ -19,8 +19,6 @@ import Text from '../../../../../src/ol/style/Text.js';
import {createXYZ} from '../../../../../src/ol/tilegrid.js';
import VectorTileRenderType from '../../../../../src/ol/layer/VectorTileRenderType.js';
import {getUid} from '../../../../../src/ol/util.js';
import TileLayer from '../../../../../src/ol/layer/Tile.js';
import XYZ from '../../../../../src/ol/source/XYZ.js';
describe('ol.renderer.canvas.VectorTileLayer', function() {
@@ -41,7 +39,6 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
target.style.height = '256px';
document.body.appendChild(target);
map = new Map({
pixelRatio: 1,
view: new View({
center: [0, 0],
zoom: 0
@@ -206,25 +203,6 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
expect(Object.keys(tile.executorGroups)[1]).to.be(getUid(layer2));
});
it('reuses render container and adds and removes overlay context', function(done) {
map.getLayers().insertAt(0, new TileLayer({
source: new XYZ({
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);
map.removeLayer(map.getLayers().item(1));
map.renderSync();
expect(document.querySelector('.ol-layer').childElementCount).to.be(1);
done();
});
});
});
describe('#prepareFrame', function() {

View File

@@ -1,7 +1,5 @@
import WebGLLayerRenderer, {
getBlankTexture, POINT_INSTRUCTIONS_COUNT, POINT_VERTEX_STRIDE,
writePointFeatureInstructions, writePointFeatureToBuffers
} from '../../../../../src/ol/renderer/webgl/Layer.js';
import WebGLLayerRenderer, {getBlankTexture, pushFeatureToBuffer} from '../../../../../src/ol/renderer/webgl/Layer.js';
import WebGLArrayBuffer from '../../../../../src/ol/webgl/Buffer.js';
import Layer from '../../../../../src/ol/layer/Layer.js';
@@ -30,211 +28,111 @@ describe('ol.renderer.webgl.Layer', function() {
});
describe('writePointFeatureInstructions', function() {
let instructions;
describe('pushFeatureToBuffer', function() {
let vertexBuffer, indexBuffer;
beforeEach(function() {
instructions = new Float32Array(100);
vertexBuffer = new WebGLArrayBuffer();
indexBuffer = new WebGLArrayBuffer();
});
it('writes instructions corresponding to the given parameters', function() {
const baseIndex = 17;
writePointFeatureInstructions(instructions, baseIndex,
1, 2, 3, 4, 5, 6,
7, 8, true, [10, 11, 12, 13]);
expect(instructions[baseIndex + 0]).to.eql(1);
expect(instructions[baseIndex + 1]).to.eql(2);
expect(instructions[baseIndex + 2]).to.eql(3);
expect(instructions[baseIndex + 3]).to.eql(4);
expect(instructions[baseIndex + 4]).to.eql(5);
expect(instructions[baseIndex + 5]).to.eql(6);
expect(instructions[baseIndex + 6]).to.eql(7);
expect(instructions[baseIndex + 7]).to.eql(8);
expect(instructions[baseIndex + 8]).to.eql(1);
expect(instructions[baseIndex + 9]).to.eql(10);
expect(instructions[baseIndex + 10]).to.eql(11);
expect(instructions[baseIndex + 11]).to.eql(12);
expect(instructions[baseIndex + 12]).to.eql(13);
it('does nothing if the feature has no geometry', function() {
const feature = {
type: 'Feature',
id: 'AFG',
properties: {
color: [0.5, 1, 0.2, 0.7],
size: 3
},
geometry: null
};
pushFeatureToBuffer(vertexBuffer, indexBuffer, feature);
expect(vertexBuffer.getArray().length).to.eql(0);
expect(indexBuffer.getArray().length).to.eql(0);
});
it('correctly chains writes', function() {
let baseIndex = 0;
baseIndex = writePointFeatureInstructions(instructions, baseIndex,
1, 2, 3, 4, 5, 6,
7, 8, true, [10, 11, 12, 13]);
baseIndex = writePointFeatureInstructions(instructions, baseIndex,
1, 2, 3, 4, 5, 6,
7, 8, true, [10, 11, 12, 13]);
writePointFeatureInstructions(instructions, baseIndex,
1, 2, 3, 4, 5, 6,
7, 8, true, [10, 11, 12, 13]);
expect(instructions[baseIndex + 0]).to.eql(1);
expect(instructions[baseIndex + 1]).to.eql(2);
expect(instructions[baseIndex + 2]).to.eql(3);
expect(instructions[baseIndex + 3]).to.eql(4);
expect(instructions[baseIndex + 4]).to.eql(5);
expect(instructions[baseIndex + 5]).to.eql(6);
expect(instructions[baseIndex + 6]).to.eql(7);
expect(instructions[baseIndex + 7]).to.eql(8);
expect(instructions[baseIndex + 8]).to.eql(1);
expect(instructions[baseIndex + 9]).to.eql(10);
expect(instructions[baseIndex + 10]).to.eql(11);
expect(instructions[baseIndex + 11]).to.eql(12);
expect(instructions[baseIndex + 12]).to.eql(13);
});
});
describe('writePointFeatureToBuffers', function() {
let vertexBuffer, indexBuffer, instructions, elementIndex;
beforeEach(function() {
vertexBuffer = new Float32Array(100);
indexBuffer = new Uint32Array(100);
instructions = new Float32Array(100);
elementIndex = 3;
writePointFeatureInstructions(instructions, elementIndex,
1, 2, 3, 4, 5, 6,
7, 8, true, [10, 11, 12, 13]);
it('adds two triangles with the correct attributes for a point geometry', function() {
const feature = {
type: 'Feature',
id: 'AFG',
properties: {
color: [0.5, 1, 0.2, 0.7],
size: 3
},
geometry: {
type: 'Point',
coordinates: [-75, 47]
}
};
const attributePerVertex = 12;
pushFeatureToBuffer(vertexBuffer, indexBuffer, feature);
expect(vertexBuffer.getArray().length).to.eql(attributePerVertex * 4);
expect(indexBuffer.getArray().length).to.eql(6);
});
it('writes correctly to the buffers (without custom attributes)', function() {
const stride = POINT_VERTEX_STRIDE;
const positions = writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer);
it('correctly sets indices & coordinates for several features', function() {
const feature = {
type: 'Feature',
id: 'AFG',
properties: {
color: [0.5, 1, 0.2, 0.7],
size: 3
},
geometry: {
type: 'Point',
coordinates: [-75, 47]
}
};
const attributePerVertex = 12;
pushFeatureToBuffer(vertexBuffer, indexBuffer, feature);
pushFeatureToBuffer(vertexBuffer, indexBuffer, feature);
expect(vertexBuffer.getArray()[0]).to.eql(-75);
expect(vertexBuffer.getArray()[1]).to.eql(47);
expect(vertexBuffer.getArray()[0 + attributePerVertex]).to.eql(-75);
expect(vertexBuffer.getArray()[1 + attributePerVertex]).to.eql(47);
expect(vertexBuffer[0]).to.eql(1);
expect(vertexBuffer[1]).to.eql(2);
expect(vertexBuffer[2]).to.eql(-3.5);
expect(vertexBuffer[3]).to.eql(-3.5);
expect(vertexBuffer[4]).to.eql(3);
expect(vertexBuffer[5]).to.eql(4);
expect(vertexBuffer[6]).to.eql(8);
expect(vertexBuffer[7]).to.eql(1);
expect(vertexBuffer[8]).to.eql(10);
expect(vertexBuffer[9]).to.eql(11);
expect(vertexBuffer[10]).to.eql(12);
expect(vertexBuffer[11]).to.eql(13);
// first point
expect(indexBuffer.getArray()[0]).to.eql(0);
expect(indexBuffer.getArray()[1]).to.eql(1);
expect(indexBuffer.getArray()[2]).to.eql(3);
expect(indexBuffer.getArray()[3]).to.eql(1);
expect(indexBuffer.getArray()[4]).to.eql(2);
expect(indexBuffer.getArray()[5]).to.eql(3);
expect(vertexBuffer[stride + 0]).to.eql(1);
expect(vertexBuffer[stride + 1]).to.eql(2);
expect(vertexBuffer[stride + 2]).to.eql(+3.5);
expect(vertexBuffer[stride + 3]).to.eql(-3.5);
expect(vertexBuffer[stride + 4]).to.eql(5);
expect(vertexBuffer[stride + 5]).to.eql(4);
expect(vertexBuffer[stride * 2 + 0]).to.eql(1);
expect(vertexBuffer[stride * 2 + 1]).to.eql(2);
expect(vertexBuffer[stride * 2 + 2]).to.eql(+3.5);
expect(vertexBuffer[stride * 2 + 3]).to.eql(+3.5);
expect(vertexBuffer[stride * 2 + 4]).to.eql(5);
expect(vertexBuffer[stride * 2 + 5]).to.eql(6);
expect(vertexBuffer[stride * 3 + 0]).to.eql(1);
expect(vertexBuffer[stride * 3 + 1]).to.eql(2);
expect(vertexBuffer[stride * 3 + 2]).to.eql(-3.5);
expect(vertexBuffer[stride * 3 + 3]).to.eql(+3.5);
expect(vertexBuffer[stride * 3 + 4]).to.eql(3);
expect(vertexBuffer[stride * 3 + 5]).to.eql(6);
expect(indexBuffer[0]).to.eql(0);
expect(indexBuffer[1]).to.eql(1);
expect(indexBuffer[2]).to.eql(3);
expect(indexBuffer[3]).to.eql(1);
expect(indexBuffer[4]).to.eql(2);
expect(indexBuffer[5]).to.eql(3);
expect(positions.indexPosition).to.eql(6);
expect(positions.vertexPosition).to.eql(stride * 4);
// second point
expect(indexBuffer.getArray()[6]).to.eql(4);
expect(indexBuffer.getArray()[7]).to.eql(5);
expect(indexBuffer.getArray()[8]).to.eql(7);
expect(indexBuffer.getArray()[9]).to.eql(5);
expect(indexBuffer.getArray()[10]).to.eql(6);
expect(indexBuffer.getArray()[11]).to.eql(7);
});
it('writes correctly to the buffers (with custom attributes)', function() {
instructions[elementIndex + POINT_INSTRUCTIONS_COUNT] = 101;
instructions[elementIndex + POINT_INSTRUCTIONS_COUNT + 1] = 102;
instructions[elementIndex + POINT_INSTRUCTIONS_COUNT + 2] = 103;
const stride = POINT_VERTEX_STRIDE + 3;
const positions = writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer,
undefined, POINT_INSTRUCTIONS_COUNT + 3);
expect(vertexBuffer[0]).to.eql(1);
expect(vertexBuffer[1]).to.eql(2);
expect(vertexBuffer[2]).to.eql(-3.5);
expect(vertexBuffer[3]).to.eql(-3.5);
expect(vertexBuffer[4]).to.eql(3);
expect(vertexBuffer[5]).to.eql(4);
expect(vertexBuffer[6]).to.eql(8);
expect(vertexBuffer[7]).to.eql(1);
expect(vertexBuffer[8]).to.eql(10);
expect(vertexBuffer[9]).to.eql(11);
expect(vertexBuffer[10]).to.eql(12);
expect(vertexBuffer[11]).to.eql(13);
expect(vertexBuffer[12]).to.eql(101);
expect(vertexBuffer[13]).to.eql(102);
expect(vertexBuffer[14]).to.eql(103);
expect(vertexBuffer[stride + 12]).to.eql(101);
expect(vertexBuffer[stride + 13]).to.eql(102);
expect(vertexBuffer[stride + 14]).to.eql(103);
expect(vertexBuffer[stride * 2 + 12]).to.eql(101);
expect(vertexBuffer[stride * 2 + 13]).to.eql(102);
expect(vertexBuffer[stride * 2 + 14]).to.eql(103);
expect(vertexBuffer[stride * 3 + 12]).to.eql(101);
expect(vertexBuffer[stride * 3 + 13]).to.eql(102);
expect(vertexBuffer[stride * 3 + 14]).to.eql(103);
expect(indexBuffer[0]).to.eql(0);
expect(indexBuffer[1]).to.eql(1);
expect(indexBuffer[2]).to.eql(3);
expect(indexBuffer[3]).to.eql(1);
expect(indexBuffer[4]).to.eql(2);
expect(indexBuffer[5]).to.eql(3);
expect(positions.indexPosition).to.eql(6);
expect(positions.vertexPosition).to.eql(stride * 4);
it('correctly adds custom attributes', function() {
const feature = {
type: 'Feature',
id: 'AFG',
properties: {
color: [0.5, 1, 0.2, 0.7],
custom: 4,
customString: '5',
custom2: 12.4,
customString2: 'abc'
},
geometry: {
type: 'Point',
coordinates: [-75, 47]
}
};
const attributePerVertex = 16;
pushFeatureToBuffer(vertexBuffer, indexBuffer, feature, ['custom', 'custom2', 'customString', 'customString2']);
expect(vertexBuffer.getArray().length).to.eql(attributePerVertex * 4);
expect(indexBuffer.getArray().length).to.eql(6);
expect(vertexBuffer.getArray()[12]).to.eql(4);
expect(vertexBuffer.getArray()[13]).to.eql(12.4);
expect(vertexBuffer.getArray()[14]).to.eql(5);
expect(vertexBuffer.getArray()[15]).to.eql(0);
});
it('correctly chains buffer writes', function() {
const stride = POINT_VERTEX_STRIDE;
let positions = writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer);
positions = writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer, positions);
positions = writePointFeatureToBuffers(instructions, elementIndex, vertexBuffer, indexBuffer, positions);
expect(vertexBuffer[0]).to.eql(1);
expect(vertexBuffer[1]).to.eql(2);
expect(vertexBuffer[2]).to.eql(-3.5);
expect(vertexBuffer[3]).to.eql(-3.5);
expect(vertexBuffer[stride * 4 + 0]).to.eql(1);
expect(vertexBuffer[stride * 4 + 1]).to.eql(2);
expect(vertexBuffer[stride * 4 + 2]).to.eql(-3.5);
expect(vertexBuffer[stride * 4 + 3]).to.eql(-3.5);
expect(vertexBuffer[stride * 8 + 0]).to.eql(1);
expect(vertexBuffer[stride * 8 + 1]).to.eql(2);
expect(vertexBuffer[stride * 8 + 2]).to.eql(-3.5);
expect(vertexBuffer[stride * 8 + 3]).to.eql(-3.5);
expect(indexBuffer[6 + 0]).to.eql(4);
expect(indexBuffer[6 + 1]).to.eql(5);
expect(indexBuffer[6 + 2]).to.eql(7);
expect(indexBuffer[6 + 3]).to.eql(5);
expect(indexBuffer[6 + 4]).to.eql(6);
expect(indexBuffer[6 + 5]).to.eql(7);
expect(indexBuffer[6 * 2 + 0]).to.eql(8);
expect(indexBuffer[6 * 2 + 1]).to.eql(9);
expect(indexBuffer[6 * 2 + 2]).to.eql(11);
expect(indexBuffer[6 * 2 + 3]).to.eql(9);
expect(indexBuffer[6 * 2 + 4]).to.eql(10);
expect(indexBuffer[6 * 2 + 5]).to.eql(11);
expect(positions.indexPosition).to.eql(6 * 3);
expect(positions.vertexPosition).to.eql(stride * 4 * 3);
});
});
describe('getBlankTexture', function() {

View File

@@ -1,11 +1,12 @@
import Feature from '../../../../../src/ol/Feature.js';
import Point from '../../../../../src/ol/geom/Point.js';
import LineString from '../../../../../src/ol/geom/LineString.js';
import VectorLayer from '../../../../../src/ol/layer/Vector.js';
import VectorSource from '../../../../../src/ol/source/Vector.js';
import WebGLPointsLayerRenderer from '../../../../../src/ol/renderer/webgl/PointsLayer.js';
import {get as getProjection} from '../../../../../src/ol/proj.js';
import Polygon from '../../../../../src/ol/geom/Polygon.js';
import ViewHint from '../../../../../src/ol/ViewHint.js';
import {POINT_VERTEX_STRIDE, WebGLWorkerMessageType} from '../../../../../src/ol/renderer/webgl/Layer.js';
describe('ol.renderer.webgl.PointsLayer', function() {
@@ -51,46 +52,44 @@ describe('ol.renderer.webgl.PointsLayer', function() {
projection: projection,
resolution: 1,
rotation: 0,
center: [0, 0]
center: [10, 10]
},
size: [2, 2],
size: [256, 256],
extent: [-100, -100, 100, 100]
};
});
it('calls WebGlHelper#prepareDraw', function() {
const spy = sinon.spy(renderer.helper, 'prepareDraw');
const spy = sinon.spy(renderer.helper_, 'prepareDraw');
renderer.prepareFrame(frameState);
expect(spy.called).to.be(true);
});
it('fills up a buffer with 2 triangles per point', function(done) {
it('fills up a buffer with 2 triangles per point', function() {
layer.getSource().addFeature(new Feature({
geometry: new Point([10, 20])
}));
renderer.prepareFrame(frameState);
const attributePerVertex = 12;
expect(renderer.verticesBuffer_.getArray().length).to.eql(4 * attributePerVertex);
expect(renderer.indicesBuffer_.getArray().length).to.eql(6);
});
it('ignores geometries other than points', function() {
layer.getSource().addFeature(new Feature({
geometry: new Point([30, 40])
geometry: new LineString([[10, 20], [30, 20]])
}));
layer.getSource().addFeature(new Feature({
geometry: new Polygon([[10, 20], [30, 20], [30, 10], [10, 20]])
}));
renderer.prepareFrame(frameState);
const attributePerVertex = POINT_VERTEX_STRIDE;
renderer.worker_.addEventListener('message', function(event) {
if (event.data.type !== WebGLWorkerMessageType.GENERATE_BUFFERS) {
return;
}
expect(renderer.verticesBuffer_.getArray().length).to.eql(2 * 4 * attributePerVertex);
expect(renderer.indicesBuffer_.getArray().length).to.eql(2 * 6);
expect(renderer.verticesBuffer_.getArray()[0]).to.eql(10);
expect(renderer.verticesBuffer_.getArray()[1]).to.eql(20);
expect(renderer.verticesBuffer_.getArray()[4 * attributePerVertex + 0]).to.eql(30);
expect(renderer.verticesBuffer_.getArray()[4 * attributePerVertex + 1]).to.eql(40);
done();
});
expect(renderer.verticesBuffer_.getArray().length).to.eql(0);
expect(renderer.indicesBuffer_.getArray().length).to.eql(0);
});
it('clears the buffers when the features are gone', function(done) {
it('clears the buffers when the features are gone', function() {
const source = layer.getSource();
source.addFeature(new Feature({
geometry: new Point([10, 20])
@@ -101,15 +100,9 @@ describe('ol.renderer.webgl.PointsLayer', function() {
}));
renderer.prepareFrame(frameState);
renderer.worker_.addEventListener('message', function(event) {
if (event.data.type !== WebGLWorkerMessageType.GENERATE_BUFFERS) {
return;
}
const attributePerVertex = 12;
expect(renderer.verticesBuffer_.getArray().length).to.eql(4 * attributePerVertex);
expect(renderer.indicesBuffer_.getArray().length).to.eql(6);
done();
});
const attributePerVertex = 12;
expect(renderer.verticesBuffer_.getArray().length).to.eql(4 * attributePerVertex);
expect(renderer.indicesBuffer_.getArray().length).to.eql(6);
});
it('rebuilds the buffers only when not interacting or animating', function() {

View File

@@ -1,76 +1,51 @@
import WebGLArrayBuffer, {getArrayClassForType} from '../../../../src/ol/webgl/Buffer.js';
import {
ARRAY_BUFFER,
ELEMENT_ARRAY_BUFFER,
STATIC_DRAW,
STREAM_DRAW
} from '../../../../src/ol/webgl.js';
import WebGLArrayBuffer from '../../../../src/ol/webgl/Buffer.js';
describe('ol.webgl.Buffer', function() {
describe('constructor', function() {
it('sets the default usage when not specified', function() {
const b = new WebGLArrayBuffer(ARRAY_BUFFER);
expect(b.getUsage()).to.be(STATIC_DRAW);
describe('without an argument', function() {
let b;
beforeEach(function() {
b = new WebGLArrayBuffer();
});
it('constructs an empty instance', function() {
expect(b.getArray()).to.be.empty();
});
});
it('sets the given usage when specified', function() {
const b = new WebGLArrayBuffer(ARRAY_BUFFER, STREAM_DRAW);
expect(b.getUsage()).to.be(STREAM_DRAW);
describe('with a single array argument', function() {
let b;
beforeEach(function() {
b = new WebGLArrayBuffer([0, 1, 2, 3]);
});
it('constructs a populated instance', function() {
expect(b.getArray()).to.eql([0, 1, 2, 3]);
});
});
it('raises an error if an incorrect type is used', function(done) {
try {
new WebGLArrayBuffer(1234);
} catch (e) {
done();
}
done(true);
});
});
describe('#getArrayClassForType', function() {
it('returns the correct typed array constructor', function() {
expect(getArrayClassForType(ARRAY_BUFFER)).to.be(Float32Array);
expect(getArrayClassForType(ELEMENT_ARRAY_BUFFER)).to.be(Uint32Array);
});
});
describe('populate methods', function() {
describe('with an empty instance', function() {
let b;
beforeEach(function() {
b = new WebGLArrayBuffer(ARRAY_BUFFER);
b = new WebGLArrayBuffer();
});
it('initializes the array using a size', function() {
b.ofSize(12);
expect(b.getArray().length).to.be(12);
expect(b.getArray()[0]).to.be(0);
expect(b.getArray()[11]).to.be(0);
});
describe('getArray', function() {
it('initializes the array using an array', function() {
b.fromArray([1, 2, 3, 4, 5]);
expect(b.getArray().length).to.be(5);
expect(b.getArray()[0]).to.be(1);
expect(b.getArray()[1]).to.be(2);
expect(b.getArray()[2]).to.be(3);
expect(b.getArray()[3]).to.be(4);
expect(b.getArray()[4]).to.be(5);
});
it('returns an empty array', function() {
expect(b.getArray()).to.be.empty();
});
it('initializes the array using a size', function() {
const a = Float32Array.of(1, 2, 3, 4, 5);
b.fromArrayBuffer(a.buffer);
expect(b.getArray().length).to.be(5);
expect(b.getArray()[0]).to.be(1);
expect(b.getArray()[1]).to.be(2);
expect(b.getArray()[2]).to.be(3);
expect(b.getArray()[3]).to.be(4);
expect(b.getArray()[4]).to.be(5);
});
});

View File

@@ -213,10 +213,7 @@ describe('ol.webgl.WebGLHelper', function() {
scaleTransform(expected, scaleX, scaleY);
rotateTransform(expected, -frameState.viewState.rotation);
translateTransform(expected, -frameState.viewState.center[0], -frameState.viewState.center[1]);
h.makeProjectionTransform(frameState, given);
expect(given.map(val => val.toFixed(15))).to.eql(expected.map(val => val.toFixed(15)));
expect(h.makeProjectionTransform(frameState, given)).to.eql(expected);
});
});

View File

@@ -1,51 +0,0 @@
import {create} from '../../../../src/ol/worker/webgl.js';
import {
POINT_INSTRUCTIONS_COUNT,
WebGLWorkerMessageType
} from '../../../../src/ol/renderer/webgl/Layer.js';
describe('ol/worker/webgl', function() {
let worker;
beforeEach(function() {
worker = create();
});
afterEach(function() {
if (worker) {
worker.terminate();
}
worker = null;
});
describe('messaging', function() {
describe('GENERATE_BUFFERS', function() {
it('responds with buffer data', function(done) {
worker.addEventListener('error', done);
worker.addEventListener('message', function(event) {
expect(event.data.type).to.eql(WebGLWorkerMessageType.GENERATE_BUFFERS);
expect(event.data.renderInstructions.byteLength).to.greaterThan(0);
expect(event.data.indexBuffer.byteLength).to.greaterThan(0);
expect(event.data.vertexBuffer.byteLength).to.greaterThan(0);
expect(event.data.testInt).to.be(101);
expect(event.data.testString).to.be('abcd');
done();
});
const instructions = new Float32Array(POINT_INSTRUCTIONS_COUNT);
const message = {
type: WebGLWorkerMessageType.GENERATE_BUFFERS,
renderInstructions: instructions,
testInt: 101,
testString: 'abcd'
};
worker.postMessage(message);
});
});
});
});

View File

@@ -1,4 +1,5 @@
import {equals} from '../src/ol/array.js';
import {WEBGL} from '../src/ol/has.js';
// avoid importing anything that results in an instanceof check
// since these extensions are global, instanceof checks fail with modules
@@ -375,6 +376,12 @@ import {equals} from '../src/ol/array.js';
map.dispose();
};
global.assertWebGL = function(map) {
if (!WEBGL) {
expect().fail('No WebGL support!');
}
};
function resembleCanvas(canvas, referenceImage, tolerance, done) {
if (showMap) {
const wrapper = document.createElement('div');
@@ -436,7 +443,21 @@ import {equals} from '../src/ol/array.js';
return;
}
const canvas = event.context.canvas;
let canvas;
if (event.glContext) {
const webglCanvas = event.glContext.getCanvas();
expect(webglCanvas).to.be.a(HTMLCanvasElement);
// draw the WebGL canvas on a new canvas, because we can not create
// a 2d context for that canvas because there is already a webgl context.
canvas = document.createElement('canvas');
canvas.width = webglCanvas.width;
canvas.height = webglCanvas.height;
canvas.getContext('2d').drawImage(webglCanvas, 0, 0,
webglCanvas.width, webglCanvas.height);
} else {
canvas = event.context.canvas;
}
expect(canvas).to.be.a(HTMLCanvasElement);
resembleCanvas(canvas, referenceImage, tolerance, done);