Compare commits
61 Commits
v6.0.0-bet
...
v6.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8b5dfa981 | ||
|
|
42f1a7ed30 | ||
|
|
f3d6456876 | ||
|
|
2ca13de4de | ||
|
|
87ae93ca2d | ||
|
|
5da32dbc5b | ||
|
|
6be2818f14 | ||
|
|
b602a6b33a | ||
|
|
20a81ceb2f | ||
|
|
3d6cf24c26 | ||
|
|
6a741d0504 | ||
|
|
aa55cce3ba | ||
|
|
a5fbbef970 | ||
|
|
25c8d93eba | ||
|
|
eb294c78d1 | ||
|
|
bd3f35eef0 | ||
|
|
f839b34594 | ||
|
|
99462d3b53 | ||
|
|
200392785d | ||
|
|
c0e5c4b7fe | ||
|
|
189ad24528 | ||
|
|
4aa11ecc94 | ||
|
|
e61c5c07bc | ||
|
|
0212ce6554 | ||
|
|
b76a0379dd | ||
|
|
e94c7b6c39 | ||
|
|
2c69ad2bb4 | ||
|
|
e8e7c46463 | ||
|
|
abda7f4f1d | ||
|
|
e8500c395c | ||
|
|
6f5a066bab | ||
|
|
08816ec9f9 | ||
|
|
fac659fa0a | ||
|
|
b0069c3c5d | ||
|
|
e7be28d2b5 | ||
|
|
15aa5ebc1f | ||
|
|
a9ad24cce2 | ||
|
|
486eb205cb | ||
|
|
28e64f646f | ||
|
|
78cf32ae70 | ||
|
|
a340da8f6e | ||
|
|
336056f4f0 | ||
|
|
e31e4b7867 | ||
|
|
683c0ef5dc | ||
|
|
23179e9ac5 | ||
|
|
7cdfc33d15 | ||
|
|
776dab81b8 | ||
|
|
182f1448a9 | ||
|
|
9b6fcf8d7b | ||
|
|
bd1c8db7a3 | ||
|
|
0fb638fcb6 | ||
|
|
effb95b322 | ||
|
|
e5ac326f1c | ||
|
|
2d0d06842d | ||
|
|
7355906c3a | ||
|
|
ec10cda088 | ||
|
|
d59eed5d3b | ||
|
|
d4980754ad | ||
|
|
e07ff9c04e | ||
|
|
94edf32540 | ||
|
|
91d2f98774 |
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
@media (min-width: 800px) {
|
||||
.wrapper {
|
||||
display: flex;
|
||||
}
|
||||
.half {
|
||||
padding: 0 10px;
|
||||
width: 50%;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
10
package.json
@@ -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",
|
||||
|
||||
BIN
rendering/cases/layer-tile-render-listener/expected.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
46
rendering/cases/layer-tile-render-listener/main.js
Normal 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();
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
@@ -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});
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -113,8 +113,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
*/
|
||||
this.tmpTransform_ = createTransform();
|
||||
|
||||
// Use nearest lower resolution.
|
||||
this.zDirection = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
};
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 806 B |
|
Before Width: | Height: | Size: 806 B |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 254 B |
|
Before Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 504 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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'
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||