Compare commits

..

61 Commits

Author SHA1 Message Date
ahocevar
a8b5dfa981 6.0.0-beta.15 2019-08-20 11:18:27 +02:00
Andreas Hocevar
42f1a7ed30 Merge pull request #9873 from ahocevar/another-vectortile-load-fix
Only check extent when a url tile coordinate is available
2019-08-20 11:08:04 +02:00
Andreas Hocevar
f3d6456876 Merge pull request #9876 from openlayers/greenkeeper/yargs-14.0.0
Update yargs to the latest version 🚀
2019-08-20 08:36:49 +02:00
greenkeeper[bot]
2ca13de4de chore(package): update lockfile package-lock.json 2019-08-19 23:21:53 +00:00
greenkeeper[bot]
87ae93ca2d chore(package): update yargs to version 14.0.0 2019-08-19 23:21:44 +00:00
ahocevar
5da32dbc5b More tests 2019-08-19 11:39:39 +02:00
ahocevar
6be2818f14 Handle empty url tile coord (no wrapx) 2019-08-19 11:01:03 +02:00
Andreas Hocevar
b602a6b33a Merge pull request #9871 from ahocevar/tile-load-key-change
Properly handle tile source key change
2019-08-19 08:08:31 +02:00
Andreas Hocevar
20a81ceb2f Merge pull request #9870 from ahocevar/declutter-multi-geometries
Declutter multi geometries per geometry instead of per feature
2019-08-19 08:06:39 +02:00
Andreas Hocevar
3d6cf24c26 Merge pull request #9872 from ahocevar/wrapx-extent
Check extent for wrapped tile coordinate
2019-08-18 18:10:24 +02:00
ahocevar
6a741d0504 Check extent for wrapped tile coordinate 2019-08-18 16:21:46 +02:00
ahocevar
aa55cce3ba Add rendering test for decluttered multipolygons 2019-08-18 15:43:41 +02:00
ahocevar
a5fbbef970 Always go through source tile change logic 2019-08-18 11:44:20 +02:00
ahocevar
25c8d93eba Fix test 2019-08-18 11:44:20 +02:00
Tim Schaub
eb294c78d1 Failing test 2019-08-18 08:58:59 +02:00
ahocevar
bd3f35eef0 Declutter multi geometries per geometry instead of per feature 2019-08-17 23:55:20 +02:00
Tim Schaub
f839b34594 Merge pull request #9869 from MoonE/master
Only get squared tolerance once per render
2019-08-17 07:23:22 -06:00
Tim Schaub
99462d3b53 Only get squared tolerance once per render 2019-08-17 07:10:10 -06:00
Maximilian Krög
200392785d Squared tolerance does not change for each style. 2019-08-17 11:15:06 +02:00
Tim Schaub
c0e5c4b7fe 6.0.0-beta.14 2019-08-16 07:03:28 -06:00
ahocevar
189ad24528 Adjust expected image for CircleCI 2019-08-16 13:22:18 +02:00
ahocevar
4aa11ecc94 Remove lint 2019-08-16 13:05:46 +02:00
Andreas Hocevar
e61c5c07bc Merge pull request #9389 from KaiVolland/tile-rendering
Replaces listener test in tile.tests.js and removes artifacts
2019-08-16 13:02:48 +02:00
Tim Schaub
0212ce6554 Merge pull request #9855 from tschaub/vector-tile-loading
Make sure vector tile load handler is called
2019-08-16 04:05:11 -06:00
Tim Schaub
b76a0379dd Merge pull request #9864 from tschaub/opacity
Properly update frameState.animate and deal with non-numeric layer opacity
2019-08-15 15:09:14 -06:00
Tim Schaub
e94c7b6c39 Only set frameState.animate true if in transition and alpha < 1 2019-08-15 12:55:27 -06:00
Tim Schaub
2c69ad2bb4 Throw on non-numeric opacity values 2019-08-15 12:55:13 -06:00
Tim Schaub
e8e7c46463 Merge pull request #9858 from tschaub/audit-fix
Run npm audit fix
2019-08-13 16:42:43 -06:00
Tim Schaub
abda7f4f1d Separate lookups for source tiles by tile coord and tile key 2019-08-13 16:40:01 -06:00
Tim Schaub
e8500c395c Run npm audit fix 2019-08-13 16:28:18 -06:00
Tim Schaub
6f5a066bab Merge pull request #9856 from openlayers/greenkeeper/webpack-4.39.2
Update webpack to the latest version 🚀
2019-08-13 16:26:50 -06:00
Tim Schaub
08816ec9f9 Merge pull request #9857 from openlayers/greenkeeper/karma-chrome-launcher-3.1.0
Update karma-chrome-launcher to the latest version 🚀
2019-08-13 16:26:16 -06:00
greenkeeper[bot]
fac659fa0a chore(package): update lockfile package-lock.json 2019-08-13 19:40:27 +00:00
greenkeeper[bot]
b0069c3c5d chore(package): update karma-chrome-launcher to version 3.1.0 2019-08-13 19:40:15 +00:00
greenkeeper[bot]
e7be28d2b5 chore(package): update lockfile package-lock.json 2019-08-13 18:10:17 +00:00
greenkeeper[bot]
15aa5ebc1f chore(package): update webpack to version 4.39.2 2019-08-13 18:10:00 +00:00
Tim Schaub
a9ad24cce2 6.0.0-beta.13 2019-08-12 21:22:15 -06:00
Andreas Hocevar
486eb205cb Merge pull request #9844 from ahocevar/empty-vectorrendertile
Set initial tile state to EMPTY when outside source extent
2019-08-11 21:50:50 +02:00
ahocevar
28e64f646f Set initial tile state to EMPTY when outside source extent 2019-08-11 00:13:18 +02:00
Andreas Hocevar
78cf32ae70 Merge pull request #9839 from mike-000/patch-1
Enable correct display of side-by-side example when not using the examples template
2019-08-09 00:40:38 +02:00
mike-000
a340da8f6e Update side-by-side.css 2019-08-08 22:48:08 +01:00
mike-000
336056f4f0 Update side-by-side.html 2019-08-08 22:40:37 +01:00
Andreas Hocevar
e31e4b7867 Merge pull request #9838 from ahocevar/wms-servertype
Make WMSServerType appear in API docs
2019-08-08 21:36:52 +02:00
ahocevar
683c0ef5dc Make WMSServerType appear in API docs 2019-08-08 21:29:29 +02:00
Andreas Hocevar
23179e9ac5 Merge pull request #9754 from mike-000/patch-1
Export PDF example extent corrections
2019-08-08 21:07:49 +02:00
mike-000
7cdfc33d15 Export PDF example extent corrections
Fixes #9460 and #9665

Replace calculateExtent and fit with getResolution and setResolution as the former do not produce the desired result when the view is rotated.

Export the viewport instead of the map div (which doesn't resize) and specify the width and height in the export options

This is a minimal fix for the two issues.  Further enhancement including a fallback to export layer canvases where the browser doesn't support html-to-image could be done separately if necessary.
2019-08-08 19:41:51 +02:00
Andreas Hocevar
776dab81b8 Merge pull request #9834 from ahocevar/nextzen
Use nextzen for osm-vector-tiles example
2019-08-08 18:38:56 +02:00
ahocevar
182f1448a9 Use nextzen for osm-vector-tiles example 2019-08-08 12:57:55 +02:00
Andreas Hocevar
9b6fcf8d7b Merge pull request #9833 from ahocevar/remove-package-lock
Remove accidentally added package-lock.json
2019-08-08 12:52:33 +02:00
ahocevar
bd1c8db7a3 Remove accidentally added package-lock.json 2019-08-08 12:35:24 +02:00
Tim Schaub
0fb638fcb6 Merge pull request #9817 from openlayers/greenkeeper/webpack-4.39.1
Update webpack to the latest version 🚀
2019-08-07 06:38:10 -06:00
Tim Schaub
effb95b322 Merge pull request #9827 from openlayers/greenkeeper/coveralls-3.0.6
Update coveralls to the latest version 🚀
2019-08-07 06:37:12 -06:00
Tim Schaub
e5ac326f1c Merge pull request #9826 from tschaub/publish-options
Accept additional args when publishing
2019-08-07 06:33:14 -06:00
greenkeeper[bot]
2d0d06842d chore(package): update lockfile package-lock.json 2019-08-07 07:41:55 +00:00
greenkeeper[bot]
7355906c3a chore(package): update coveralls to version 3.0.6 2019-08-07 07:41:48 +00:00
Andreas Hocevar
ec10cda088 Merge pull request #9812 from ahocevar/zdirection
Make zDirection configurable on tile source
2019-08-07 08:56:23 +02:00
Tim Schaub
d59eed5d3b Accept additional args when publishing 2019-08-07 00:01:57 -04:00
greenkeeper[bot]
d4980754ad chore(package): update webpack to version 4.39.1 2019-08-02 12:51:21 +00:00
ahocevar
e07ff9c04e Make zDirection configurable on tile source 2019-07-30 16:50:01 +02:00
Kai Volland
94edf32540 Removes artifacts of old rendering test approach
Data and comparison images of the old rendering test approach
are removed as every test is transformed to the new approach.
2019-04-01 15:56:03 +02:00
Kai Volland
91d2f98774 Replaces listener test in tile.tests.js
Transforms the old render listener test to
the new rendering test approach.
2019-04-01 15:53:19 +02:00
100 changed files with 1052 additions and 571 deletions

View File

@@ -236,3 +236,7 @@ A `WebGLArrayBuffer` must either be of type `ELEMENT_ARRAY_BUFFER` or `ARRAY_BUF
### 63
Support for the `OES_element_index_uint` WebGL extension is mandatory for WebGL layers.
### 64
Layer opacity must be a number.

View File

@@ -65,18 +65,18 @@ exportButton.addEventListener('click', function() {
const width = Math.round(dim[0] * resolution / 25.4);
const height = Math.round(dim[1] * resolution / 25.4);
const size = map.getSize();
const extent = map.getView().calculateExtent(size);
const viewResolution = map.getView().getResolution();
map.once('rendercomplete', function() {
toJpeg(map.getTargetElement(), exportOptions).then(function(dataUrl) {
exportOptions.width = width;
exportOptions.height = height;
toJpeg(map.getViewport(), exportOptions).then(function(dataUrl) {
const pdf = new jsPDF('landscape', undefined, format);
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
pdf.save('map.pdf');
// Reset original map size
map.setSize(size);
map.getView().fit(extent, {
size: size
});
map.getView().setResolution(viewResolution);
exportButton.disabled = false;
document.body.style.cursor = 'auto';
});
@@ -85,6 +85,7 @@ exportButton.addEventListener('click', function() {
// Set print size
const printSize = [width, height];
map.setSize(printSize);
map.getView().fit(extent, {size: printSize});
const scaling = Math.min(width / size[0], height / size[1]);
map.getView().setResolution(viewResolution / scaling);
}, false);

View File

@@ -6,7 +6,7 @@ docs: >
A simple vector tiles map with Mapzen vector tiles. This example uses the TopoJSON format's `layerName` option to determine the layer ("water", "roads", "buildings") for styling. **Note**: [`ol/format/MVT`] is an even more efficient format for vector tiles.
tags: "vector, tiles, osm, mapzen"
cloak:
- key: vector-tiles-5eJz6JX
value: Your Mapzen API key from https://mapzen.com/developers
- key: uZNs91nMR-muUTP99MyBSg
value: Your Nextzen API key from https://developers.nextzen.org/
---
<div id="map" class="map"></div>

View File

@@ -6,7 +6,7 @@ import {fromLonLat} from '../src/ol/proj.js';
import VectorTileSource from '../src/ol/source/VectorTile.js';
import {Fill, Stroke, Style} from '../src/ol/style.js';
const key = 'vector-tiles-5eJz6JX';
const key = 'uZNs91nMR-muUTP99MyBSg';
const roadStyleCache = {};
const roadColor = {
@@ -67,7 +67,7 @@ const map = new Map({
layers: ['water', 'roads', 'buildings']
}),
maxZoom: 19,
url: 'https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.topojson?api_key=' + key
url: 'https://tile.nextzen.org/tilezen/vector/v1/all/{z}/{x}/{y}.topojson?api_key=' + key
}),
style: function(feature, resolution) {
switch (feature.get('layer')) {

View File

@@ -1,4 +1,7 @@
@media (min-width: 800px) {
.wrapper {
display: flex;
}
.half {
padding: 0 10px;
width: 50%;

View File

@@ -9,11 +9,13 @@ cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
---
<div class="half">
<h4>Road</h4>
<div id="roadMap" class="map"></div>
</div>
<div class="half">
<h4>Aerial</h4>
<div id="aerialMap" class="map"></div>
<div class="wrapper">
<div class="half">
<h4>Road</h4>
<div id="roadMap" class="map"></div>
</div>
<div class="half">
<h4>Aerial</h4>
<div id="aerialMap" class="map"></div>
</div>
</div>

View File

@@ -5,7 +5,7 @@ shortdesc: Label decluttering with a custom renderer.
resources:
- https://cdn.polyfill.io/v2/polyfill.min.js?features=Set"
docs: >
Decluttering is used to avoid overlapping labels with `overflow: true` set on the text style. For MultiPolygon geometries, only the widest polygon is selected in a custom `geometry` function.
Decluttering is used to avoid overlapping labels. The `overflow: true` setting on the text style makes it so labels that do not fit within the bounds of a polygon are also included.
tags: "vector, decluttering, labels"
---
<div id="map" class="map"></div>

View File

@@ -1,6 +1,5 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {getWidth} from '../src/ol/extent.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
@@ -15,23 +14,6 @@ const map = new Map({
});
const labelStyle = new Style({
geometry: function(feature) {
let geometry = feature.getGeometry();
if (geometry.getType() == 'MultiPolygon') {
// Only render label for the widest polygon of a multipolygon
const polygons = geometry.getPolygons();
let widest = 0;
for (let i = 0, ii = polygons.length; i < ii; ++i) {
const polygon = polygons[i];
const width = getWidth(polygon.getExtent());
if (width > widest) {
widest = width;
geometry = polygon;
}
}
}
return geometry;
},
text: new Text({
font: '12px Calibri,sans-serif',
overflow: true,

672
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.0-beta.12",
"version": "6.0.0-beta.15",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -54,7 +54,7 @@
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.3",
"coveralls": "3.0.5",
"coveralls": "3.0.6",
"eslint": "^6.0.0",
"eslint-config-openlayers": "^12.0.0",
"expect.js": "0.3.1",
@@ -70,7 +70,7 @@
"jsdoc": "3.6.3",
"jsdoc-plugin-typescript": "^2.0.1",
"karma": "^4.1.0",
"karma-chrome-launcher": "3.0.0",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "^1.1.2",
"karma-coverage-istanbul-reporter": "^2.0.5",
"karma-firefox-launcher": "^1.1.0",
@@ -97,11 +97,11 @@
"typescript": "^3.4.5",
"url-polyfill": "^1.1.5",
"walk": "^2.3.9",
"webpack": "4.39.0",
"webpack": "4.39.2",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",
"yargs": "^13.2.2"
"yargs": "^14.0.0"
},
"eslintConfig": {
"extends": "openlayers",

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -0,0 +1,46 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js';
import {transform, fromLonLat} from '../../../src/ol/proj.js';
import XYZ from '../../../src/ol/source/XYZ.js';
import CircleStyle from '../../../src/ol/style/Circle.js';
import Fill from '../../../src/ol/style/Fill.js';
import Stroke from '../../../src/ol/style/Stroke.js';
import Point from '../../../src/ol/geom/Point.js';
import {getVectorContext} from '../../../src/ol/render.js';
const center = fromLonLat([8.6, 50.1]);
const layer = new TileLayer({
source: new XYZ({
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
transition: 0
})
});
const onRender = function(event) {
const context = event.context;
context.restore();
const vectorContext = getVectorContext(event);
vectorContext.setImageStyle(new CircleStyle({
radius: 12,
fill: new Fill({color: 'yellow'}),
stroke: new Stroke({color: 'red', width: 1})
}));
vectorContext.drawPoint(new Point(
transform([13, 37], 'EPSG:4326', 'EPSG:3857')));
};
layer.on('postrender', onRender);
const map = new Map({
layers: [
],
target: 'map',
view: new View({
center: center,
zoom: 3
})
});
map.addLayer(layer);
render();

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,55 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
import VectorLayer from '../../../src/ol/layer/Vector.js';
import VectorSource from '../../../src/ol/source/Vector.js';
import {Fill, Stroke, Style, Text} from '../../../src/ol/style.js';
const map = new Map({
target: 'map',
view: new View({
center: [-17465028, 2331736],
zoom: 5
})
});
const labelStyle = new Style({
text: new Text({
font: '16px Ubuntu',
overflow: true,
fill: new Fill({
color: '#000'
}),
stroke: new Stroke({
color: '#fff',
width: 3
})
})
});
const countryStyle = new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.6)'
}),
stroke: new Stroke({
color: '#319FD3',
width: 1
})
});
const style = [countryStyle, labelStyle];
const vectorLayer = new VectorLayer({
source: new VectorSource({
url: '/data/countries.json',
format: new GeoJSON()
}),
style: function(feature) {
labelStyle.getText().setText(feature.get('name'));
return style;
},
declutter: true
});
map.addLayer(vectorLayer);
render({tolerance: 0.007});

View File

@@ -6,6 +6,7 @@ import BaseObject from '../Object.js';
import LayerProperty from './Property.js';
import {clamp} from '../math.js';
import {assign} from '../obj.js';
import {assert} from '../asserts.js';
/**
@@ -52,8 +53,11 @@ class BaseLayer extends BaseObject {
* @type {Object<string, *>}
*/
const properties = assign({}, options);
properties[LayerProperty.OPACITY] =
options.opacity !== undefined ? options.opacity : 1;
options.opacity !== undefined ? options.opacity : 1;
assert(typeof properties[LayerProperty.OPACITY] === 'number', 64); // Layer opacity must be a number
properties[LayerProperty.VISIBLE] =
options.visible !== undefined ? options.visible : true;
properties[LayerProperty.Z_INDEX] = options.zIndex;
@@ -292,6 +296,7 @@ class BaseLayer extends BaseObject {
* @api
*/
setOpacity(opacity) {
assert(typeof opacity === 'number', 64); // Layer opacity must be a number
this.set(LayerProperty.OPACITY, opacity);
}

View File

@@ -106,9 +106,9 @@ class VectorContext {
/**
* @param {import("../style/Text.js").default} textStyle Text style.
* @param {import("./canvas.js").DeclutterGroup=} opt_declutterGroup Declutter.
* @param {import("./canvas.js").DeclutterGroups=} opt_declutterGroups Declutter.
*/
setTextStyle(textStyle, opt_declutterGroup) {}
setTextStyle(textStyle, opt_declutterGroups) {}
}
export default VectorContext;

View File

@@ -62,7 +62,6 @@ import LabelCache from './canvas/LabelCache.js';
* @property {Array<number>} [padding]
*/
/**
* Container for decluttered replay instructions that need to be rendered or
* omitted together, i.e. when styles render both an image and text, or for the
@@ -76,6 +75,12 @@ import LabelCache from './canvas/LabelCache.js';
*/
/**
* Declutter groups for support of multi geometries.
* @typedef {Array<DeclutterGroup>} DeclutterGroups
*/
/**
* @const
* @type {string}

View File

@@ -40,10 +40,10 @@ class BuilderGroup {
this.declutter_ = declutter;
/**
* @type {import("../canvas.js").DeclutterGroup}
* @type {import("../canvas.js").DeclutterGroups}
* @private
*/
this.declutterGroup_ = null;
this.declutterGroups_ = null;
/**
* @private
@@ -78,17 +78,17 @@ class BuilderGroup {
/**
* @param {boolean} group Group with previous builder.
* @return {Array<*>} The resulting instruction group.
* @return {import("../canvas").DeclutterGroups} The resulting instruction groups.
*/
addDeclutter(group) {
let declutter = null;
if (this.declutter_) {
if (group) {
declutter = this.declutterGroup_;
/** @type {number} */ (declutter[4])++;
declutter = this.declutterGroups_;
/** @type {number} */ (declutter[0][4])++;
} else {
declutter = this.declutterGroup_ = createEmpty();
declutter.push(1);
declutter = this.declutterGroups_ = [createEmpty()];
declutter[0].push(1);
}
}
return declutter;

View File

@@ -535,7 +535,7 @@ class Executor extends Disposable {
const ii = instructions.length; // end of instructions
let d = 0; // data index
let dd; // end of per-instruction data
let anchorX, anchorY, prevX, prevY, roundX, roundY, declutterGroup, image, text, textKey;
let anchorX, anchorY, prevX, prevY, roundX, roundY, declutterGroup, declutterGroups, image, text, textKey;
let strokeKey, fillKey;
let pendingFill = 0;
let pendingStroke = 0;
@@ -633,7 +633,7 @@ class Executor extends Disposable {
// Remaining arguments in DRAW_IMAGE are in alphabetical order
anchorX = /** @type {number} */ (instruction[4]);
anchorY = /** @type {number} */ (instruction[5]);
declutterGroup = featureCallback ? null : /** @type {import("../canvas.js").DeclutterGroup} */ (instruction[6]);
declutterGroups = featureCallback ? null : instruction[6];
let height = /** @type {number} */ (instruction[7]);
const opacity = /** @type {number} */ (instruction[8]);
const originX = /** @type {number} */ (instruction[9]);
@@ -643,7 +643,6 @@ class Executor extends Disposable {
const scale = /** @type {number} */ (instruction[13]);
let width = /** @type {number} */ (instruction[14]);
if (!image && instruction.length >= 19) {
// create label images
text = /** @type {string} */ (instruction[18]);
@@ -679,25 +678,41 @@ class Executor extends Disposable {
rotation += viewRotation;
}
let widthIndex = 0;
let declutterGroupIndex = 0;
for (; d < dd; d += 2) {
if (geometryWidths && geometryWidths[widthIndex++] < width / this.pixelRatio) {
continue;
}
if (declutterGroups) {
const index = Math.floor(declutterGroupIndex);
if (declutterGroups.length < index + 1) {
declutterGroup = createEmpty();
declutterGroup.push(declutterGroups[0][4]);
declutterGroups.push(declutterGroup);
}
declutterGroup = declutterGroups[index];
}
this.replayImage_(context,
pixelCoordinates[d], pixelCoordinates[d + 1], image, anchorX, anchorY,
declutterGroup, height, opacity, originX, originY, rotation, scale,
snapToPixel, width, padding,
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
if (declutterGroup) {
if (declutterGroupIndex === Math.floor(declutterGroupIndex)) {
this.declutterItems.push(this, declutterGroup, feature);
}
declutterGroupIndex += 1 / declutterGroup[4];
}
}
this.declutterItems.push(this, declutterGroup, feature);
++i;
break;
case CanvasInstruction.DRAW_CHARS:
const begin = /** @type {number} */ (instruction[1]);
const end = /** @type {number} */ (instruction[2]);
const baseline = /** @type {number} */ (instruction[3]);
declutterGroup = featureCallback ? null : /** @type {import("../canvas.js").DeclutterGroup} */ (instruction[4]);
declutterGroup = featureCallback ? null : instruction[4];
const overflow = /** @type {number} */ (instruction[5]);
fillKey = /** @type {string} */ (instruction[6]);
const maxAngle = /** @type {number} */ (instruction[7]);

View File

@@ -16,9 +16,9 @@ class CanvasImageBuilder extends CanvasBuilder {
/**
* @private
* @type {import("../canvas.js").DeclutterGroup}
* @type {import("../canvas.js").DeclutterGroups}
*/
this.declutterGroup_ = null;
this.declutterGroups_ = null;
/**
* @private
@@ -121,14 +121,14 @@ class CanvasImageBuilder extends CanvasBuilder {
this.instructions.push([
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_ * this.pixelRatio, this.width_
]);
this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_, this.width_
]);
@@ -151,14 +151,14 @@ class CanvasImageBuilder extends CanvasBuilder {
this.instructions.push([
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_ * this.pixelRatio, this.width_
]);
this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_,
// Remaining arguments to DRAW_IMAGE are in alphabetical order
this.anchorX_, this.anchorY_, this.declutterGroup_, this.height_, this.opacity_,
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
this.scale_, this.width_
]);
@@ -189,7 +189,7 @@ class CanvasImageBuilder extends CanvasBuilder {
/**
* @inheritDoc
*/
setImageStyle(imageStyle, declutterGroup) {
setImageStyle(imageStyle, declutterGroups) {
const anchor = imageStyle.getAnchor();
const size = imageStyle.getSize();
const hitDetectionImage = imageStyle.getHitDetectionImage(1);
@@ -197,7 +197,7 @@ class CanvasImageBuilder extends CanvasBuilder {
const origin = imageStyle.getOrigin();
this.anchorX_ = anchor[0];
this.anchorY_ = anchor[1];
this.declutterGroup_ = /** @type {import("../canvas.js").DeclutterGroup} */ (declutterGroup);
this.declutterGroups_ = /** @type {import("../canvas.js").DeclutterGroups} */ (declutterGroups);
this.hitDetectionImage_ = hitDetectionImage;
this.image_ = image;
this.height_ = size[1];

View File

@@ -40,9 +40,9 @@ class CanvasTextBuilder extends CanvasBuilder {
/**
* @private
* @type {import("../canvas.js").DeclutterGroup}
* @type {import("../canvas.js").DeclutterGroups}
*/
this.declutterGroup_;
this.declutterGroups_;
/**
* @private
@@ -201,7 +201,10 @@ class CanvasTextBuilder extends CanvasBuilder {
}
end = this.coordinates.length;
flatOffset = ends[o];
this.drawChars_(begin, end, this.declutterGroup_);
const declutterGroup = this.declutterGroups_ ?
(o === 0 ? this.declutterGroups_[0] : [].concat(this.declutterGroups_[0])) :
null;
this.drawChars_(begin, end, declutterGroup);
begin = end;
}
this.endGeometry(feature);
@@ -274,7 +277,7 @@ class CanvasTextBuilder extends CanvasBuilder {
// render time.
const pixelRatio = this.pixelRatio;
this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
null, NaN, NaN, this.declutterGroup_, NaN, 1, 0, 0,
null, NaN, NaN, this.declutterGroups_, NaN, 1, 0, 0,
this.textRotateWithView_, this.textRotation_, 1, NaN,
textState.padding == defaultPadding ?
defaultPadding : textState.padding.map(function(p) {
@@ -285,7 +288,7 @@ class CanvasTextBuilder extends CanvasBuilder {
this.textOffsetX_, this.textOffsetY_, geometryWidths
]);
this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
null, NaN, NaN, this.declutterGroup_, NaN, 1, 0, 0,
null, NaN, NaN, this.declutterGroups_, NaN, 1, 0, 0,
this.textRotateWithView_, this.textRotation_, 1 / this.pixelRatio, NaN,
textState.padding,
!!textState.backgroundFill, !!textState.backgroundStroke,
@@ -379,12 +382,12 @@ class CanvasTextBuilder extends CanvasBuilder {
/**
* @inheritDoc
*/
setTextStyle(textStyle, declutterGroup) {
setTextStyle(textStyle, declutterGroups) {
let textState, fillState, strokeState;
if (!textStyle) {
this.text_ = '';
} else {
this.declutterGroup_ = /** @type {import("../canvas.js").DeclutterGroup} */ (declutterGroup);
this.declutterGroups_ = /** @type {import("../canvas.js").DeclutterGroups} */ (declutterGroups);
const textFillStyle = textStyle.getFill();
if (!textFillStyle) {

View File

@@ -63,12 +63,6 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
* @type {import("../../TileRange.js").default}
*/
this.tmpTileRange_ = new TileRange(0, 0, 0, 0);
/**
* @protected
* @type {number}
*/
this.zDirection = 0;
}
/**
@@ -151,8 +145,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
const tileSource = tileLayer.getSource();
const sourceRevision = tileSource.getRevision();
const tileGrid = tileSource.getTileGridForProjection(projection);
const zDirection = tileSource.zDirection === undefined ? this.zDirection : tileSource.zDirection;
const z = tileGrid.getZForResolution(viewResolution, zDirection);
const z = tileGrid.getZForResolution(viewResolution, tileSource.zDirection);
const tileResolution = tileGrid.getResolution(z);
let extent = frameState.extent;
@@ -384,7 +377,8 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
return;
}
const uid = getUid(this);
const alpha = opacity * (transition ? tile.getAlpha(uid, frameState.time) : 1);
const tileAlpha = transition ? tile.getAlpha(uid, frameState.time) : 1;
const alpha = opacity * tileAlpha;
const alphaChanged = alpha !== this.context.globalAlpha;
if (alphaChanged) {
this.context.save();
@@ -396,7 +390,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
if (alphaChanged) {
this.context.restore();
}
if (alpha !== 1) {
if (tileAlpha !== 1) {
frameState.animate = true;
} else if (transition) {
tile.endTransition(uid);

View File

@@ -299,6 +299,8 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
vectorSource.loadFeatures(extent, resolution, projection);
const squaredTolerance = getSquaredRenderTolerance(resolution, pixelRatio);
/**
* @param {import("../../Feature.js").default} feature Feature.
* @this {CanvasVectorLayerRenderer}
@@ -310,11 +312,11 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
styles = styleFunction(feature, resolution);
}
if (styles) {
const dirty = this.renderFeature(
feature, resolution, pixelRatio, styles, replayGroup);
const dirty = this.renderFeature(feature, squaredTolerance, styles, replayGroup);
this.dirty_ = this.dirty_ || dirty;
}
}.bind(this);
if (vectorLayerRenderOrder) {
/** @type {Array<import("../../Feature.js").default>} */
const features = [];
@@ -350,13 +352,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
/**
* @param {import("../../Feature.js").default} feature Feature.
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {number} squaredTolerance Squared render tolerance.
* @param {import("../../style/Style.js").default|Array<import("../../style/Style.js").default>} styles The style or array of styles.
* @param {import("../../render/canvas/BuilderGroup.js").default} builderGroup Builder group.
* @return {boolean} `true` if an image is loading.
*/
renderFeature(feature, resolution, pixelRatio, styles, builderGroup) {
renderFeature(feature, squaredTolerance, styles, builderGroup) {
if (!styles) {
return false;
}
@@ -364,14 +365,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
if (Array.isArray(styles)) {
for (let i = 0, ii = styles.length; i < ii; ++i) {
loading = renderFeature(
builderGroup, feature, styles[i],
getSquaredRenderTolerance(resolution, pixelRatio),
builderGroup, feature, styles[i], squaredTolerance,
this.handleStyleImageChange_, this) || loading;
}
} else {
loading = renderFeature(
builderGroup, feature, styles,
getSquaredRenderTolerance(resolution, pixelRatio),
builderGroup, feature, styles, squaredTolerance,
this.handleStyleImageChange_, this);
}
return loading;

View File

@@ -113,8 +113,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
*/
this.tmpTransform_ = createTransform();
// Use nearest lower resolution.
this.zDirection = 1;
}
/**

View File

@@ -269,7 +269,8 @@ class BingMaps extends TileImage {
const attributions = [];
const viewState = frameState.viewState;
const tileGrid = this.getTileGrid();
const tileCoord = tileGrid.getTileCoordForCoordAndResolution(viewState.center, viewState.resolution);
const z = tileGrid.getZForResolution(viewState.resolution, this.zDirection);
const tileCoord = tileGrid.getTileCoordForCoordAndZ(viewState.center, z);
const zoom = tileCoord[0];
resource.imageryProviders.map(function(imageryProvider) {
let intersecting = false;

View File

@@ -40,8 +40,8 @@ import TileImage from './TileImage.js';
* @property {string} [url] Base URL of the IIIF Image service.
* 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.
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
*/

View File

@@ -24,6 +24,7 @@ import {wrapX, getForProjection as getTileGridForProjection} from '../tilegrid.j
* @property {boolean} [wrapX=true]
* @property {number} [transition]
* @property {string} [key]
* @property {number} [zDirection=0]
*/
@@ -110,9 +111,9 @@ class TileSource extends Source {
* by a renderer if the views resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @type {number=}
* @type {number}
*/
this.zDirection;
this.zDirection = options.zDirection ? options.zDirection : 0;
}
/**

View File

@@ -80,6 +80,11 @@ class LabeledTile extends Tile {
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Optional projection.
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number} [zDirection=0] Set to `1` when debugging `VectorTile` sources with
* a default configuration. Indicates which resolution should be used by a renderer if
* the view resolution does not match any resolution of the tile source. If 0, the nearest
* resolution will be used. If 1, the nearest lower resolution will be used. If -1, the
* nearest higher resolution will be used.
*/
@@ -106,7 +111,8 @@ class TileDebug extends XYZ {
opaque: false,
projection: options.projection,
tileGrid: options.tileGrid,
wrapX: options.wrapX !== undefined ? options.wrapX : true
wrapX: options.wrapX !== undefined ? options.wrapX : true,
zDirection: options.zDirection
});
}

View File

@@ -52,6 +52,10 @@ import {getForProjection as getTileGridForProjection} from '../tilegrid.js';
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {string} [key] Optional tile key for proper cache fetching
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
*/
@@ -84,7 +88,8 @@ class TileImage extends UrlTile {
wrapX: options.wrapX,
transition: options.transition,
key: options.key,
attributionsCollapsible: options.attributionsCollapsible
attributionsCollapsible: options.attributionsCollapsible,
zDirection: options.zDirection
});
/**

View File

@@ -168,7 +168,8 @@ class TileWMS extends TileImage {
tileGrid = this.getTileGridForProjection(projectionObj);
}
const tileCoord = tileGrid.getTileCoordForCoordAndResolution(coordinate, resolution);
const z = tileGrid.getZForResolution(resolution, this.zDirection);
const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z);
if (tileGrid.getResolutions().length <= tileCoord[0]) {
return undefined;

View File

@@ -385,8 +385,8 @@ class UTFGrid extends TileSource {
forDataAtCoordinateAndResolution(
coordinate, resolution, callback, opt_request) {
if (this.tileGrid) {
const tileCoord = this.tileGrid.getTileCoordForCoordAndResolution(
coordinate, resolution);
const z = this.tileGrid.getZForResolution(resolution, this.zDirection);
const tileCoord = this.tileGrid.getTileCoordForCoordAndZ(coordinate, z);
const tile = /** @type {!CustomTile} */(this.getTile(
tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection()));
tile.forDataAtCoordinate(coordinate, callback, opt_request);

View File

@@ -25,6 +25,7 @@ import {getKeyZXY} from '../tilecoord.js';
* @property {boolean} [wrapX=true]
* @property {number} [transition]
* @property {string} [key]
* @property {number} [zDirection=0]
*/
@@ -51,7 +52,8 @@ class UrlTile extends TileSource {
wrapX: options.wrapX,
transition: options.transition,
key: options.key,
attributionsCollapsible: options.attributionsCollapsible
attributionsCollapsible: options.attributionsCollapsible,
zDirection: options.zDirection
});
/**

View File

@@ -9,7 +9,7 @@ import {toSize} from '../size.js';
import UrlTile from './UrlTile.js';
import {getKeyZXY, getKey} from '../tilecoord.js';
import {createXYZ, extentFromProjection, createForProjection} from '../tilegrid.js';
import {buffer as bufferExtent, getIntersection} from '../extent.js';
import {buffer as bufferExtent, getIntersection, intersects} from '../extent.js';
import {listen, unlistenByKey} from '../events.js';
import EventType from '../events/EventType.js';
import {loadFeaturesXhr} from '../featureloader.js';
@@ -64,6 +64,10 @@ import {equals} from '../array.js';
* When set to `false`, only one world
* will be rendered. When set to `true`, tiles will be wrapped horizontally to
* render multiple worlds.
* @property {number} [zDirection=1] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
*/
@@ -109,7 +113,8 @@ class VectorTile extends UrlTile {
url: options.url,
urls: options.urls,
wrapX: options.wrapX === undefined ? true : options.wrapX,
transition: options.transition
transition: options.transition,
zDirection: options.zDirection === undefined ? 1 : options.zDirection
});
/**
@@ -127,7 +132,7 @@ class VectorTile extends UrlTile {
* @private
* @type {Object<string, import("../VectorTile.js").default>}
*/
this.sourceTiles_ = {};
this.sourceTileByCoordKey_ = {};
/**
* @private
@@ -168,7 +173,7 @@ class VectorTile extends UrlTile {
*/
clear() {
this.tileCache.clear();
this.sourceTiles_ = {};
this.sourceTileByCoordKey_ = {};
this.sourceTilesByTileKey_ = {};
}
@@ -194,75 +199,79 @@ class VectorTile extends UrlTile {
const sourceZ = sourceTileGrid.getZForResolution(resolution, 1);
const minZoom = sourceTileGrid.getMinZoom();
const previousSourceTiles = this.sourceTilesByTileKey_[getKey(tile.tileCoord)];
const previousSourceTiles = this.sourceTilesByTileKey_[tile.getKey()];
let sourceTiles, covered, empty, loadedZ;
if (previousSourceTiles && previousSourceTiles.length > 0 && previousSourceTiles[0].tileCoord[0] === sourceZ) {
return previousSourceTiles;
}
const sourceTiles = [];
let loadedZ = sourceZ + 1;
let covered, empty;
do {
--loadedZ;
sourceTiles = previousSourceTiles;
covered = true;
empty = true;
sourceTileGrid.forEachTileCoord(extent, loadedZ, function(sourceTileCoord) {
const tileKey = getKey(sourceTileCoord);
let sourceTile;
if (tileKey in this.sourceTiles_) {
sourceTile = this.sourceTiles_[tileKey];
const state = sourceTile.getState();
if (state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) {
empty = empty && state === TileState.EMPTY;
sourceTiles.push(sourceTile);
empty = false;
loadedZ = sourceZ;
} else {
sourceTiles = [];
loadedZ = sourceZ + 1;
do {
--loadedZ;
covered = true;
empty = true;
sourceTileGrid.forEachTileCoord(extent, loadedZ, function(sourceTileCoord) {
const coordKey = getKey(sourceTileCoord);
let sourceTile;
if (coordKey in this.sourceTileByCoordKey_) {
sourceTile = this.sourceTileByCoordKey_[coordKey];
const state = sourceTile.getState();
if (state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) {
empty = empty && state === TileState.EMPTY;
sourceTiles.push(sourceTile);
return;
}
} else if (loadedZ === sourceZ) {
const tileUrl = this.tileUrlFunction(sourceTileCoord, pixelRatio, projection);
if (tileUrl !== undefined) {
sourceTile = new this.tileClass(sourceTileCoord, TileState.IDLE, tileUrl,
this.format_, this.tileLoadFunction);
sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
sourceTile.projection = projection;
sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
this.sourceTileByCoordKey_[coordKey] = sourceTile;
empty = false;
listen(sourceTile, EventType.CHANGE, this.handleTileChange, this);
sourceTile.load();
}
} else {
empty = false;
}
covered = false;
if (!sourceTile) {
return;
}
} else if (loadedZ === sourceZ) {
const tileUrl = this.tileUrlFunction(sourceTileCoord, pixelRatio, projection);
if (tileUrl !== undefined) {
sourceTile = new this.tileClass(sourceTileCoord, TileState.IDLE, tileUrl,
this.format_, this.tileLoadFunction);
sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
sourceTile.projection = projection;
sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
this.sourceTiles_[tileKey] = sourceTile;
empty = false;
listen(sourceTile, EventType.CHANGE, this.handleTileChange, this);
sourceTile.load();
if (sourceTile.getState() !== TileState.EMPTY && tile.getState() === TileState.IDLE) {
tile.loadingSourceTiles++;
const key = listen(sourceTile, EventType.CHANGE, function() {
const state = sourceTile.getState();
const sourceTileKey = sourceTile.getKey();
if (state === TileState.LOADED || state === TileState.ERROR) {
if (state === TileState.LOADED) {
unlistenByKey(key);
tile.loadingSourceTiles--;
delete tile.errorSourceTileKeys[sourceTileKey];
} else if (state === TileState.ERROR) {
tile.errorSourceTileKeys[sourceTileKey] = true;
}
if (tile.loadingSourceTiles - Object.keys(tile.errorSourceTileKeys).length === 0) {
tile.hifi = true;
tile.sourceZ = sourceZ;
tile.setState(isEmpty(tile.errorSourceTileKeys) ? TileState.LOADED : TileState.ERROR);
}
}
});
}
} else {
empty = false;
}.bind(this));
if (!covered) {
sourceTiles.length = 0;
}
covered = false;
if (!sourceTile) {
return;
}
if (sourceTile.getState() !== TileState.EMPTY && tile.getState() === TileState.IDLE) {
tile.loadingSourceTiles++;
const key = listen(sourceTile, EventType.CHANGE, function() {
const state = sourceTile.getState();
const sourceTileKey = getKey(sourceTile.tileCoord);
if (state === TileState.LOADED || state === TileState.ERROR) {
if (state === TileState.LOADED) {
unlistenByKey(key);
tile.loadingSourceTiles--;
delete tile.errorSourceTileKeys[sourceTileKey];
} else if (state === TileState.ERROR) {
tile.errorSourceTileKeys[sourceTileKey] = true;
}
if (tile.loadingSourceTiles - Object.keys(tile.errorSourceTileKeys).length === 0) {
tile.hifi = true;
tile.sourceZ = sourceZ;
tile.setState(isEmpty(tile.errorSourceTileKeys) ? TileState.LOADED : TileState.ERROR);
}
}
});
}
}.bind(this));
if (!covered) {
sourceTiles.length = 0;
}
} while (!covered && loadedZ > minZoom);
} while (!covered && loadedZ > minZoom);
}
if (!empty && tile.getState() === TileState.IDLE) {
tile.setState(TileState.LOADING);
}
@@ -284,7 +293,7 @@ class VectorTile extends UrlTile {
* @param {Array<import("../VectorTile").default>} sourceTiles Source tiles.
*/
addSourceTiles(tile, sourceTiles) {
this.sourceTilesByTileKey_[getKey(tile.tileCoord)] = sourceTiles;
this.sourceTilesByTileKey_[tile.getKey()] = sourceTiles;
for (let i = 0, ii = sourceTiles.length; i < ii; ++i) {
sourceTiles[i].consumers++;
}
@@ -294,7 +303,7 @@ class VectorTile extends UrlTile {
* @param {VectorRenderTile} tile Tile.
*/
removeSourceTiles(tile) {
const tileKey = getKey(tile.tileCoord);
const tileKey = tile.getKey();
if (tileKey in this.sourceTilesByTileKey_) {
const sourceTiles = this.sourceTilesByTileKey_[tileKey];
for (let i = 0, ii = sourceTiles.length; i < ii; ++i) {
@@ -302,7 +311,7 @@ class VectorTile extends UrlTile {
sourceTile.consumers--;
if (sourceTile.consumers === 0) {
sourceTile.dispose();
delete this.sourceTiles_[getKey(sourceTile.tileCoord)];
delete this.sourceTileByCoordKey_[getKey(sourceTile.tileCoord)];
}
}
}
@@ -313,18 +322,27 @@ class VectorTile extends UrlTile {
* @inheritDoc
*/
getTile(z, x, y, pixelRatio, projection) {
const tileCoordKey = getKeyZXY(z, x, y);
const coordKey = getKeyZXY(z, x, y);
const key = this.getKey();
let tile;
if (this.tileCache.containsKey(tileCoordKey)) {
tile = /** @type {!import("../Tile.js").default} */ (this.tileCache.get(tileCoordKey));
if (this.tileCache.containsKey(coordKey)) {
tile = /** @type {!import("../Tile.js").default} */ (this.tileCache.get(coordKey));
if (tile.key === key) {
return tile;
}
}
const tileCoord = [z, x, y];
const urlTileCoord = this.getTileCoordForTileUrlFunction(
tileCoord, projection);
let urlTileCoord = this.getTileCoordForTileUrlFunction(tileCoord, projection);
const sourceExtent = this.getTileGrid().getExtent();
if (urlTileCoord && sourceExtent) {
const tileGrid = this.getTileGridForProjection(projection);
const tileExtent = tileGrid.getTileCoordExtent(urlTileCoord);
// make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space
bufferExtent(tileExtent, -1 / tileGrid.getResolution(z), tileExtent);
if (!intersects(sourceExtent, tileExtent)) {
urlTileCoord = null;
}
}
const newTile = new VectorRenderTile(
tileCoord,
urlTileCoord !== null ? TileState.IDLE : TileState.EMPTY,
@@ -337,9 +355,9 @@ class VectorTile extends UrlTile {
if (tile) {
newTile.interimTile = tile;
newTile.refreshInterimChain();
this.tileCache.replace(tileCoordKey, newTile);
this.tileCache.replace(coordKey, newTile);
} else {
this.tileCache.set(tileCoordKey, newTile);
this.tileCache.set(coordKey, newTile);
}
return newTile;
}

View File

@@ -9,8 +9,24 @@
* @enum {string}
*/
export default {
/**
* HiDPI support for [Carmenta Server](https://www.carmenta.com/en/products/carmenta-server)
* @api
*/
CARMENTA_SERVER: 'carmentaserver',
/**
* HiDPI support for [GeoServer](https://geoserver.org/)
* @api
*/
GEOSERVER: 'geoserver',
/**
* HiDPI support for [MapServer](https://mapserver.org/)
* @api
*/
MAPSERVER: 'mapserver',
/**
* HiDPI support for [QGIS](https://qgis.org/)
* @api
*/
QGIS: 'qgis'
};

View File

@@ -41,6 +41,10 @@ import {createXYZ, extentFromProjection} from '../tilegrid.js';
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
*/
@@ -94,7 +98,8 @@ class XYZ extends TileImage {
urls: options.urls,
wrapX: options.wrapX !== undefined ? options.wrapX : true,
transition: options.transition,
attributionsCollapsible: options.attributionsCollapsible
attributionsCollapsible: options.attributionsCollapsible,
zDirection: options.zDirection
});
}

View File

@@ -114,8 +114,8 @@ export class CustomTile extends ImageTile {
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
* @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.
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
*/

View File

@@ -23,7 +23,7 @@ REMOTE=https://github.com/openlayers/openlayers.git
display_usage() {
cat <<-EOF
Usage: ${1} <version>
Usage: ${1} <version> [options]
To publish a new release, update the version number in package.json and
create a tag for the release.
@@ -33,6 +33,8 @@ display_usage() {
The tag must be pushed to ${REMOTE} before the release can be published.
Additional args afer <version> will be passed to "npm publish" (e.g. "--tag beta").
EOF
}
@@ -76,12 +78,13 @@ main() {
npm install
npm run build-package
cd ${BUILT_PACKAGE}
npm publish
shift
npm publish ${@}
}
if test ${#} -ne 1; then
if test ${#} -lt 1; then
display_usage ${0}
exit 1
else
main ${1}
main ${@}
fi

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
width="512px"
height="512px"
viewBox="0 0 512 512"
enable-background="new 0 0 512 512"
xml:space="preserve"
inkscape:version="0.48.4 r9939"
sodipodi:docname="me0.svg"><metadata
id="metadata3776"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs3774" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1024"
inkscape:window-height="1258"
id="namedview3772"
showgrid="false"
inkscape:zoom="0.4609375"
inkscape:cx="309.13338"
inkscape:cy="256"
inkscape:window-x="1016"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<g
id="g3754"
style="fill:#085095;fill-opacity:1;stroke:#ffffff;stroke-opacity:1;stroke-width:25;stroke-miterlimit:4;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round"><path
style="stroke:#ffffff;stroke-width:25;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill:#085095;fill-opacity:1;stroke-linejoin:round;stroke-linecap:round"
id="path3770"
d="m 256,25.6 c -95.4279,0 -172.8,77.3721 -172.8,172.8 0,95.4279 144,288 172.8,288 28.8,0 172.8,-192.5721 172.8,-288 C 428.8,102.9721 351.4279,25.6 256,25.6 z m 0,288 c -63.5346,0 -115.2,-51.6942 -115.2,-115.2 0,-63.5058 51.6654,-115.2 115.2,-115.2 63.5346,0 115.2,51.6942 115.2,115.2 0,63.5058 -51.6654,115.2 -115.2,115.2 z"
inkscape:connector-curvature="0" /><polygon
style="fill:#085095;stroke:#ffffff;stroke-width:69.44444444;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1"
transform="matrix(0.36,0,0,0.36,160.72934,103.79972)"
id="polygon3"
points="374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 259.216,29.942 330.27,173.919 489.16,197.007 "
stroke-miterlimit="10" /></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -1,100 +0,0 @@
import Map from '../../../../src/ol/Map.js';
import View from '../../../../src/ol/View.js';
import Point from '../../../../src/ol/geom/Point.js';
import TileLayer from '../../../../src/ol/layer/Tile.js';
import {assign} from '../../../../src/ol/obj.js';
import {transform} from '../../../../src/ol/proj.js';
import XYZ from '../../../../src/ol/source/XYZ.js';
import CircleStyle from '../../../../src/ol/style/Circle.js';
import Fill from '../../../../src/ol/style/Fill.js';
import Stroke from '../../../../src/ol/style/Stroke.js';
describe('ol.rendering.layer.Tile', function() {
let map;
function createMap(renderer, opt_center, opt_size, opt_pixelRatio, opt_resolutions) {
const MapConstructor = Map;
const size = opt_size !== undefined ? opt_size : [50, 50];
map = new MapConstructor({
pixelRatio: opt_pixelRatio || 1,
target: createMapDiv(size[0], size[1]),
view: new View({
center: opt_center !== undefined ? opt_center : transform(
[-122.416667, 37.783333], 'EPSG:4326', 'EPSG:3857'),
resolutions: opt_resolutions,
zoom: 5
})
});
}
afterEach(function() {
if (map) {
disposeMap(map);
}
map = null;
});
function waitForTiles(renderer, sources, layerOptions, onTileLoaded) {
const LayerConstructor = TileLayer;
let tilesLoading = 0;
let tileLoaded = 0;
const update = function() {
if (tilesLoading === tileLoaded) {
onTileLoaded();
}
};
sources.forEach(function(source, i) {
source.on('tileloadstart', function(event) {
tilesLoading++;
});
source.on('tileloadend', function(event) {
tileLoaded++;
update();
});
source.on('tileloaderror', function(event) {
expect().fail('Tile failed to load');
});
const options = {
source: source
};
assign(options, layerOptions[i] || layerOptions);
map.addLayer(new LayerConstructor(options));
});
}
describe('tile layer with render listener', function() {
let source, onAddLayer;
beforeEach(function() {
source = new XYZ({
url: 'rendering/ol/data/tiles/osm/{z}/{x}/{y}.png',
transition: 0
});
onAddLayer = function(evt) {
evt.element.on('render', function(e) {
e.vectorContext.setImageStyle(new CircleStyle({
radius: 5,
fill: new Fill({color: 'yellow'}),
stroke: new Stroke({color: 'red', width: 1})
}));
e.vectorContext.drawPoint(new Point(
transform([-123, 38], 'EPSG:4326', 'EPSG:3857')));
});
};
});
it('works with the canvas renderer', function(done) {
createMap('canvas', undefined, [100, 100]);
map.getLayers().on('add', onAddLayer);
waitForTiles('canvas', [source], {}, function() {
expectResemble(map, 'rendering/ol/layer/expected/render-canvas.png',
IMAGE_TOLERANCE, done);
});
});
});
});

View File

@@ -112,6 +112,19 @@ describe('ol.layer.Layer', function() {
layer.dispose();
});
it('throws on non-numeric opacity', function() {
function create() {
new Layer({
source: new Source({
projection: 'EPSG:4326'
}),
opacity: 'foo'
});
}
expect(create).to.throwException();
});
it('accepts a custom render function', function() {
let called = false;
const layer = new Layer({
@@ -511,6 +524,13 @@ describe('ol.layer.Layer', function() {
expect(layer.getOpacity()).to.be(0.3);
});
it('throws on types other than number', function() {
function set() {
layer.setOpacity('foo');
}
expect(set).to.throwException();
});
it('triggers a change event', function() {
const listener = sinon.spy();
layer.on('propertychange', listener);

View File

@@ -1,5 +1,6 @@
import {Map, View} from '../../../../src/ol/index.js';
import TileLayer from '../../../../src/ol/layer/Tile.js';
import OSM from '../../../../src/ol/source/OSM.js';
import {OSM, XYZ} from '../../../../src/ol/source.js';
describe('ol.layer.Tile', function() {
@@ -32,4 +33,73 @@ describe('ol.layer.Tile', function() {
});
describe('frameState.animate after tile transition with layer opacity', function() {
let target, map;
beforeEach(function(done) {
target = document.createElement('div');
Object.assign(target.style, {
position: 'absolute',
left: '-1000px',
top: '-1000px',
width: '256px',
height: '256px'
});
document.body.appendChild(target);
map = new Map({
target: target,
view: new View({center: [0, 0], zoom: 1})
});
map.once('rendercomplete', function() {
done();
});
});
afterEach(function() {
map.dispose();
document.body.removeChild(target);
});
it('sets frameState.animate to false when opacity is 1', function(done) {
let lastFrameState;
const layer = new TileLayer({
opacity: 1,
source: new XYZ({
url: 'spec/ol/data/osm-0-0-0.png'
})
});
layer.on('postrender', function(event) {
lastFrameState = event.frameState;
});
map.once('rendercomplete', function() {
expect(lastFrameState.animate).to.be(false);
done();
});
map.addLayer(layer);
});
it('sets frameState.animate to false when opacity is 0.5', function(done) {
let lastFrameState;
const layer = new TileLayer({
opacity: 0.5,
source: new XYZ({
url: 'spec/ol/data/osm-0-0-0.png'
})
});
layer.on('postrender', function(event) {
lastFrameState = event.frameState;
});
map.once('rendercomplete', function() {
expect(lastFrameState.animate).to.be(false);
done();
});
map.addLayer(layer);
});
});
});

View File

@@ -203,6 +203,7 @@ describe('ol.Map', function() {
target: target,
layers: [
new TileLayer({
opacity: 0.5,
source: new XYZ({
url: 'spec/ol/data/osm-{z}-{x}-{y}.png'
})

View File

@@ -86,6 +86,17 @@ describe('ol.renderer.canvas.TileLayer', function() {
done();
});
});
it('respects the source\'s zDirection setting', function(done) {
layer.getSource().zDirection = 1;
map.getView().setZoom(5.8); // would lead to z6 tile request with the default zDirection
map.once('rendercomplete', function() {
const tileCache = layer.getSource().tileCache;
const keys = tileCache.getKeys();
expect(keys.some(key => key.startsWith('6/'))).to.be(false);
done();
});
});
});
});

View File

@@ -75,11 +75,10 @@ describe('ol.renderer.canvas.VectorLayer', function() {
style: layerStyle
});
map.addLayer(layer);
const spy = sinon.spy(layer.getRenderer(),
'renderFeature');
const spy = sinon.spy(layer.getRenderer(), 'renderFeature');
map.renderSync();
expect(spy.getCall(0).args[3]).to.be(layerStyle);
expect(spy.getCall(1).args[3]).to.be(featureStyle);
expect(spy.getCall(0).args[2]).to.be(layerStyle);
expect(spy.getCall(1).args[2]).to.be(featureStyle);
document.body.removeChild(target);
});

View File

@@ -9,6 +9,7 @@ import {getCenter} from '../../../../../src/ol/extent.js';
import MVT from '../../../../../src/ol/format/MVT.js';
import Point from '../../../../../src/ol/geom/Point.js';
import VectorTileLayer from '../../../../../src/ol/layer/VectorTile.js';
import {getKey} from '../../../../../src/ol/tilecoord.js';
import {get as getProjection} from '../../../../../src/ol/proj.js';
import {checkedFonts} from '../../../../../src/ol/render/canvas.js';
import RenderFeature from '../../../../../src/ol/render/Feature.js';
@@ -101,7 +102,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
it('creates a new instance', function() {
const renderer = new CanvasVectorTileLayerRenderer(layer);
expect(renderer).to.be.a(CanvasVectorTileLayerRenderer);
expect(renderer.zDirection).to.be(1);
expect(renderer.getLayer()).to.equal(layer);
});
it('does not render replays for pure image rendering', function() {
@@ -300,12 +301,8 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
tileClass: TileClass,
tileGrid: createXYZ()
});
source.sourceTiles_ = {
'0/0/0': sourceTile
};
source.sourceTilesByTileKey_ = {
'0/0/0': [sourceTile]
};
source.sourceTileByCoordKey_[getKey(sourceTile.tileCoord)] = sourceTile;
source.sourceTilesByTileKey_[sourceTile.getKey()] = [sourceTile];
executorGroup = {};
source.getTile = function() {
const tile = VectorTileSource.prototype.getTile.apply(source, arguments);

View File

@@ -5,7 +5,7 @@ import VectorTile from '../../../../src/ol/VectorTile.js';
import GeoJSON from '../../../../src/ol/format/GeoJSON.js';
import MVT from '../../../../src/ol/format/MVT.js';
import VectorTileLayer from '../../../../src/ol/layer/VectorTile.js';
import {get as getProjection} from '../../../../src/ol/proj.js';
import {get as getProjection, get} from '../../../../src/ol/proj.js';
import VectorTileSource from '../../../../src/ol/source/VectorTile.js';
import {createXYZ} from '../../../../src/ol/tilegrid.js';
import TileGrid from '../../../../src/ol/tilegrid/TileGrid.js';
@@ -14,18 +14,24 @@ import TileState from '../../../../src/ol/TileState.js';
describe('ol.source.VectorTile', function() {
const format = new MVT();
const source = new VectorTileSource({
format: format,
url: 'spec/ol/data/{z}-{x}-{y}.vector.pbf'
let format, source;
beforeEach(function() {
format = new MVT();
source = new VectorTileSource({
format: format,
url: 'spec/ol/data/{z}-{x}-{y}.vector.pbf'
});
});
let tile;
describe('constructor', function() {
it('sets the format on the instance', function() {
expect(source.format_).to.equal(format);
});
it('sets the default zDirection on the instance', function() {
expect(source.zDirection).to.be(1);
});
it('uses ol.VectorTile as default tileClass', function() {
expect(source.tileClass).to.equal(VectorTile);
});
@@ -40,15 +46,9 @@ describe('ol.source.VectorTile', function() {
describe('#getTile()', function() {
it('creates a tile with the correct tile class', function() {
tile = source.getTile(0, 0, 0, 1, getProjection('EPSG:3857'));
const tile = source.getTile(0, 0, 0, 1, getProjection('EPSG:3857'));
expect(tile).to.be.a(VectorRenderTile);
});
it('sets the correct tileCoord on the created tile', function() {
expect(tile.getTileCoord()).to.eql([0, 0, 0]);
});
it('fetches tile from cache when requested again', function() {
expect(source.getTile(0, 0, 0, 1, getProjection('EPSG:3857')))
.to.equal(tile);
});
@@ -71,7 +71,7 @@ describe('ol.source.VectorTile', function() {
});
});
it('handles empty tiles tiles', function(done) {
it('handles empty tiles', function(done) {
const source = new VectorTileSource({
format: new GeoJSON(),
url: ''
@@ -86,6 +86,29 @@ describe('ol.source.VectorTile', function() {
tile.load();
});
it('creates empty tiles outside the source extent', function() {
const fullExtent = get('EPSG:3857').getExtent();
const source = new VectorTileSource({
extent: [fullExtent[0], fullExtent[1], 0, 0]
});
const tile = source.getTile(1, 1, 1, 1, source.getProjection());
expect(tile.getState()).to.be(TileState.EMPTY);
});
it('creates empty tiles outside the world extent when wrapX === false', function() {
const source = new VectorTileSource({
wrapX: false
});
const tile = source.getTile(0, -1, 0, 1, source.getProjection());
expect(tile.getState()).to.be(TileState.EMPTY);
});
it('creates non-empty tiles outside the world extent when wrapX === true', function() {
const source = new VectorTileSource({});
const tile = source.getTile(0, -1, 0, 1, source.getProjection());
expect(tile.getState()).to.be(TileState.IDLE);
});
it('creates new tile when source key changes', function() {
source.setKey('key1');
const tile1 = source.getTile(0, 0, 0, 1, getProjection('EPSG:3857'));
@@ -108,7 +131,7 @@ describe('ol.source.VectorTile', function() {
describe('Tile load events', function() {
it('triggers tileloadstart and tileloadend with ol.VectorTile', function(done) {
tile = source.getTile(14, 8938, 5680, 1, getProjection('EPSG:3857'));
const tile = source.getTile(14, 8938, 5680, 1, getProjection('EPSG:3857'));
let started = false;
source.on('tileloadstart', function() {
started = true;
@@ -190,4 +213,66 @@ describe('ol.source.VectorTile', function() {
});
it('does not fill up the tile queue', function(done) {
const target = document.createElement('div');
target.style.width = '100px';
target.style.height = '100px';
document.body.appendChild(target);
const urls = [
'spec/ol/data/14-8938-5680.vector.pbf?num=0&coord={z},{x},{y}',
'spec/ol/data/14-8938-5680.vector.pbf?num=1&coord={z},{x},{y}',
'spec/ol/data/14-8938-5680.vector.pbf?num=2&coord={z},{x},{y}',
'spec/ol/data/14-8938-5680.vector.pbf?num=3&coord={z},{x},{y}'
];
const source = new VectorTileSource({
format: new MVT(),
url: urls[0]
});
const map = new Map({
target: target,
layers: [
new VectorTileLayer({
source: source
})
],
view: new View({
center: [0, 0],
zoom: 0
})
});
map.renderSync();
const max = urls.length + 3;
let count = 0;
let tile = source.getTile(0, 0, 0, 1, map.getView().getProjection());
tile.addEventListener('change', function onTileChange(e) {
if (e.target.getState() !== TileState.LOADED && !e.target.hifi) {
return;
}
e.target.removeEventListener('change', onTileChange);
map.once('rendercomplete', function() {
expect(map.tileQueue_.getTilesLoading()).to.be(0);
++count;
if (count === max) {
document.body.removeChild(target);
map.dispose();
done();
return;
}
source.setUrl(urls[count % urls.length]);
tile = source.getTile(0, 0, 0, 1, map.getView().getProjection());
tile.addEventListener('change', onTileChange);
});
});
});
});

View File

@@ -20,6 +20,13 @@ describe('ol.source.XYZ', function() {
expect(source).to.be.an(TileSource);
});
it('can be constructed with a custom zDirection', function() {
const source = new XYZ({
zDirection: -1
});
expect(source.zDirection).to.be(-1);
});
it('can be constructed with a custom tile grid', function() {
const tileGrid = createXYZ();
const tileSource = new XYZ({

View File

@@ -5,7 +5,6 @@ import {listen, listenOnce, unlistenByKey} from '../../../src/ol/events.js';
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
import {createXYZ} from '../../../src/ol/tilegrid.js';
import TileGrid from '../../../src/ol/tilegrid/TileGrid.js';
import {getKey} from '../../../src/ol/tilecoord.js';
import EventType from '../../../src/ol/events/EventType.js';
@@ -107,7 +106,7 @@ describe('ol.VectorRenderTile', function() {
tile.load();
expect(tile.getState()).to.be(TileState.LOADING);
tile.dispose();
expect(source.sourceTilesByTileKey_[getKey(tile)]).to.be(undefined);
expect(source.sourceTilesByTileKey_[tile.getKey()]).to.be(undefined);
expect(tile.getState()).to.be(TileState.ABORT);
});