Compare commits

..

1 Commits

Author SHA1 Message Date
ahocevar
e0381bfd6a Tag for v6.0.0-beta.4 2019-04-03 15:17:02 +02:00
127 changed files with 637 additions and 48382 deletions

View File

@@ -27,10 +27,6 @@ jobs:
name: Run Tests
command: npm test
- store_artifacts:
path: coverage/
destination: coverage
- store_artifacts:
path: rendering/cases/
destination: rendering
@@ -42,11 +38,3 @@ jobs:
- store_artifacts:
path: build/examples
destination: examples
- run:
name: Build API Docs
command: npm run apidoc
- store_artifacts:
path: build/apidoc
destination: apidoc

View File

@@ -4,16 +4,6 @@
#### Backwards incompatible changes
#### Removal of optional this arguments
The optional this (i.e. opt_this) arguments were removed from the following methods.
Please use closures, the es6 arrow function or the bind method to achieve this effect (Bind is explained here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
* `forEachCorner` in `ol/extent`
* `LRUCache#forEach`
* `RBush#forEach` and `RBush#forEachInExtent`
##### The `setCenter`, `setZoom`, `setResolution` and `setRotation` methods on `ol/View` do not bypass constraints anymore
Previously, these methods allowed setting values that were inconsistent with the given view constraints.
@@ -98,14 +88,6 @@ If you were previously using `VectorTile` layers with `renderMode: 'vector'`, yo
If you were previously using `Vector` layers with `renderMode: 'image'`, you have to remove this configuration option. Instead, use the new `ol/layer/VectorImage` layer with your `ol/source/Vector`.
##### New declutter behavior
If a map has more than one layer with `declutter` set to true, decluttering now considers all `Vector` and `VectorTile` layers, instead of decluttering each layer separately. Only `VectorImage` layers continue to be decluttered separately. The higher the z-index of a layer, the higher the priority of its decluttered items.
Within a layer, the declutter order has changed. Previously, styles with a lower `zIndex` were prioritized over those with a higher `zIndex`. Now the opposite order is used.
On vector layers, even if decluttered images or texts have a lower z-Index than polygons or lines, they will now be rendered on top of the polygons or lines. For vector tile layers, this was the case already in previous releases.
##### New `prerender` and `postrender` layer events replace old `precompose`, `render` and `postcompose` events
If you were previously registering for `precompose` and `postcompose` events, you should now register for `prerender` and `postrender` events on layers. Instead of the previous `render` event, you should now listen for `postrender`. Layers are no longer composed to a single Canvas element. Instead, they are added to the map viewport as individual elements.

View File

@@ -1,43 +1,43 @@
<table><tr>
<th width="33.3%">Map</th><th width="33.3%">View</th><th width="33.3%">Layers</th>
</tr><tr>
<td><p>A <a href="module-ol_Map-Map.html">map</a> is made of <a href="module-ol_layer_Base-BaseLayer.html">layers</a>, a <a href="module-ol_View-View.html">view</a> to visualize them, <a href="module-ol_interaction_Interaction-Interaction.html">interactions</a> to modify map content and <a href="module-ol_control_Control-Control.html">controls</a> with UI components.</p>
<a href="module-ol_Map-Map.html">Overview</a><br>
<a href="module-ol_Map-Map.html#Map">Creation</a><br>
<a href="module-ol_MapBrowserEvent-MapBrowserEvent.html">Events</a></td>
<td><p>A [map](module-ol_Map-Map.html) is made of [layers](module-ol_layer_Base-BaseLayer.html), a [view](module-ol_View-View.html) to visualize them, [interactions](module-ol_interaction_Interaction-Interaction.html) to modify map content and [controls](module-ol_control_Control-Control.html) with UI components.</p>
[Overview](module-ol_Map-Map.html)<br>
[Creation](module-ol_Map-Map.html#Map)<br>
[Events](module-ol_MapBrowserEvent-MapBrowserEvent.html)</td>
<td><p>The view manages the visual parameters of the map view, like resolution or rotation.</p>
<a href="module-ol_View-View.html">View</a> with center, projection, resolution and rotation</td>
<td><p>Layers are lightweight containers that get their data from <a href="module-ol_source_Source-Source.html">sources</a>.</p>
<a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a><br>
<a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a><br>
<a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a><br>
<a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a></td>
[View](module-ol_View-View.html) with center, projection, resolution and rotation</td>
<td><p>Layers are lightweight containers that get their data from [sources](module-ol_source_Source-Source.html).</p>
[ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)<br>
[ol/layer/Image](module-ol_layer_Image-ImageLayer.html)<br>
[ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)<br>
[ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)</td>
</tr><tr>
<th>Controls</th><th>Interactions</th><th>Sources and formats</th>
</tr><tr>
<td><a href="module-ol_control_util.html#.defaults">Map default controls</a><br>
<a href="module-ol_control_Control-Control.html">All controls</a>
<td>[Map default controls](module-ol_control_util.html#.defaults)<br>
[All controls](module-ol_control_Control-Control.html)
</td>
<td>
<a href="module-ol_interaction.html#~defaults">Map default interactions</a><br>
Interactions for <a href="module-ol_Feature-Feature.html">vector features</a>
<ul><li><a href="module-ol_interaction_Select-Select.html">ol/interaction/Select</a></li>
<li><a href="module-ol_interaction_Draw-Draw.html">ol/interaction/Draw</a></li>
<li><a href="module-ol_interaction_Modify-Modify.html">ol/interaction/Modify</a></li></ul>
<a href="module-ol_interaction_Interaction-Interaction.html">All interactions</a></td>
<td><a href="module-ol_source_Tile-TileSource.html">Tile sources</a> for <a href="module-ol_layer_Tile-TileLayer.html">ol/layer/Tile</a>
<br><a href="module-ol_source_Image-ImageSource.html">Image sources</a> for <a href="module-ol_layer_Image-ImageLayer.html">ol/layer/Image</a>
<br><a href="module-ol_source_Vector-VectorSource.html">Vector sources</a> for <a href="module-ol_layer_Vector-VectorLayer.html">ol/layer/Vector</a>
<br><a href="module-ol_source_VectorTile-VectorTile.html">Vector tile sources</a> for <a href="module-ol_layer_VectorTile-VectorTileLayer.html">ol/layer/VectorTile</a>
<br><a href="module-ol_format_Feature-FeatureFormat.html">Formats</a> for reading/writing vector data
<br><a href="module-ol_format_WMSCapabilities-WMSCapabilities.html">ol/format/WMSCapabilities</a></td></tr>
[Map default interactions](module-ol_interaction.html#~defaults)<br>
Interactions for [vector features](module-ol_Feature-Feature.html)
<ul><li>[ol/interaction/Select](module-ol_interaction_Select-Select.html)</li>
<li>[ol/interaction/Draw](module-ol_interaction_Draw-Draw.html)</li>
<li>[ol/interaction/Modify](module-ol_interaction_Modify-Modify.html)</li></ul>
[All interactions](module-ol_interaction_Interaction-Interaction.html)</td>
<td>[Tile sources](module-ol_source_Tile-TileSource.html) for [ol/layer/Tile](module-ol_layer_Tile-TileLayer.html)
<br>[Image sources](module-ol_source_Image-ImageSource.html) for [ol/layer/Image](module-ol_layer_Image-ImageLayer.html)
<br>[Vector sources](module-ol_source_Vector-VectorSource.html) for [ol/layer/Vector](module-ol_layer_Vector-VectorLayer.html)
<br>[Vector tile sources](module-ol_source_VectorTile-VectorTile.html) for [ol/layer/VectorTile](module-ol_layer_VectorTile-VectorTileLayer.html)
<br>[Formats](module-ol_format_Feature-FeatureFormat.html) for reading/writing vector data
<br>[ol/format/WMSCapabilities](module-ol_format_WMSCapabilities-WMSCapabilities.html)</td></tr>
<tr><th>Projections</th><th>Observable objects</th><th>Other components</th></tr>
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use <a href="module-ol_proj.html#.transform">ol/proj#transform()</a> and <a href="module-ol_proj.html#.transformExtent">ol/proj#transformExtent()</a>.</p>
<a href="module-ol_proj.html">ol/proj</a></td>
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use [ol/proj#transform()](module-ol_proj.html#.transform) and [ol/proj#transformExtent()](module-ol_proj.html#.transformExtent).</p>
[ol/proj](module-ol_proj.html)</td>
<td><p>Changes to all [ol/Object](module-ol_Object-BaseObject.html)s can be observed by calling the [object.on('propertychange')](module-ol_Object-BaseObject.html#on) method. Listeners receive an [ol/Object.ObjectEvent](module-ol_Object-ObjectEvent.html) with information on the changed property and old value.</p>
<td>
<a href="module-ol_Geolocation.html">ol/Geolocation</a><br>
<a href="module-ol_Overlay-Overlay.html">ol/Overlay</a><br></td>
[ol/Geolocation](module-ol_Geolocation.html)<br>
[ol/Overlay](module-ol_Overlay-Overlay.html)<br></td>
</tr></table>
&nbsp;

View File

@@ -1,29 +1,32 @@
const events = {};
const classes = {};
exports.handlers = {
newDoclet: function(e) {
const doclet = e.doclet;
if (doclet.kind !== 'event') {
return;
}
const cls = doclet.longname.split('#')[0];
let cls;
if (doclet.kind == 'event') {
cls = doclet.longname.split('#')[0];
if (!(cls in events)) {
events[cls] = [];
}
events[cls].push(doclet.longname);
} else if (doclet.kind == 'class' && !(doclet.longname in classes)) {
classes[doclet.longname] = doclet;
}
},
parseComplete: function(e) {
const doclets = e.doclets;
for (let i = 0, ii = doclets.length - 1; i < ii; ++i) {
const doclet = doclets[i];
let doclet, i, ii, j, jj, event, fires;
for (i = 0, ii = doclets.length - 1; i < ii; ++i) {
doclet = doclets[i];
if (doclet.fires) {
if (doclet.kind == 'class') {
const fires = [];
for (let j = 0, jj = doclet.fires.length; j < jj; ++j) {
const event = doclet.fires[j].replace('event:', '');
fires = [];
for (j = 0, jj = doclet.fires.length; j < jj; ++j) {
event = doclet.fires[j].replace('event:', '');
if (events[event]) {
fires.push.apply(fires, events[event]);
} else if (doclet.fires[j] !== 'event:ObjectEvent') {

View File

@@ -220,11 +220,3 @@ Duplicate item added to a unique collection. For example, it may be that you tr
### 59
Invalid command found in the PBF. This indicates that the loaded vector tile may be corrupt.
### 60
Missing or invalid `size`.
### 61
Cannot determine IIIF Image API version from provided image information JSON.

View File

@@ -5,6 +5,7 @@
"common": false,
"createMapboxStreetsV6Style": false,
"d3": false,
"domtoimage": false,
"geojsonvt": false,
"GyroNorm": false,
"jsPDF": false,

View File

@@ -100,7 +100,8 @@ function xyz2rgb(x) {
const raster = new RasterSource({
sources: [new Stamen({
layer: 'watercolor'
layer: 'watercolor',
transition: 0
})],
operation: function(pixels, data) {
const hcl = rgb2hcl(pixels[0]);

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,6 @@ gn.init().then(function() {
center[0] -= resolution * gamma * 25;
center[1] += resolution * beta * 25;
view.setCenter(center);
view.setCenter(view.constrainCenter(center));
});
});

View File

@@ -3,9 +3,11 @@ layout: example.html
title: Map Export
shortdesc: Example of exporting a map as a PNG image.
docs: >
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/html-to-image">html-to-image</a>
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/dom-to-image-more">dom-to-image-more</a>
library.
tags: "export, png, openstreetmap"
resources:
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
---
<div id="map" class="map"></div>
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>

View File

@@ -4,8 +4,6 @@ import GeoJSON from '../src/ol/format/GeoJSON.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {toPng} from 'html-to-image';
const map = new Map({
layers: [
new TileLayer({
@@ -25,17 +23,9 @@ const map = new Map({
})
});
// export options for html-to-image.
// See: https://github.com/bubkoo/html-to-image#options
const exportOptions = {
filter: function(element) {
return element.className.indexOf('ol-control') === -1;
}
};
document.getElementById('export-png').addEventListener('click', function() {
map.once('rendercomplete', function() {
toPng(map.getTargetElement(), exportOptions)
domtoimage.toPng(map.getViewport().querySelector('.ol-layers'))
.then(function(dataURL) {
const link = document.getElementById('image-download');
link.href = dataURL;

View File

@@ -7,6 +7,7 @@ docs: >
tags: "export, pdf, openstreetmap"
resources:
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
---
<div class="row-fluid">
<div class="span12">

View File

@@ -4,8 +4,6 @@ import WKT from '../src/ol/format/WKT.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {toJpeg} from 'html-to-image';
const raster = new TileLayer({
source: new OSM()
});
@@ -43,15 +41,6 @@ const dims = {
a5: [210, 148]
};
// export options for html-to-image.
// See: https://github.com/bubkoo/html-to-image#options
const exportOptions = {
filter: function(element) {
return element.className.indexOf('ol-control') === -1;
}
};
const exportButton = document.getElementById('export-pdf');
exportButton.addEventListener('click', function() {
@@ -68,14 +57,15 @@ exportButton.addEventListener('click', function() {
const extent = map.getView().calculateExtent(size);
map.once('rendercomplete', function() {
toJpeg(map.getTargetElement(), exportOptions).then(function(dataUrl) {
domtoimage.toJpeg(map.getViewport().querySelector('.ol-layers')).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
size: size,
constrainResolution: false
});
exportButton.disabled = false;
document.body.style.cursor = 'auto';

View File

@@ -1,5 +1,6 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {platformModifierKeyOnly} from '../src/ol/events/condition.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import ExtentInteraction from '../src/ol/interaction/Extent.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
@@ -26,7 +27,9 @@ const map = new Map({
})
});
const extent = new ExtentInteraction();
const extent = new ExtentInteraction({
condition: platformModifierKeyOnly
});
map.addInteraction(extent);
extent.setActive(false);

View File

@@ -1,25 +0,0 @@
---
layout: example.html
title: Filtering features with WebGL
shortdesc: Using WebGL to filter large quantities of features
docs: >
This example shows how to use `ol/renderer/webgl/PointsLayer` to dynamically filter a large amount
of point geometries. The above map is based on a dataset from the NASA containing 45k recorded meteorite
landing sites. Each meteorite is marked by a circle on the map (the bigger the circle, the heavier
the object). A pulse effect has been added, which is slightly offset by the year of the impact.
Adjusting the sliders causes the objects outside of the date range to be filtered out of the map. This is done using
a custom fragment shader on the layer renderer, and by using the `v_opacity` attribute of the rendered objects
to store the year of impact.
tags: "webgl, icon, sprite, filter, feature"
---
<div id="map" class="map"></div>
<form>
<div id="status">Show impacts between <span class="min-year"></span> and <span class="max-year"></span></div>
<label>Minimum year:</label>
<input id="min-year" type="range" min="1850" max="2015" step="1" value="1850"/>
<label>Maximum year:</label>
<input id="max-year" type="range" min="1850" max="2015" step="1" value="2015"/>
</form>

View File

@@ -1,164 +0,0 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import Feature from '../src/ol/Feature';
import Point from '../src/ol/geom/Point';
import VectorLayer from '../src/ol/layer/Vector';
import {Vector} from '../src/ol/source';
import {fromLonLat} from '../src/ol/proj';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
import {clamp, lerp} from '../src/ol/math';
import Stamen from '../src/ol/source/Stamen';
const vectorSource = new Vector({
features: [],
attributions: 'NASA'
});
const oldColor = [180, 140, 140];
const newColor = [255, 80, 80];
const startTime = Date.now() * 0.001;
// hanle input values & events
const minYearInput = document.getElementById('min-year');
const maxYearInput = document.getElementById('max-year');
function updateStatusText() {
const div = document.getElementById('status');
div.querySelector('span.min-year').textContent = minYearInput.value;
div.querySelector('span.max-year').textContent = maxYearInput.value;
}
minYearInput.addEventListener('input', updateStatusText);
minYearInput.addEventListener('change', updateStatusText);
maxYearInput.addEventListener('input', updateStatusText);
maxYearInput.addEventListener('change', updateStatusText);
updateStatusText();
class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
colorCallback: function(feature, color) {
// color is interpolated based on year
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
color[0] = lerp(oldColor[0], newColor[0], ratio) / 255;
color[1] = lerp(oldColor[1], newColor[1], ratio) / 255;
color[2] = lerp(oldColor[2], newColor[2], ratio) / 255;
color[3] = 1;
return color;
},
sizeCallback: function(feature) {
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
},
fragmentShader: [
'precision mediump float;',
'uniform float u_time;',
'uniform float u_minYear;',
'uniform float u_maxYear;',
'varying vec2 v_texCoord;',
'varying float v_opacity;',
'varying vec4 v_color;',
'void main(void) {',
' float impactYear = v_opacity;',
// filter out pixels if the year is outside of the given range
' if (impactYear < u_minYear || v_opacity > u_maxYear) {',
' discard;',
' }',
' vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);',
' float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;',
' float value = 2.0 * (1.0 - sqRadius);',
' float alpha = smoothstep(0.0, 1.0, value);',
' vec3 color = v_color.rgb;',
' float period = 8.0;',
' color.g *= 2.0 * (1.0 - sqrt(mod(u_time + impactYear * 0.025, period) / period));',
' gl_FragColor = vec4(color, v_color.a);',
' gl_FragColor.a *= alpha;',
' gl_FragColor.rgb *= gl_FragColor.a;',
'}'
].join(' '),
opacityCallback: function(feature) {
// here the opacity channel of the vertices is used to store the year of impact
return feature.get('year');
},
uniforms: {
u_time: function() {
return Date.now() * 0.001 - startTime;
},
u_minYear: function() {
return parseInt(minYearInput.value);
},
u_maxYear: function() {
return parseInt(maxYearInput.value);
}
}
});
}
}
function loadData() {
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/meteorite_landings.csv');
client.onload = function() {
const csv = client.responseText;
const features = [];
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
let curIndex;
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
if (isNaN(coords[0]) || isNaN(coords[1])) {
// guard against bad data
continue;
}
features.push(new Feature({
mass: parseFloat(line[1]) || 0,
year: parseInt(line[2]) || 0,
geometry: new Point(coords)
}));
}
vectorSource.addFeatures(features);
};
client.send();
}
loadData();
const map = new Map({
layers: [
new TileLayer({
source: new Stamen({
layer: 'toner'
})
}),
new WebglPointsLayer({
source: vectorSource
})
],
target: document.getElementById('map'),
view: new View({
center: [0, 0],
zoom: 2
})
});
// animate the map
function animate() {
map.render();
window.requestAnimationFrame(animate);
}
animate();

View File

@@ -10,6 +10,7 @@ import {fromLonLat} from '../src/ol/proj';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
import {lerp} from '../src/ol/math';
const features = [];
const vectorSource = new Vector({
features: [],
attributions: 'National UFO Reporting Center'
@@ -38,17 +39,16 @@ class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
texture: texture,
colorCallback: function(feature, color) {
colorCallback: function(feature, vertex, component) {
// component at index 3 is alpha
if (component === 3) {
return 1;
}
// color is interpolated based on year (min is 1910, max is 2013)
// please note: most values are between 2000-2013
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
color[0] = lerp(oldColor[0], newColor[0], ratio * ratio) / 255;
color[1] = lerp(oldColor[1], newColor[1], ratio * ratio) / 255;
color[2] = lerp(oldColor[2], newColor[2], ratio * ratio) / 255;
color[3] = 1;
return color;
return lerp(oldColor[component], newColor[component], ratio * ratio) / 255;
},
texCoordCallback: function(feature, component) {
let coords = shapeTextureCoords[feature.get('shape')];
@@ -70,15 +70,18 @@ function loadData() {
client.open('GET', 'data/csv/ufo_sighting_data.csv');
client.onload = function() {
const csv = client.responseText;
const features = [];
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
let curIndex;
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
let prevIndex = 0;
let line;
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;
// skip header
if (prevIndex === 0) {
continue;
}
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
// only keep valid points

View File

@@ -1,16 +0,0 @@
---
layout: example.html
title: IIIF Image API
shortdesc: Example of a IIIF Image API source.
docs: >
Example of a tile source for an International Image Interoperability Framework (IIIF) Image Service.
Try any Image API version 1 or 2 service.
tags: "IIIF, IIIF Image API, tile source"
---
<div id="map" class="map"></div>
<div class="controls">
<div id="iiif-notification">&nbsp;</div>
Enter <code>info.json</code> URL:
<input type="text" id="imageInfoUrl" value="https://iiif.ub.uni-leipzig.de/iiif/j2k/0000/0107/0000010732/00000072.jpx/info.json">
<button id="display">Display image</button>
</div>

View File

@@ -1,46 +0,0 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import IIIF from '../src/ol/source/IIIF.js';
import IIIFInfo from '../src/ol/format/IIIFInfo.js';
const layer = new TileLayer(),
map = new Map({
layers: [layer],
target: 'map'
}),
notifyDiv = document.getElementById('iiif-notification'),
urlInput = document.getElementById('imageInfoUrl'),
displayButton = document.getElementById('display');
function refreshMap(imageInfoUrl) {
fetch(imageInfoUrl).then(function(response) {
response.json().then(function(imageInfo) {
const options = new IIIFInfo(imageInfo).getTileSourceOptions();
if (options === undefined || options.version === undefined) {
notifyDiv.textContent = 'Data seems to be no valid IIIF image information.';
return;
}
options.zDirection = -1;
const iiifTileSource = new IIIF(options);
layer.setSource(iiifTileSource);
map.setView(new View({
resolutions: iiifTileSource.getTileGrid().getResolutions(),
extent: iiifTileSource.getTileGrid().getExtent(),
constrainOnlyCenter: true
}));
map.getView().fit(iiifTileSource.getTileGrid().getExtent());
notifyDiv.textContent = '';
}).catch(function(body) {
notifyDiv.textContent = 'Could not read image info json. ' + body;
});
}).catch(function() {
notifyDiv.textContent = 'Could not read data from URL.';
});
}
displayButton.addEventListener('click', function() {
refreshMap(urlInput.value);
});
refreshMap(urlInput.value);

View File

@@ -11,25 +11,9 @@
body {
padding-top: 70px;
}
img.header-logo {
padding-left: 18px;
}
input.search-query {
color: #333;
}
@media (max-width: 480px) {
input.search-query {
width: 110px;
}
#count {
display: none;
}
}
@media (max-width: 374px) {
input.search-query {
display: none;
}
}
.example {
display: block;
padding: 10px;
@@ -198,9 +182,9 @@
<body>
<header class="navbar navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="container">
<div class="display-table pull-left">
<a class="navbar-brand" href="./"><img class="header-logo" src="./resources/logo-70x70.png">&nbsp;OpenLayers</a>
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers Examples</a>
<form class="navbar-form" role="search">
<input name="q" type="text" id="keywords" class="search-query" placeholder="Search" autofocus>
<span id="count"></span>

View File

@@ -6,7 +6,7 @@ docs: >
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
tags: "simple, mapbox, vector, tiles"
resources:
- https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.js
- https://unpkg.com/mapbox-gl@0.51.0/dist/mapbox-gl.js
cloak:
- key: ER67WIiPdCQvhgsUjoWK
value: Your Mapbox access token from http://mapbox.com/ here

View File

@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import Layer from '../src/ol/layer/Layer';
import {assign} from '../src/ol/obj';
import {toLonLat} from '../src/ol/proj';
import {getTransform} from '../src/ol/proj';
import SourceState from '../src/ol/source/State';
import {Stroke, Style} from '../src/ol/style.js';
import VectorLayer from '../src/ol/layer/Vector.js';
@@ -12,7 +12,7 @@ import GeoJSON from '../src/ol/format/GeoJSON.js';
class Mapbox extends Layer {
/**
* @param {import('../src/ol/layer/Layer').Options} options Layer options.
* @param {import('./Base.js').Options} options Layer options.
*/
constructor(options) {
const baseOptions = assign({}, options);
@@ -32,7 +32,8 @@ class Mapbox extends Layer {
initMap() {
const map = this.map_;
const view = map.getView();
const center = toLonLat(view.getCenter(), view.getProjection());
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
const center = transformToLatLng(view.getCenter());
this.centerLastRender = view.getCenter();
this.zoomLastRender = view.getZoom();
@@ -60,7 +61,9 @@ class Mapbox extends Layer {
this.mbmap.getCanvas().remove();
this.loaded = true;
this.map_.render();
this.mbmap.getContainer().querySelector('.mapboxgl-control-container').remove();
[
'mapboxgl-control-container'
].forEach(className => document.getElementsByClassName(className)[0].remove());
}.bind(this));
this.mbmap.on('render', function() {
@@ -71,7 +74,7 @@ class Mapbox extends Layer {
if (this.zoomNextRender) {
this.zoomLastRender = this.zoomNextRender;
}
this.updateRenderedPosition(0, 0, 1);
this.updateRenderedPosition([0, 0], 1);
}.bind(this));
}
@@ -83,13 +86,15 @@ class Mapbox extends Layer {
render(frameState) {
const map = this.map_;
const view = map.getView();
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
this.centerNextRender = view.getCenter();
const lastRender = map.getPixelFromCoordinate(this.centerLastRender);
const nextRender = map.getPixelFromCoordinate(this.centerNextRender);
const centerOffset = [lastRender[0] - nextRender[0], lastRender[1] - nextRender[1]];
this.zoomNextRender = view.getZoom();
const scale = Math.pow(2, this.zoomNextRender - this.zoomLastRender);
this.updateRenderedPosition(lastRender[0] - nextRender[0], lastRender[1] - nextRender[1], scale);
const zoomOffset = Math.pow(2, this.zoomNextRender - this.zoomLastRender);
this.updateRenderedPosition(centerOffset, zoomOffset);
const rotation = frameState.viewState.rotation;
if (rotation) {
@@ -99,7 +104,7 @@ class Mapbox extends Layer {
}
// Re-render mbmap
const center = toLonLat(this.centerNextRender, view.getProjection());
const center = transformToLatLng(this.centerNextRender);
const zoom = view.getZoom() - 1;
this.mbmap.jumpTo({
center: center,
@@ -108,11 +113,11 @@ class Mapbox extends Layer {
return this.mbmap.getCanvas();
}
updateRenderedPosition(left, top, scale) {
updateRenderedPosition(centerOffset, zoomOffset) {
const style = this.mbmap.getCanvas().style;
style.left = Math.round(left) + 'px';
style.top = Math.round(top) + 'px';
style.transform = 'scale(' + scale + ')';
style.left = Math.round(centerOffset[0]) + 'px';
style.top = Math.round(centerOffset[1]) + 'px';
style.transform = 'scale(' + zoomOffset + ')';
}
setVisible(visible) {

View File

@@ -24,7 +24,8 @@ function flood(pixels, data) {
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
const elevation = new XYZ({
url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
crossOrigin: 'anonymous'
crossOrigin: 'anonymous',
transition: 0
});
const raster = new RasterSource({

View File

@@ -100,7 +100,8 @@ function shade(inputs, data) {
const elevation = new XYZ({
url: 'https://{a-d}.tiles.mapbox.com/v3/aj.sf-dem/{z}/{x}/{y}.png',
crossOrigin: 'anonymous'
crossOrigin: 'anonymous',
transition: 0
});
const raster = new Raster({

View File

@@ -78,7 +78,7 @@
<header class="navbar" role="navigation">
<div class="container">
<div class="display-table pull-left" id="navbar-logo-container">
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers</a>
<a class="navbar-brand" href="./"><img src="./resources/logo-70x70.png">&nbsp;OpenLayers Examples</a>
</div>
<!-- menu items that get hidden below 768px width -->
<nav class='collapse navbar-collapse navbar-responsive-collapse'>
@@ -122,7 +122,7 @@
<a class="copy-button" id="copy-html-button" data-clipboard-target="#example-html-source"><i class="fa fa-clipboard"></i> Copy</a>
</div>
<pre><legend>index.html</legend><code id="example-html-source" class="language-markup">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{ title }}&lt;/title&gt;
&lt;!-- The line below is only needed for old environments like Internet Explorer and Android 4.x --&gt;

View File

@@ -46,7 +46,7 @@ function updateInfo() {
function setTime() {
startDate.setMinutes(startDate.getMinutes() + 15);
if (startDate > new Date()) {
if (startDate > Date.now()) {
startDate = threeHoursAgo();
}
layers[1].getSource().updateParams({'TIME': startDate.toISOString()});

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "6.0.0-beta.7",
"version": "6.0.0-beta.4",
"description": "OpenLayers mapping library",
"keywords": [
"map",
@@ -24,7 +24,7 @@
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && tsc --project config/tsconfig-build.json",
"typecheck": "tsc --pretty",
"apidoc": "jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
"apidoc": "jsdoc config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
},
"main": "index.js",
"repository": {
@@ -41,62 +41,56 @@
"rbush": "2.0.2"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"@openlayers/eslint-plugin": "^4.0.0-beta.2",
"@openlayers/eslint-plugin": "^4.0.0-beta.1",
"@types/arcgis-rest-api": "^10.4.4",
"@types/geojson": "^7946.0.7",
"@types/geojson": "^7946.0.6",
"@types/pbf": "^3.0.1",
"@types/rbush": "^2.0.2",
"@types/topojson-specification": "^1.0.1",
"babel-loader": "^8.0.5",
"buble": "^0.19.7",
"buble-loader": "^0.5.1",
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.3.0",
"copy-webpack-plugin": "^5.0.3",
"clean-css-cli": "4.2.1",
"copy-webpack-plugin": "^5.0.1",
"coveralls": "3.0.3",
"eslint": "^5.16.0",
"eslint": "^5.15.2",
"eslint-config-openlayers": "^11.0.0",
"expect.js": "0.3.1",
"front-matter": "^3.0.2",
"fs-extra": "^8.0.0",
"glob": "^7.1.4",
"globby": "^9.2.0",
"handlebars": "4.1.2",
"html-to-image": "^0.1.0",
"front-matter": "^3.0.1",
"fs-extra": "^7.0.1",
"glob": "^7.1.2",
"globby": "^9.1.0",
"handlebars": "4.1.1",
"istanbul": "0.4.5",
"istanbul-instrumenter-loader": "^3.0.1",
"jquery": "3.4.1",
"jsdoc": "3.6.1",
"jsdoc-plugin-typescript": "^2.0.0",
"karma": "^4.1.0",
"jquery": "3.3.1",
"jsdoc": "3.5.5",
"jsdoc-plugin-typescript": "^1.0.7",
"karma": "^4.0.1",
"karma-chrome-launcher": "2.2.0",
"karma-coverage": "^1.1.2",
"karma-coverage-istanbul-reporter": "^2.0.5",
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "1.3.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-rc.2",
"loglevelnext": "^3.0.1",
"marked": "0.6.2",
"mocha": "6.1.4",
"ol-mapbox-style": "^4.3.1",
"loglevelnext": "^3.0.0",
"marked": "0.6.1",
"mocha": "6.0.2",
"ol-mapbox-style": "^4.2.1",
"pixelmatch": "^4.0.2",
"pngjs": "^3.4.0",
"proj4": "2.5.0",
"puppeteer": "~1.15.0",
"serve-static": "^1.14.0",
"puppeteer": "~1.14.0",
"serve-static": "^1.13.2",
"shx": "^0.3.2",
"sinon": "^7.3.2",
"sinon": "^7.2.7",
"terser-webpack-plugin": "^1.2.3",
"typescript": "^3.4.5",
"typescript": "^3.2.2",
"url-polyfill": "^1.1.5",
"walk": "^2.3.9",
"webpack": "4.31.0",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-dev-server": "^3.3.1",
"webpack": "4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-middleware": "^3.6.1",
"webpack-dev-server": "^3.2.1",
"yargs": "^13.2.2"
},
"eslintConfig": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -7,7 +7,6 @@ import Point from '../../../src/ol/geom/Point.js';
import Style from '../../../src/ol/style/Style.js';
import Text from '../../../src/ol/style/Text.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 LineString from '../../../src/ol/geom/LineString.js';
@@ -60,10 +59,9 @@ source1.addFeature(new Feature({
}));
layer1.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
image: new CircleStyle({
radius: 15,
fill: new Fill({
stroke: new Stroke({
color: 'blue'
})
})
@@ -71,7 +69,7 @@ layer1.setStyle(function(feature) {
});
map.addLayer(layer1);
center = [center[0] + 500, center[1] + 700];
center = [center[0] + 500, center[1] + 500];
const feature2 = new Feature({
geometry: new Point(center),
text: 'center',
@@ -90,16 +88,15 @@ source2.addFeature(new Feature({
}));
layer2.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
text: new Text({
text: feature.get('text'),
font: 'italic bold 18px Ubuntu'
font: '16px Ubuntu'
})
});
});
map.addLayer(layer2);
center = [center[0] + 500, center[1] + 300];
center = [center[0] + 500, center[1] + 500];
source3.addFeature(new Feature({
geometry: new Point(center),
text: 'center'
@@ -115,17 +112,16 @@ source3.addFeature(new Feature({
layer3.setStyle(function(feature) {
return new Style({
image: new CircleStyle({
radius: 10,
radius: 5,
stroke: new Stroke({
color: 'red',
width: 8
color: 'red'
})
}),
text: new Text({
text: feature.get('text'),
font: 'italic bold 18px Ubuntu',
font: '16px Ubuntu',
textBaseline: 'bottom',
offsetY: -12
offsetY: -5
})
});
});
@@ -134,12 +130,11 @@ map.addLayer(layer3);
center = [center[0] - 2000, center[1] - 2000];
const point = new Feature(new Point(center));
point.setStyle(new Style({
zIndex: 1,
zIndex: 2,
image: new CircleStyle({
radius: 8,
stroke: new Stroke({
color: 'blue',
width: 4
color: 'blue'
})
})
}));
@@ -148,7 +143,7 @@ const line = new Feature(new LineString([
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new Style({
zIndex: 2,
zIndex: 1,
stroke: new Stroke({
color: '#CCC',
width: 12
@@ -156,7 +151,7 @@ line.setStyle(new Style({
text: new Text({
placement: 'line',
text: 'east-west',
font: 'italic bold 18px Ubuntu',
font: '16px Ubuntu',
overflow: true
})
}));
@@ -164,4 +159,4 @@ source4.addFeature(point);
source4.addFeature(line);
map.addLayer(layer4);
render({tolerance: 0.007});
render({tolerance: 0.02});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 B

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -1,154 +1,55 @@
import Feature from '../../../src/ol/Feature.js';
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import VectorSource from '../../../src/ol/source/Vector.js';
import VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
import Feature from '../../../src/ol/Feature.js';
import Point from '../../../src/ol/geom/Point.js';
import Style from '../../../src/ol/style/Style.js';
import Text from '../../../src/ol/style/Text.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 VectorImageLayer from '../../../src/ol/layer/VectorImage.js';
import CircleStyle from '../../../src/ol/style/Circle.js';
import Point from '../../../src/ol/geom/Point.js';
import LineString from '../../../src/ol/geom/LineString.js';
import Text from '../../../src/ol/style/Text.js';
let center = [1825927.7316762917, 6143091.089223046];
const map = new Map({
pixelRatio: 1,
target: 'map',
view: new View({
center: center,
zoom: 13
})
});
const center = [1825927.7316762917, 6143091.089223046];
const source1 = new VectorSource();
const layer1 = new VectorImageLayer({
declutter: true,
source: source1
});
const source2 = new VectorSource();
const layer2 = new VectorImageLayer({
declutter: true,
source: source2
});
const source3 = new VectorSource();
const layer3 = new VectorImageLayer({
declutter: true,
source: source3
});
const source4 = new VectorSource();
const layer4 = new VectorImageLayer({
declutter: true,
source: source4
});
const feature1 = new Feature({
geometry: new Point(center),
zIndex: 2
});
source1.addFeature(feature1);
source1.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
zIndex: 3
}));
source1.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
zIndex: 1
}));
layer1.setStyle(function(feature) {
const source = new VectorSource();
const vectorLayer1 = new VectorImageLayer({
source: source,
style: function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
image: new CircleStyle({
radius: 15,
fill: new Fill({
color: 'blue'
})
})
});
});
map.addLayer(layer1);
center = [center[0] + 500, center[1] + 700];
const feature2 = new Feature({
geometry: new Point(center),
text: 'center',
zIndex: 2
});
source2.addFeature(feature2);
source2.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
text: 'west',
zIndex: 3
}));
source2.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
text: 'east',
zIndex: 1
}));
layer2.setStyle(function(feature) {
return new Style({
zIndex: feature.get('zIndex'),
text: new Text({
text: feature.get('text'),
font: 'italic bold 18px Ubuntu'
})
});
});
map.addLayer(layer2);
center = [center[0] + 500, center[1] + 300];
source3.addFeature(new Feature({
geometry: new Point(center),
text: 'center'
}));
source3.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
text: 'west'
}));
source3.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
text: 'east'
}));
layer3.setStyle(function(feature) {
return new Style({
image: new CircleStyle({
radius: 10,
stroke: new Stroke({
color: 'red',
width: 8
color: 'blue'
})
}),
text: new Text({
text: feature.get('text'),
font: 'italic bold 18px Ubuntu',
textBaseline: 'bottom',
offsetY: -12
font: '16px Ubuntu'
})
});
}
});
map.addLayer(layer3);
center = [center[0] - 2000, center[1] - 2000];
const point = new Feature(new Point(center));
point.setStyle(new Style({
zIndex: 1,
image: new CircleStyle({
radius: 8,
stroke: new Stroke({
color: 'blue',
width: 4
})
})
const centerFeature = new Feature({
geometry: new Point(center),
text: 'center'
});
source.addFeature(centerFeature);
source.addFeature(new Feature({
geometry: new Point([center[0] - 540, center[1]]),
text: 'west'
}));
source.addFeature(new Feature({
geometry: new Point([center[0] + 540, center[1]]),
text: 'east'
}));
const line = new Feature(new LineString([
[center[0] - 650, center[1] - 200],
[center[0] + 650, center[1] - 200]
]));
line.setStyle(new Style({
zIndex: 2,
stroke: new Stroke({
color: '#CCC',
width: 12
@@ -156,12 +57,23 @@ line.setStyle(new Style({
text: new Text({
placement: 'line',
text: 'east-west',
font: 'italic bold 18px Ubuntu',
overflow: true
font: '16px Ubuntu'
})
}));
source4.addFeature(point);
source4.addFeature(line);
map.addLayer(layer4);
source.addFeature(line);
render({tolerance: 0.007});
const map = new Map({
pixelRatio: 1,
layers: [
vectorLayer1
],
target: 'map',
view: new View({
center: center,
zoom: 13
})
});
map.getView().fit(source.getExtent());
render({tolerance: 0.02});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -4,10 +4,8 @@ import {Vector as VectorLayer, Tile as TileLayer} from '../../../src/ol/layer.js
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
import {Style, Stroke} from '../../../src/ol/style.js';
import Feature from '../../../src/ol/Feature.js';
import Point from '../../../src/ol/geom/Point.js';
const map = new Map({
new Map({
layers: [
new TileLayer({
source: new XYZ({
@@ -16,7 +14,6 @@ const map = new Map({
})
}),
new VectorLayer({
zIndex: 1,
style: new Style({
stroke: new Stroke({
color: 'rgba(255,255,255,0.5)',
@@ -36,11 +33,4 @@ const map = new Map({
})
});
const unmanaged = new VectorLayer({
source: new VectorSource({
features: [new Feature(new Point([0, 0]))]
})
});
unmanaged.setMap(map);
render();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 B

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -131,4 +131,4 @@ const map = new Map({
});
map.getView().fit(vectorSource.getExtent());
render({tolerance: 0.021});
render({tolerance: 0.02});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -103,4 +103,4 @@ const map = new Map({
});
map.getView().fit(vectorSource.getExtent());
render({tolerance: 0.024});
render({tolerance: 0.02});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 910 B

After

Width:  |  Height:  |  Size: 801 B

View File

@@ -39,7 +39,6 @@ import {create as createTransform, apply as applyTransform} from './transform.js
* @property {boolean} animate
* @property {import("./transform.js").Transform} coordinateToPixelTransform
* @property {null|import("./extent.js").Extent} extent
* @property {Array<*>} declutterItems
* @property {import("./coordinate.js").Coordinate} focus
* @property {number} index
* @property {Array<import("./layer/Layer.js").State>} layerStatesArray
@@ -1176,7 +1175,6 @@ class PluggableMap extends BaseObject {
frameState = /** @type {FrameState} */ ({
animate: false,
coordinateToPixelTransform: this.coordinateToPixelTransform_,
declutterItems: previousFrameState ? previousFrameState.declutterItems : [],
extent: extent,
focus: this.focus_ ? this.focus_ : viewState.center,
index: this.frameIndex_++,

View File

@@ -170,9 +170,6 @@ class Tile extends EventTarget {
// cleaned up by refreshInterimChain)
do {
if (tile.getState() == TileState.LOADED) {
// Show tile immediately instead of fading it in after loading, because
// the interim tile is in place already
this.transition_ = 0;
return tile;
}
tile = tile.interimTile;

View File

@@ -44,7 +44,7 @@ class TileCache extends LRUCache {
this.remove(getKey(tile.tileCoord));
tile.dispose();
}
}.bind(this));
}, this);
}
}

View File

@@ -191,11 +191,6 @@ const DEFAULT_MIN_ZOOM = 0;
* This is the object to act upon to change the center, resolution,
* and rotation of the map.
*
* A View has a `projection`. The projection determines the
* coordinate system of the center, and its units determine the units of the
* resolution (projection units per pixel). The default projection is
* Spherical Mercator (EPSG:3857).
*
* ### The view states
*
* An View is determined by three states: `center`, `resolution`,
@@ -207,6 +202,11 @@ const DEFAULT_MIN_ZOOM = 0;
* methods are available, as well as `getResolutionForZoom` and
* `getZoomForResolution` to switch from one system to the other.
*
* A View has a `projection`. The projection determines the
* coordinate system of the center, and its units determine the units of the
* resolution (projection units per pixel). The default projection is
* Spherical Mercator (EPSG:3857).
*
* ### The constraints
*
* `setCenter`, `setResolution` and `setRotation` can be used to change the
@@ -218,7 +218,7 @@ const DEFAULT_MIN_ZOOM = 0;
*
* The *resolution constraint* typically restricts min/max values and
* snaps to specific resolutions. It is determined by the following
* options: `resolutions`, `maxResolution`, `maxZoom` and `zoomFactor`.
* options: `resolutions`, `maxResolution`, `maxZoom`, and `zoomFactor`.
* If `resolutions` is set, the other three options are ignored. See
* documentation for each option for more information. By default, the view
* only has a min/max restriction and allow intermediary zoom levels when
@@ -226,7 +226,7 @@ const DEFAULT_MIN_ZOOM = 0;
*
* The *rotation constraint* snaps to specific angles. It is determined
* by the following options: `enableRotation` and `constrainRotation`.
* By default rotation is allowed and its value is snapped to zero when approaching the
* By default the rotation value is snapped to zero when approaching the
* horizontal.
*
* The *center constraint* is determined by the `extent` option. By
@@ -284,6 +284,8 @@ class View extends BaseObject {
*/
this.updateAnimationKey_;
this.updateAnimations_ = this.updateAnimations_.bind(this);
/**
* @private
* @const
@@ -450,17 +452,6 @@ class View extends BaseObject {
* @api
*/
animate(var_args) {
if (this.isDef() && !this.getAnimating()) {
this.resolveConstraints(0);
}
this.animate_.apply(this, arguments);
}
/**
* @private
* @param {...(AnimationOptions|function(boolean): void)} var_args Animation options.
*/
animate_(var_args) {
let animationCount = arguments.length;
let callback;
if (animationCount > 1 && typeof arguments[animationCount - 1] === 'function') {
@@ -650,7 +641,11 @@ class View extends BaseObject {
// prune completed series
this.animations_ = this.animations_.filter(Boolean);
if (more && this.updateAnimationKey_ === undefined) {
this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_.bind(this));
this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);
}
if (!this.getAnimating()) {
setTimeout(this.resolveConstraints.bind(this), 0);
}
}
@@ -934,9 +929,13 @@ class View extends BaseObject {
const center = /** @type {import("./coordinate.js").Coordinate} */ (this.getCenter());
const projection = this.getProjection();
const resolution = /** @type {number} */ (this.getResolution());
const pixelResolution = resolution / pixelRatio;
const rotation = this.getRotation();
return {
center: center.slice(0),
center: [
Math.round(center[0] / pixelResolution) * pixelResolution,
Math.round(center[1] / pixelResolution) * pixelResolution
],
projection: projection !== undefined ? projection : null,
resolution: resolution,
rotation: rotation,
@@ -1086,7 +1085,7 @@ class View extends BaseObject {
const callback = options.callback ? options.callback : VOID;
if (options.duration !== undefined) {
this.animate_({
this.animate({
resolution: resolution,
center: this.getConstrainedCenter(center, resolution),
duration: options.duration,
@@ -1313,7 +1312,7 @@ class View extends BaseObject {
this.cancelAnimations();
}
this.animate_({
this.animate({
rotation: newRotation,
center: newCenter,
resolution: newResolution,
@@ -1326,13 +1325,9 @@ class View extends BaseObject {
/**
* Notify the View that an interaction has started.
* The view state will be resolved to a stable one if needed
* (depending on its constraints).
* @api
*/
beginInteraction() {
this.resolveConstraints(0);
this.setHint(ViewHint.INTERACTING, 1);
}

View File

@@ -400,25 +400,26 @@ export function extendXY(extent, x, y) {
* callback returns a truthy value the function returns that value
* immediately. Otherwise the function returns `false`.
* @param {Extent} extent Extent.
* @param {function(import("./coordinate.js").Coordinate): S} callback Callback.
* @param {function(this:T, import("./coordinate.js").Coordinate): S} callback Callback.
* @param {T=} opt_this Value to use as `this` when executing `callback`.
* @return {S|boolean} Value.
* @template S
* @template S, T
*/
export function forEachCorner(extent, callback) {
export function forEachCorner(extent, callback, opt_this) {
let val;
val = callback(getBottomLeft(extent));
val = callback.call(opt_this, getBottomLeft(extent));
if (val) {
return val;
}
val = callback(getBottomRight(extent));
val = callback.call(opt_this, getBottomRight(extent));
if (val) {
return val;
}
val = callback(getTopRight(extent));
val = callback.call(opt_this, getTopRight(extent));
if (val) {
return val;
}
val = callback(getTopLeft(extent));
val = callback.call(opt_this, getTopLeft(extent));
if (val) {
return val;
}

View File

@@ -7,7 +7,6 @@ export {default as GeoJSON} from './format/GeoJSON.js';
export {default as GML} from './format/GML.js';
export {default as GPX} from './format/GPX.js';
export {default as IGC} from './format/IGC.js';
export {default as IIIFInfo} from './format/IIIFInfo.js';
export {default as KML} from './format/KML.js';
export {default as MVT} from './format/MVT.js';
export {default as OWS} from './format/OWS.js';

View File

@@ -1,426 +0,0 @@
/**
* @module ol/format/IIIFInfo
*/
import {assert} from '../asserts.js';
/**
* @typedef {Object} PreferredOptions
* @property {string} [format] Preferred image format. Will be used if the image information
* indicates support for that format.
* @property {string} [quality] IIIF image qualitiy. Will be used if the image information
* indicates support for that quality.
*/
/**
* @typedef {Object} SupportedFeatures
* @property {Array<string>} [supports] Supported IIIF image size and region
* calculation features.
* @property {Array<string>} [formats] Supported image formats.
* @property {Array<string>} [qualities] Supported IIIF image qualities.
*/
/**
* @typedef {Object} ImageInformationResponse1_0
* @property {string} identifier
* @property {number} width
* @property {number} height
* @property {Array<number>} [scale_factors] Resolution scaling factors.
* @property {number} [tile_width]
* @property {number} [tile_height]
* @property {Array<string>} [formats] Supported image formats.
* @property {string} [profile] Compliance level URI.
*/
/**
* @typedef {Object} ImageInformationResponse1_1
* @property {string} "@id" The base URI of the image service.
* @property {string} "@context" JSON-LD context URI.
* @property {number} width Full image width.
* @property {number} height Full image height.
* @property {Array<number>} [scale_factors] Resolution scaling factors.
* @property {number} [tile_width]
* @property {number} [tile_height]
* @property {Array<string>} [formats] Supported image formats.
* @property {string} [profile] Compliance level URI.
*/
/**
* @typedef {Object} TileInfo
* @property {Array<number>} scaleFactors Supported resolution scaling factors.
* @property {number} width Tile width in pixels.
* @property {number} [height] Tile height in pixels. Same as tile width if height is
* not given.
*/
/**
* @typedef {Object} IiifProfile
* @property {Array<string>} [formats] Supported image formats for the image service.
* @property {Array<string>} [qualities] Supported IIIF image qualities.
* @property {Array<string>} [supports] Supported features.
* @property {number} [maxArea] Maximum area (pixels) available for this image service.
* @property {number} [maxHeight] Maximum height.
* @property {number} [maxWidth] Maximum width.
*/
/**
* @typedef {Object} ImageInformationResponse2
* @property {string} "@id" The base URI of the image service.
* @property {string} "@context" JSON-LD context IRI
* @property {number} width Full image width.
* @property {number} height Full image height.
* @property {Array<string|IiifProfile>} profile Additional informations about the image
* service's capabilities.
* @property {Array<Object<string, number>>} [sizes] Supported full image dimensions.
* @property {Array<TileInfo>} [tiles] Supported tile sizes and resolution scaling factors.
*/
/**
* @typedef {Object} ImageInformationResponse3
* @property {string} id The base URI of the image service.
* @property {string} "@context" JSON-LD context IRI
* @property {number} width Full image width.
* @property {number} height Full image height.
* @property {string} profile Compliance level, one of 'level0', 'level1' or 'level2'
* @property {Array<Object<string, number>>} [sizes] Supported full image dimensions.
* @property {Array<TileInfo>} [tiles] Supported tile sizes and resolution scaling factors.
* @property {number} [maxArea] Maximum area (pixels) available for this image service.
* @property {number} [maxHeight] Maximum height.
* @property {number} [maxWidth] Maximum width.
* @property {Array<string>} [extraQualities] IIIF image qualities supported by the
* image service additional to the ones indicated by the compliance level.
* @property {Array<string>} [extraFormats] Image formats supported by the
* image service additional to the ones indicated by the compliance level.
* @property {Array<string>} [extraFeatures] Additional supported features whose support
* is not indicated by the compliance level.
*/
/**
* @enum {string}
*/
export const Versions = {
VERSION1: 'version1',
VERSION2: 'version2',
VERSION3: 'version3'
};
/**
* Supported image formats, qualities and supported region / size calculation features
* for different image API versions and compliance levels
* @const
* @type {Object<string, Object<string, SupportedFeatures>>}
*/
const IIIF_PROFILE_VALUES = {};
IIIF_PROFILE_VALUES[Versions.VERSION1] = {
'level0': {
supports: [],
formats: [],
qualities: ['native']
},
'level1': {
supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
formats: ['jpg'],
qualities: ['native']
},
'level2': {
supports: ['regionByPx', 'regionByPct', 'sizeByW', 'sizeByH', 'sizeByPct',
'sizeByConfinedWh', 'sizeByWh'],
formats: ['jpg', 'png'],
qualities: ['native', 'color', 'grey', 'bitonal']
}
};
IIIF_PROFILE_VALUES[Versions.VERSION2] = {
'level0': {
supports: [],
formats: ['jpg'],
qualities: ['default']
},
'level1': {
supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
formats: ['jpg'],
qualities: ['default']
},
'level2': {
supports: ['regionByPx', 'regionByPct', 'sizeByW', 'sizeByH', 'sizeByPct',
'sizeByConfinedWh', 'sizeByDistortedWh', 'sizeByWh'],
formats: ['jpg', 'png'],
qualities: ['default', 'bitonal']
}
};
IIIF_PROFILE_VALUES[Versions.VERSION3] = {
'level0': {
supports: [],
formats: ['jpg'],
qualities: ['default']
},
'level1': {
supports: ['regionByPx', 'regionSquare', 'sizeByW', 'sizeByH'],
formats: ['jpg'],
qualities: ['default']
},
'level2': {
supports: ['regionByPx', 'regionSquare', 'regionByPct',
'sizeByW', 'sizeByH', 'sizeByPct', 'sizeByConfinedWh', 'sizeByWh'],
formats: ['jpg'],
qualities: ['default', 'bitonal']
}
};
IIIF_PROFILE_VALUES['none'] = {
'none': {
supports: [],
formats: [],
qualities: []
}
};
const COMPLIANCE_VERSION1 = new RegExp('^https?\:\/\/library\.stanford\.edu\/iiif\/image-api\/(1\.1\/)?compliance\.html#level[0-2]$');
const COMPLIANCE_VERSION2 = new RegExp('^https?\:\/\/iiif\.io\/api\/image\/2\/level[0-2](\.json)?$');
const COMPLIANCE_VERSION3 = new RegExp('(^https?\:\/\/iiif\.io\/api\/image\/3\/level[0-2](\.json)?$)|(^level[0-2]$)');
function generateVersion1Options(iiifInfo) {
let levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
// Version 1.0 and 1.1 do not require a profile.
if (levelProfile === undefined) {
levelProfile = IIIF_PROFILE_VALUES[Versions.VERSION1]['level0'];
}
return {
url: iiifInfo.imageInfo['@id'] === undefined ? undefined : iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
supports: levelProfile.supports,
formats: [...levelProfile.formats, iiifInfo.imageInfo.formats === undefined ?
[] : iiifInfo.imageInfo.formats
],
qualities: [...levelProfile.qualities, iiifInfo.imageInfo.qualities === undefined ?
[] : iiifInfo.imageInfo.qualities
],
resolutions: iiifInfo.imageInfo.scale_factors,
tileSize: iiifInfo.imageInfo.tile_width !== undefined ? (iiifInfo.imageInfo.tile_height !== undefined ?
[iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_height] : [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_width]) :
(iiifInfo.imageInfo.tile_height != undefined ? [iiifInfo.imageInfo.tile_height, iiifInfo.imageInfo.tile_height] : undefined)
};
}
function generateVersion2Options(iiifInfo) {
const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
additionalProfile = Array.isArray(iiifInfo.imageInfo.profile) && iiifInfo.imageInfo.profile.length > 1,
profileSupports = additionalProfile && iiifInfo.imageInfo.profile[1].supports ? iiifInfo.imageInfo.profile[1].supports : [],
profileFormats = additionalProfile && iiifInfo.imageInfo.profile[1].formats ? iiifInfo.imageInfo.profile[1].formats : [],
profileQualities = additionalProfile && iiifInfo.imageInfo.profile[1].qualities ? iiifInfo.imageInfo.profile[1].qualities : [];
return {
url: iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
sizes: iiifInfo.imageInfo.sizes === undefined ? undefined : iiifInfo.imageInfo.sizes.map(function(size) {
return [size.width, size.height];
}),
tileSize: iiifInfo.imageInfo.tiles === undefined ? undefined : [
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.width;
})[0],
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.height === undefined ? tile.width : tile.height;
})[0]
],
resolutions: iiifInfo.imageInfo.tiles === undefined ? undefined :
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.scaleFactors;
})[0],
supports: [...levelProfile.supports, ...profileSupports],
formats: [...levelProfile.formats, ...profileFormats],
qualities: [...levelProfile.qualities, ...profileQualities]
};
}
function generateVersion3Options(iiifInfo) {
const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
return {
url: iiifInfo.imageInfo['id'],
sizes: iiifInfo.imageInfo.sizes === undefined ? undefined : iiifInfo.imageInfo.sizes.map(function(size) {
return [size.width, size.height];
}),
tileSize: iiifInfo.imageInfo.tiles === undefined ? undefined : [
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.width;
})[0],
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.height;
})[0]
],
resolutions: iiifInfo.imageInfo.tiles === undefined ? undefined :
iiifInfo.imageInfo.tiles.map(function(tile) {
return tile.scaleFactors;
})[0],
supports: iiifInfo.imageInfo.extraFeatures === undefined ? levelProfile.supports :
[...levelProfile.supports, ...iiifInfo.imageInfo.extraFeatures],
formats: iiifInfo.imageInfo.extraFormats === undefined ? levelProfile.formats :
[...levelProfile.formats, ...iiifInfo.imageInfo.extraFormats],
qualities: iiifInfo.imageInfo.extraQualities === undefined ? levelProfile.qualities :
[...levelProfile.supports, ...iiifInfo.imageInfo.extraQualities],
maxWidth: undefined,
maxHeight: undefined,
maxArea: undefined
};
}
const versionFunctions = {};
versionFunctions[Versions.VERSION1] = generateVersion1Options;
versionFunctions[Versions.VERSION2] = generateVersion2Options;
versionFunctions[Versions.VERSION3] = generateVersion3Options;
/**
* @classdesc
* Format for transforming IIIF Image API image information responses into
* IIIF tile source ready options
*
* @api
*/
class IIIFInfo {
/**
* @param {ImageInformationResponse1_0|ImageInformationResponse1_1|ImageInformationResponse2|ImageInformationResponse3|string} imageInfo
* Deserialized image information JSON response object or JSON response as string
*/
constructor(imageInfo) {
this.setImageInfo(imageInfo);
}
/**
* @param {Object|string} imageInfo Deserialized image information JSON response
* object or JSON response as string
*/
setImageInfo(imageInfo) {
if (typeof imageInfo == 'string') {
this.imageInfo = JSON.parse(imageInfo);
} else {
this.imageInfo = imageInfo;
}
}
/**
* @returns {Versions} Major IIIF version.
*/
getImageApiVersion() {
if (this.imageInfo === undefined) {
return;
}
let context = this.imageInfo['@context'] || 'ol-no-context';
if (typeof context == 'string') {
context = [context];
}
for (let i = 0; i < context.length; i++) {
switch (context[i]) {
case 'http://library.stanford.edu/iiif/image-api/1.1/context.json':
case 'http://iiif.io/api/image/1/context.json':
return Versions.VERSION1;
case 'http://iiif.io/api/image/2/context.json':
return Versions.VERSION2;
case 'http://iiif.io/api/image/3/context.json':
return Versions.VERSION3;
case 'ol-no-context':
// Image API 1.0 has no '@context'
if (this.getComplianceLevelEntryFromProfile(Versions.VERSION1) && this.imageInfo.identifier) {
return Versions.VERSION1;
}
break;
default:
}
}
assert(false, 61);
}
/**
* @param {Versions} version Optional IIIF image API version
* @returns {string} Compliance level as it appears in the IIIF image information
* response.
*/
getComplianceLevelEntryFromProfile(version) {
if (this.imageInfo === undefined || this.imageInfo.profile === undefined) {
return;
}
if (version === undefined) {
version = this.getImageApiVersion();
}
switch (version) {
case Versions.VERSION1:
if (COMPLIANCE_VERSION1.test(this.imageInfo.profile)) {
return this.imageInfo.profile;
}
break;
case Versions.VERSION3:
if (COMPLIANCE_VERSION3.test(this.imageInfo.profile)) {
return this.imageInfo.profile;
}
break;
case Versions.VERSION2:
if (typeof this.imageInfo.profile === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile)) {
return this.imageInfo.profile;
}
if (Array.isArray(this.imageInfo.profile) && this.imageInfo.profile.length > 0
&& typeof this.imageInfo.profile[0] === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile[0])) {
return this.imageInfo.profile[0];
}
break;
default:
}
}
/**
* @param {Versions} version Optional IIIF image API version
* @returns {string} Compliance level, on of 'level0', 'level1' or 'level2' or undefined
*/
getComplianceLevelFromProfile(version) {
const complianceLevel = this.getComplianceLevelEntryFromProfile(version);
if (complianceLevel === undefined) {
return undefined;
}
const level = complianceLevel.match(/level[0-2](\.json)?$/g);
return Array.isArray(level) ? level[0].replace('.json', '') : undefined;
}
/**
* @returns {SupportedFeatures} Image formats, qualities and region / size calculation
* methods that are supported by the IIIF service.
*/
getComplianceLevelSupportedFeatures() {
if (this.imageInfo === undefined) {
return;
}
const version = this.getImageApiVersion();
const level = this.getComplianceLevelFromProfile(version);
if (level === undefined) {
return IIIF_PROFILE_VALUES['none']['none'];
}
return IIIF_PROFILE_VALUES[version][level];
}
/**
* @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality.
* @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
*/
getTileSourceOptions(opt_preferredOptions) {
const options = opt_preferredOptions || {},
version = this.getImageApiVersion();
if (version === undefined) {
return;
}
const imageOptions = version === undefined ? undefined : versionFunctions[version](this);
if (imageOptions === undefined) {
return;
}
return {
url: imageOptions.url,
version: version,
size: [this.imageInfo.width, this.imageInfo.height],
sizes: imageOptions.sizes,
format: imageOptions.formats.includes(options.format) ? options.format : 'jpg',
supports: imageOptions.supports,
quality: options.quality && imageOptions.qualities.includes(options.quality) ?
options.quality : imageOptions.qualities.includes('native') ? 'native' : 'default',
resolutions: Array.isArray(imageOptions.resolutions) ? imageOptions.resolutions.sort(function(a, b) {
return b - a;
}) : undefined,
tileSize: imageOptions.tileSize
};
}
}
export default IIIFInfo;

View File

@@ -4,7 +4,6 @@
export {default as Circle} from './geom/Circle.js';
export {default as Geometry} from './geom/Geometry.js';
export {default as GeometryCollection} from './geom/GeometryCollection.js';
export {default as LineString} from './geom/LineString.js';
export {default as MultiLineString} from './geom/MultiLineString.js';
export {default as MultiPoint} from './geom/MultiPoint.js';

View File

@@ -5,8 +5,6 @@ import {createOrUpdate, forEachCorner, intersects} from '../extent.js';
import GeometryType from './GeometryType.js';
import SimpleGeometry from './SimpleGeometry.js';
import {deflateCoordinate} from './flat/deflate.js';
import {rotate, translate} from './flat/transform.js';
/**
* @classdesc
@@ -145,7 +143,7 @@ class Circle extends SimpleGeometry {
return true;
}
return forEachCorner(extent, this.intersectsCoordinate.bind(this));
return forEachCorner(extent, this.intersectsCoordinate, this);
}
return false;
@@ -214,29 +212,6 @@ class Circle extends SimpleGeometry {
this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
this.changed();
}
/**
* @inheritDoc
* @api
*/
rotate(angle, anchor) {
const center = this.getCenter();
const stride = this.getStride();
this.setCenter(rotate(center, 0, center.length, stride, angle, anchor, center));
this.changed();
}
/**
* @inheritDoc
* @api
*/
translate(deltaX, deltaY) {
const center = this.getCenter();
const stride = this.getStride();
this.setCenter(translate(center, 0, center.length, stride, deltaX, deltaY, center));
this.changed();
}
}

View File

@@ -73,10 +73,6 @@ class DragPan extends PointerInteraction {
* @inheritDoc
*/
handleDragEvent(mapBrowserEvent) {
if (!this.panning_) {
this.panning_ = true;
this.getMap().getView().beginInteraction();
}
const targetPointers = this.targetPointers;
const centroid = centroidFromPointers(targetPointers);
if (targetPointers.length == this.lastPointersCount_) {
@@ -153,6 +149,10 @@ class DragPan extends PointerInteraction {
if (view.getAnimating()) {
view.cancelAnimations();
}
if (!this.panning_) {
this.panning_ = true;
this.getMap().getView().beginInteraction();
}
if (this.kinetic_) {
this.kinetic_.begin();
}

View File

@@ -38,7 +38,7 @@ import {createEditingStyle} from '../style/Style.js';
const ExtentEventType = {
/**
* Triggered after the extent is changed
* @event ExtentEvent#extentchanged
* @event ExtentEventType#extentchanged
* @api
*/
EXTENTCHANGED: 'extentchanged'
@@ -47,10 +47,10 @@ const ExtentEventType = {
/**
* @classdesc
* Events emitted by {@link module:ol/interaction/Extent~Extent} instances are
* Events emitted by {@link module:ol/interaction/Extent~ExtentInteraction} instances are
* instances of this type.
*/
class ExtentEvent extends Event {
class ExtentInteractionEvent extends Event {
/**
* @param {import("../extent.js").Extent} extent the new extent
@@ -75,10 +75,10 @@ class ExtentEvent extends Event {
* Once drawn, the vector box can be modified by dragging its vertices or edges.
* This interaction is only supported for mouse devices.
*
* @fires ExtentEvent
* @fires Event
* @api
*/
class Extent extends PointerInteraction {
class ExtentInteraction extends PointerInteraction {
/**
* @param {Options=} opt_options Options.
*/
@@ -399,7 +399,7 @@ class Extent extends PointerInteraction {
//Null extent means no bbox
this.extent_ = extent ? extent : null;
this.createOrUpdateExtentFeature_(extent);
this.dispatchEvent(new ExtentEvent(this.extent_));
this.dispatchEvent(new ExtentInteractionEvent(this.extent_));
}
}
@@ -470,4 +470,4 @@ function getSegments(extent) {
}
export default Extent;
export default ExtentInteraction;

View File

@@ -111,7 +111,7 @@ export function pan(view, delta, opt_duration) {
const currentCenter = view.getCenter();
if (currentCenter) {
const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]];
view.animate_({
view.animate({
duration: opt_duration !== undefined ? opt_duration : 250,
easing: linear,
center: view.getConstrainedCenter(center)

View File

@@ -8,6 +8,13 @@ import Interaction, {zoomByDelta} from './Interaction.js';
import {clamp} from '../math.js';
/**
* Maximum mouse wheel delta.
* @type {number}
*/
const MAX_DELTA = 1;
/**
* @enum {string}
*/
@@ -23,7 +30,6 @@ export const Mode = {
* takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
* boolean to indicate whether that event should be handled. Default is
* {@link module:ol/events/condition~always}.
* @property {number} [maxDelta=1] Maximum mouse wheel delta.
* @property {number} [duration=250] Animation duration in milliseconds.
* @property {number} [timeout=80] Mouse wheel timeout duration in milliseconds.
* @property {boolean} [useAnchor=true] Enable zooming using the mouse's
@@ -59,12 +65,6 @@ class MouseWheelZoom extends Interaction {
*/
this.lastDelta_ = 0;
/**
* @private
* @type {number}
*/
this.maxDelta_ = options.maxDelta !== undefined ? options.maxDelta : 1;
/**
* @private
* @type {number}
@@ -235,7 +235,8 @@ class MouseWheelZoom extends Interaction {
if (view.getAnimating()) {
view.cancelAnimations();
}
const delta = clamp(this.totalDelta_, -this.maxDelta_, this.maxDelta_);
const maxDelta = MAX_DELTA;
const delta = clamp(this.totalDelta_, -maxDelta, maxDelta);
zoomByDelta(view, -delta, this.lastAnchor_, this.duration_);
this.mode_ = undefined;
this.totalDelta_ = 0;

View File

@@ -83,20 +83,19 @@ class BaseLayer extends BaseObject {
}
/**
* @param {boolean=} opt_managed Layer is managed.
* @return {import("./Layer.js").State} Layer state.
*/
getLayerState(opt_managed) {
getLayerState() {
/** @type {import("./Layer.js").State} */
const state = this.state_ || /** @type {?} */ ({
layer: this,
managed: opt_managed === undefined ? true : opt_managed
managed: true
});
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
state.sourceState = this.getSourceState();
state.visible = this.getVisible();
state.extent = this.getExtent();
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
state.zIndex = this.getZIndex() || 0;
state.maxResolution = this.getMaxResolution();
state.minResolution = Math.max(this.getMinResolution(), 0);
this.state_ = state;

View File

@@ -8,7 +8,6 @@ import {assign} from '../obj.js';
/**
* @typedef {Object} Options
* @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
* @property {number} [opacity=1] Opacity (0, 1).
* @property {boolean} [visible=true] Visibility.
* @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be

View File

@@ -32,10 +32,8 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
* use {@link module:ol/Map#addLayer}.
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
* higher priority.
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
* means higher priority.
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will

View File

@@ -27,6 +27,7 @@ import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer';
* of the heatmap, specified as an array of CSS color strings.
* @property {number} [radius=8] Radius size in pixels.
* @property {number} [blur=15] Blur size in pixels.
* @property {number} [shadow=250] Shadow size in pixels.
* @property {string|function(import("../Feature.js").default):number} [weight='weight'] The feature
* attribute to use for the weight or a function that returns a weight from a feature. Weight values
* should range from 0 to 1 (and values outside will be clamped to that range).
@@ -74,6 +75,7 @@ class Heatmap extends VectorLayer {
delete baseOptions.gradient;
delete baseOptions.radius;
delete baseOptions.blur;
delete baseOptions.shadow;
delete baseOptions.weight;
super(baseOptions);
@@ -83,6 +85,24 @@ class Heatmap extends VectorLayer {
*/
this.gradient_ = null;
/**
* @private
* @type {number}
*/
this.shadow_ = options.shadow !== undefined ? options.shadow : 250;
/**
* @private
* @type {string|undefined}
*/
this.circleImage_ = undefined;
/**
* @private
* @type {Array<Array<import("../style/Style.js").default>>}
*/
this.styleCache_ = null;
listen(this,
getChangeEventType(Property.GRADIENT),
this.handleGradientChanged_, this);
@@ -218,7 +238,7 @@ class Heatmap extends VectorLayer {
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
float alpha = smoothstep(0.0, 1.0, value) * v_opacity;
gl_FragColor = vec4(alpha, alpha, alpha, alpha);
gl_FragColor = vec4(1.0, 1.0, 1.0, alpha);
}`,
uniforms: {
u_size: function() {
@@ -253,7 +273,9 @@ class Heatmap extends VectorLayer {
}
}
],
opacityCallback: this.weightFunction_
opacityCallback: function(feature) {
return this.weightFunction_(feature);
}.bind(this)
});
}
}

View File

@@ -212,7 +212,12 @@ class Layer extends BaseLayer {
if (map) {
this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
renderEvent.frameState.layerStatesArray.push(this.getLayerState(false));
const layerState = this.getLayerState();
layerState.managed = false;
if (this.getZIndex() === undefined) {
layerState.zIndex = Infinity;
}
renderEvent.frameState.layerStatesArray.push(layerState);
}, this);
this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
this.changed();

View File

@@ -30,9 +30,9 @@ import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
* use {@link module:ol/Map#addLayer}.
* @property {boolean} [declutter=false] Declutter images and text on this layer. The priority is defined
* by the `zIndex` of the style and the render order of features. Higher z-index means higher priority.
* Within the same z-index, a feature rendered before another has higher priority.
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
* means higher priority.
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will

View File

@@ -46,10 +46,8 @@ import {assign} from '../obj.js';
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
* use {@link module:ol/Map#addLayer}.
* @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all
* image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority
* is defined by the z-index of the layer, the `zIndex` of the style and the render order of features.
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
* higher priority.
* image and text styles, and the priority is defined by the z-index of the style. Lower z-index
* means higher priority.
* @property {import("../style/Style.js").StyleLike} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be

View File

@@ -110,23 +110,3 @@ export function getRenderPixel(event, pixel) {
applyTransform(event.inversePixelTransform.slice(), result);
return result;
}
/**
* @param {import("./PluggableMap.js").FrameState} frameState Frame state.
* @param {?} declutterTree Declutter tree.
* @returns {?} Declutter tree.
*/
export function renderDeclutterItems(frameState, declutterTree) {
if (declutterTree) {
declutterTree.clear();
}
const items = frameState.declutterItems;
for (let z = items.length - 1; z >= 0; --z) {
const zIndexItems = items[z];
for (let i = 0, ii = zIndexItems.length; i < ii; i += 3) {
declutterTree = zIndexItems[i].renderDeclutter(zIndexItems[i + 1], zIndexItems[i + 2], declutterTree);
}
}
items.length = 0;
return declutterTree;
}

View File

@@ -21,7 +21,6 @@ import {
import {createCanvasContext2D} from '../../dom.js';
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
import Disposable from '../../Disposable.js';
import rbush from 'rbush';
/**
@@ -59,10 +58,15 @@ class Executor extends Disposable {
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The replay can have overlapping geometries.
* @param {?} declutterTree Declutter tree.
* @param {SerializableInstructions} instructions The serializable instructions
*/
constructor(resolution, pixelRatio, overlaps, instructions) {
constructor(resolution, pixelRatio, overlaps, declutterTree, instructions) {
super();
/**
* @type {?}
*/
this.declutterTree = declutterTree;
/**
* @protected
@@ -89,11 +93,6 @@ class Executor extends Disposable {
*/
this.alignFill_;
/**
* @type {Array<*>}
*/
this.declutterItems = [];
/**
* @protected
* @type {Array<*>}
@@ -413,10 +412,8 @@ class Executor extends Disposable {
/**
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
* @param {import("../../Feature.js").FeatureLike} feature Feature.
* @param {?} declutterTree Declutter tree.
* @return {?} Declutter tree.
*/
renderDeclutter(declutterGroup, feature, declutterTree) {
renderDeclutter_(declutterGroup, feature) {
if (declutterGroup && declutterGroup.length > 5) {
const groupCount = declutterGroup[4];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
@@ -428,11 +425,8 @@ class Executor extends Disposable {
maxY: /** @type {number} */ (declutterGroup[3]),
value: feature
};
if (!declutterTree) {
declutterTree = rbush(9, undefined);
}
if (!declutterTree.collides(box)) {
declutterTree.insert(box);
if (!this.declutterTree.collides(box)) {
this.declutterTree.insert(box);
for (let j = 5, jj = declutterGroup.length; j < jj; ++j) {
const declutterData = /** @type {Array} */ (declutterGroup[j]);
if (declutterData) {
@@ -449,7 +443,6 @@ class Executor extends Disposable {
createOrUpdateEmpty(declutterGroup);
}
}
return declutterTree;
}
/**
@@ -504,7 +497,6 @@ class Executor extends Disposable {
featureCallback,
opt_hitExtent
) {
this.declutterItems.length = 0;
/** @type {Array<number>} */
let pixelCoordinates;
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
@@ -678,7 +670,7 @@ class Executor extends Disposable {
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
}
this.declutterItems.push(this, declutterGroup, feature);
this.renderDeclutter_(declutterGroup, feature);
++i;
break;
case CanvasInstruction.DRAW_CHARS:
@@ -747,7 +739,7 @@ class Executor extends Disposable {
}
}
}
this.declutterItems.push(this, declutterGroup, feature);
this.renderDeclutter_(declutterGroup, feature);
++i;
break;
case CanvasInstruction.END_GEOMETRY:

View File

@@ -35,12 +35,18 @@ class ExecutorGroup extends Disposable {
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {boolean} overlaps The executor group can have overlapping geometries.
* @param {?} declutterTree Declutter tree for declutter processing in postrender.
* @param {!Object<string, !Object<BuilderType, import("./Builder.js").SerializableInstructions>>} allInstructions
* The serializable instructions.
* @param {number=} opt_renderBuffer Optional rendering buffer.
*/
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, allInstructions, opt_renderBuffer) {
super();
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = declutterTree;
/**
* @private
@@ -122,7 +128,7 @@ class ExecutorGroup extends Disposable {
for (const builderType in instructionByZindex) {
const instructions = instructionByZindex[builderType];
executors[builderType] = new Executor(
this.resolution_, this.pixelRatio_, this.overlaps_, instructions);
this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_, instructions);
}
}
}
@@ -166,7 +172,7 @@ class ExecutorGroup extends Disposable {
* @param {number} hitTolerance Hit tolerance in pixels.
* @param {Object<string, boolean>} skippedFeaturesHash Ids of features to skip.
* @param {function(import("../../Feature.js").FeatureLike): T} callback Feature callback.
* @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @param {Object<string, import("../canvas.js").DeclutterGroup>} declutterReplays Declutter replays.
* @return {T|undefined} Callback result.
* @template T
*/
@@ -177,7 +183,7 @@ class ExecutorGroup extends Disposable {
hitTolerance,
skippedFeaturesHash,
callback,
declutteredFeatures
declutterReplays
) {
hitTolerance = Math.round(hitTolerance);
@@ -207,6 +213,12 @@ class ExecutorGroup extends Disposable {
}
const mask = getCircleArray(hitTolerance);
let declutteredFeatures;
if (this.declutterTree_) {
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
return entry.value;
});
}
let builderType;
@@ -249,6 +261,15 @@ class ExecutorGroup extends Disposable {
builderType = ORDER[j];
executor = executors[builderType];
if (executor !== undefined) {
if (declutterReplays &&
(builderType == BuilderType.IMAGE || builderType == BuilderType.TEXT)) {
const declutter = declutterReplays[zIndexKey];
if (!declutter) {
declutterReplays[zIndexKey] = [executor, transform.slice(0)];
} else {
declutter.push(executor, transform.slice(0));
}
} else {
result = executor.executeHitDetection(context, transform, rotation,
skippedFeaturesHash, featureCallback, hitExtent);
if (result) {
@@ -257,6 +278,7 @@ class ExecutorGroup extends Disposable {
}
}
}
}
return undefined;
}
@@ -424,20 +446,14 @@ export function getCircleArray(radius) {
* @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation.
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
* @param {Array<Array<*>>} declutterItems Declutter items.
*/
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel, declutterItems) {
export function replayDeclutter(declutterReplays, context, rotation, snapToPixel) {
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
const skippedFeatureUids = {};
for (let z = 0, zz = zs.length; z < zz; ++z) {
const executorData = declutterReplays[zs[z].toString()];
let currentExecutor;
for (let i = 0, ii = executorData.length; i < ii;) {
const executor = executorData[i++];
if (executor !== currentExecutor) {
currentExecutor = executor;
declutterItems.push(executor.declutterItems);
}
const transform = executorData[i++];
executor.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
}

102
src/ol/render/webgl.js Normal file
View File

@@ -0,0 +1,102 @@
/**
* @module ol/render/webgl
*/
/**
* @const
* @type {string}
*/
export const DEFAULT_FONT = '10px sans-serif';
/**
* @const
* @type {import("../color.js").Color}
*/
export const DEFAULT_FILLSTYLE = [0.0, 0.0, 0.0, 1.0];
/**
* @const
* @type {string}
*/
export const DEFAULT_LINECAP = 'round';
/**
* @const
* @type {Array<number>}
*/
export const DEFAULT_LINEDASH = [];
/**
* @const
* @type {number}
*/
export const DEFAULT_LINEDASHOFFSET = 0;
/**
* @const
* @type {string}
*/
export const DEFAULT_LINEJOIN = 'round';
/**
* @const
* @type {number}
*/
export const DEFAULT_MITERLIMIT = 10;
/**
* @const
* @type {import("../color.js").Color}
*/
export const DEFAULT_STROKESTYLE = [0.0, 0.0, 0.0, 1.0];
/**
* @const
* @type {number}
*/
export const DEFAULT_TEXTALIGN = 0.5;
/**
* @const
* @type {number}
*/
export const DEFAULT_TEXTBASELINE = 0.5;
/**
* @const
* @type {number}
*/
export const DEFAULT_LINEWIDTH = 1;
/**
* @const
* @type {number}
*/
export const EPSILON = Number.EPSILON || 2.220446049250313e-16;
/**
* Calculates the orientation of a triangle based on the determinant method.
* @param {number} x1 First X coordinate.
* @param {number} y1 First Y coordinate.
* @param {number} x2 Second X coordinate.
* @param {number} y2 Second Y coordinate.
* @param {number} x3 Third X coordinate.
* @param {number} y3 Third Y coordinate.
* @return {boolean|undefined} Triangle is clockwise.
*/
export const triangleIsCounterClockwise = function(x1, y1, x2, y2, x3, y3) {
const area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
return (area <= EPSILON && area >= -EPSILON) ?
undefined : area > 0;
};

View File

@@ -94,12 +94,11 @@ class CompositeMapRenderer extends MapRenderer {
if (element) {
const zIndex = layerState.zIndex;
if (zIndex !== element.style.zIndex) {
element.style.zIndex = zIndex === Infinity ? Number.MAX_SAFE_INTEGER : zIndex;
element.style.zIndex = zIndex;
}
this.children_.push(element);
}
}
super.renderFrame(frameState);
replaceChildren(this.element_, this.children_);

View File

@@ -89,11 +89,10 @@ class LayerRenderer extends Observable {
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
* @param {number} hitTolerance Hit tolerance in pixels.
* @param {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default): T} callback Feature callback.
* @param {Array<import("../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
* @return {T|void} Callback result.
* @template T
*/
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {}
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {}
/**
* @abstract

View File

@@ -10,7 +10,6 @@ import {TRUE} from '../functions.js';
import {visibleAtResolution} from '../layer/Layer.js';
import {shared as iconImageCache} from '../style/IconImageCache.js';
import {compose as composeTransform, makeInverse} from '../transform.js';
import {renderDeclutterItems} from '../render.js';
/**
* @abstract
@@ -29,11 +28,6 @@ class MapRenderer extends Disposable {
*/
this.map_ = map;
/**
* @private
*/
this.declutterTree_ = null;
/**
* @private
* @type {!Object<string, import("./Layer.js").default>}
@@ -139,12 +133,6 @@ class MapRenderer extends Disposable {
const layerStates = frameState.layerStatesArray;
const numLayers = layerStates.length;
let declutteredFeatures;
if (this.declutterTree_) {
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
return entry.value;
});
}
let i;
for (i = numLayers - 1; i >= 0; --i) {
const layerState = layerStates[i];
@@ -156,7 +144,7 @@ class MapRenderer extends Disposable {
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
result = layerRenderer.forEachFeatureAtCoordinate(
source.getWrapX() ? translatedCoordinate : coordinate,
frameState, hitTolerance, callback, declutteredFeatures);
frameState, hitTolerance, callback);
}
if (result) {
return result;
@@ -264,10 +252,11 @@ class MapRenderer extends Disposable {
/**
* Render.
* @abstract
* @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
*/
renderFrame(frameState) {
this.declutterTree_ = renderDeclutterItems(frameState, this.declutterTree_);
abstract();
}
/**

View File

@@ -11,7 +11,6 @@ import CanvasVectorLayerRenderer from './VectorLayer.js';
import {listen} from '../../events.js';
import EventType from '../../events/EventType.js';
import ImageState from '../../ImageState.js';
import {renderDeclutterItems} from '../../render.js';
/**
* @classdesc
@@ -73,7 +72,6 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
let skippedFeatures = this.skippedFeatures_;
const context = vectorRenderer.context;
const imageFrameState = /** @type {import("../../PluggableMap.js").FrameState} */ (assign({}, frameState, {
declutterItems: [],
size: [
getWidth(renderedExtent) / viewResolution,
getHeight(renderedExtent) / viewResolution
@@ -88,7 +86,6 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
(vectorRenderer.replayGroupChanged ||
!equals(skippedFeatures, newSkippedFeatures))) {
vectorRenderer.renderFrame(imageFrameState, layerState);
renderDeclutterItems(imageFrameState, null);
skippedFeatures = newSkippedFeatures;
callback();
}
@@ -126,11 +123,11 @@ class CanvasVectorImageLayerRenderer extends CanvasImageLayerRenderer {
/**
* @inheritDoc
*/
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback) {
if (this.vectorRenderer_) {
return this.vectorRenderer_.forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures);
return this.vectorRenderer_.forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback);
} else {
return super.forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures);
return super.forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback);
}
}
}

View File

@@ -5,10 +5,11 @@ import {getUid} from '../../util.js';
import ViewHint from '../../ViewHint.js';
import {listen, unlisten} from '../../events.js';
import EventType from '../../events/EventType.js';
import rbush from 'rbush';
import {buffer, createEmpty, containsExtent, getWidth} from '../../extent.js';
import {labelCache} from '../../render/canvas.js';
import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js';
import ExecutorGroup, {replayDeclutter} from '../../render/canvas/ExecutorGroup.js';
import ExecutorGroup from '../../render/canvas/ExecutorGroup.js';
import CanvasLayerRenderer from './Layer.js';
import {defaultOrder as defaultRenderOrder, getTolerance as getRenderTolerance, getSquaredTolerance as getSquaredRenderTolerance, renderFeature} from '../vector.js';
import {toString as transformToString, makeScale, makeInverse} from '../../transform.js';
@@ -27,6 +28,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
super(vectorLayer);
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = vectorLayer.getDeclutter() ? rbush(9, undefined) : null;
/**
* @private
* @type {boolean}
@@ -131,14 +138,17 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
this.clip(context, frameState, clipExtent);
}
if (this.declutterTree_) {
this.declutterTree_.clear();
}
const viewHints = frameState.viewHints;
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
const transform = this.getRenderTransform(frameState, width, height, 0);
const skippedFeatureUids = layerState.managed ? frameState.skippedFeatureUids : {};
const declutterReplays = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer()).getDeclutter() ? {} : null;
replayGroup.execute(context, transform, rotation, skippedFeatureUids, snapToPixel, undefined, declutterReplays);
replayGroup.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
if (vectorSource.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, extent)) {
let startX = extent[0];
@@ -149,7 +159,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
--world;
offsetX = worldWidth * world;
const transform = this.getRenderTransform(frameState, width, height, offsetX);
replayGroup.execute(context, transform, rotation, skippedFeatureUids, snapToPixel, undefined, declutterReplays);
replayGroup.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
startX += worldWidth;
}
world = 0;
@@ -158,15 +168,10 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
++world;
offsetX = worldWidth * world;
const transform = this.getRenderTransform(frameState, width, height, offsetX);
replayGroup.execute(context, transform, rotation, skippedFeatureUids, snapToPixel, undefined, declutterReplays);
replayGroup.execute(context, transform, rotation, skippedFeatureUids, snapToPixel);
startX -= worldWidth;
}
}
if (declutterReplays) {
const viewHints = frameState.viewHints;
const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems);
}
if (clipped) {
context.restore();
@@ -185,7 +190,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
/**
* @inheritDoc
*/
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, thisArg) {
if (!this.replayGroup_) {
return undefined;
} else {
@@ -203,9 +208,9 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const key = getUid(feature);
if (!(key in features)) {
features[key] = true;
return callback(feature, layer);
return callback.call(thisArg, feature, layer);
}
}, declutteredFeatures);
}, null);
return result;
}
}
@@ -294,7 +299,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const replayGroup = new CanvasBuilderGroup(
getRenderTolerance(resolution, pixelRatio), extent, resolution,
pixelRatio, vectorLayer.getDeclutter());
pixelRatio, !!this.declutterTree_);
vectorSource.loadFeatures(extent, resolution, projection);
@@ -334,7 +339,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
const replayGroupInstructions = replayGroup.finish();
const executorGroup = new ExecutorGroup(extent, resolution,
pixelRatio, vectorSource.getOverlaps(),
pixelRatio, vectorSource.getOverlaps(), this.declutterTree_,
replayGroupInstructions, vectorLayer.getRenderBuffer());
this.renderedResolution_ = resolution;

View File

@@ -7,6 +7,7 @@ import TileState from '../../TileState.js';
import ViewHint from '../../ViewHint.js';
import {listen, unlisten, unlistenByKey} from '../../events.js';
import EventType from '../../events/EventType.js';
import rbush from 'rbush';
import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js';
import VectorTileRenderType from '../../layer/VectorTileRenderType.js';
import ReplayType from '../../render/canvas/BuilderType.js';
@@ -102,6 +103,12 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
*/
this.inverseOverlayPixelTransform_ = createTransform();
/**
* Declutter tree.
* @private
*/
this.declutterTree_ = layer.getDeclutter() ? rbush(9, undefined) : null;
/**
* @private
* @type {boolean}
@@ -131,8 +138,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
*/
this.tmpTransform_ = createTransform();
// Use nearest lower resolution.
this.zDirection = 1;
// Use closest resolution.
this.zDirection = 0;
listen(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
@@ -267,7 +274,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
buffer(sharedExtent, layer.getRenderBuffer() * resolution, this.tmpExtent);
builderState.dirty = false;
const builderGroup = new CanvasBuilderGroup(0, sharedExtent, resolution,
pixelRatio, layer.getDeclutter());
pixelRatio, !!this.declutterTree_);
const squaredTolerance = getSquaredRenderTolerance(resolution, pixelRatio);
/**
@@ -303,7 +310,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
null :
sharedExtent;
const renderingReplayGroup = new CanvasExecutorGroup(replayExtent, resolution,
pixelRatio, source.getOverlaps(), executorGroupInstructions, layer.getRenderBuffer());
pixelRatio, source.getOverlaps(), this.declutterTree_, executorGroupInstructions, layer.getRenderBuffer());
tile.executorGroups[layerUid].push(renderingReplayGroup);
}
builderState.renderedRevision = revision;
@@ -315,12 +322,11 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
/**
* @inheritDoc
*/
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, declutteredFeatures) {
forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, thisArg) {
const resolution = frameState.viewState.resolution;
const rotation = frameState.viewState.rotation;
hitTolerance = hitTolerance == undefined ? 0 : hitTolerance;
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const declutter = layer.getDeclutter();
const layer = this.getLayer();
const source = layer.getSource();
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
/** @type {!Object<string, boolean>} */
@@ -332,7 +338,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
let i, ii;
for (i = 0, ii = renderedTiles.length; i < ii; ++i) {
const tile = renderedTiles[i];
if (!declutter) {
if (!this.declutterTree_) {
// When not decluttering, we only need to consider the tile that contains the given
// coordinate, because each feature will be rendered for each tile that contains it.
const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
@@ -355,9 +361,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
}
if (!(key in features)) {
features[key] = true;
return callback(feature, layer);
return callback.call(thisArg, feature, layer);
}
}, declutteredFeatures);
}, null);
}
}
return found;
@@ -458,6 +464,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
context.clearRect(0, 0, width, height);
}
if (declutterReplays) {
this.declutterTree_.clear();
}
const tiles = this.renderedTiles;
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
const clips = [];
@@ -513,7 +522,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
}
}
if (declutterReplays) {
replayDeclutter(declutterReplays, context, rotation, hifi, frameState.declutterItems);
replayDeclutter(declutterReplays, context, rotation, hifi);
}
const opacity = layerState.opacity;
@@ -543,6 +552,9 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
frameState.animate = true;
delete this.renderTileImageQueue_[uid];
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
if (this.declutterTree_ && layer.getRenderMode() === VectorTileRenderType.IMAGE) {
this.declutterTree_.clear();
}
const viewState = frameState.viewState;
const tileGrid = layer.getSource().getTileGridForProjection(viewState.projection);
const tileResolution = tileGrid.getResolution(tile.tileCoord[0]);
@@ -614,8 +626,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
const tileGrid = source.getTileGridForProjection(projection);
const resolution = tileGrid.getResolution(z);
const context = tile.getContext(layer);
// Increase tile size when overzooming for low pixel ratio, to avoid blurry tiles
pixelRatio = Math.max(pixelRatio, renderPixelRatio / pixelRatio);
const size = source.getTilePixelSize(z, pixelRatio, projection);
context.canvas.width = size[0];
context.canvas.height = size[1];

View File

@@ -74,11 +74,11 @@ const FRAGMENT_SHADER = `
* @property {function(import("../../Feature").default, number):number} [texCoordCallback] Will be called on every feature in the
* source to compute the texture coordinates of each corner of the quad (without effect if no `texture` option defined). This is only done on source change.
* The second argument is 0 for `u0` component, 1 for `v0`, 2 for `u1`, and 3 for `v1`.
* @property {function(import("../../Feature").default, Array<number>=):Array<number>} [colorCallback] Will be called on every feature in the
* source to compute the color for use in the fragment shader (available as the `v_color` varying). This is only done on source change.
* The return value should be between an array of R, G, B, A values between 0 and 1. To reduce unnecessary
* allocation, the function is called with a reusable array that can serve as the return value after updating
* the R, G, B, and A values.
* @property {function(import("../../Feature").default, number, number):number} [colorCallback] Will be called on every feature in the
* source to compute the color of each corner of the quad. This is only done on source change.
* The second argument is 0 for bottom left, 1 for bottom right, 2 for top right and 3 for top left
* The third argument is 0 for red, 1 for green, 2 for blue and 3 for alpha
* The return value should be between 0 and 1.
* @property {function(import("../../Feature").default):number} [opacityCallback] Will be called on every feature in the
* source to compute the opacity of the quad on screen (from 0 to 1). This is only done on source change.
* Note: this is multiplied with the color of the point which can also have an alpha value < 1.
@@ -110,11 +110,11 @@ const FRAGMENT_SHADER = `
*
* The following uniform is used for the main texture: `u_texture`.
*
* Please note that the main shader output should have premultiplied alpha, otherwise visual anomalies may occur.
* Please note that the main shader output should have premultiplied alpha, otherwise the colors will be blended
* additively.
*
* Points are rendered as quads with the following structure:
*
* ```
* (u0, v1) (u1, v1)
* [3]----------[2]
* |` |
@@ -125,7 +125,6 @@ const FRAGMENT_SHADER = `
* | ` |
* [0]----------[1]
* (u0, v0) (u1, v0)
* ```
*
* This uses {@link module:ol/webgl/Helper~WebGLHelper} internally.
*
@@ -229,12 +228,9 @@ class WebGLPointsLayerRenderer extends LayerRenderer {
this.texCoordCallback_ = options.texCoordCallback || function(feature, index) {
return index < 2 ? 0 : 1;
};
this.colorArray_ = [1, 1, 1, 1];
this.colorCallback_ = options.colorCallback || function(feature, color) {
return this.colorArray_;
this.colorCallback_ = options.colorCallback || function(feature, index, component) {
return 1;
};
this.rotateWithViewCallback_ = options.rotateWithViewCallback || function() {
return false;
};
@@ -298,27 +294,35 @@ class WebGLPointsLayerRenderer extends LayerRenderer {
const size = this.sizeCallback_(feature);
const opacity = this.opacityCallback_(feature);
const rotateWithView = this.rotateWithViewCallback_(feature) ? 1 : 0;
const color = this.colorCallback_(feature, this.colorArray_);
const red = color[0];
const green = color[1];
const blue = color[2];
const alpha = color[3];
const v0_r = this.colorCallback_(feature, 0, 0);
const v0_g = this.colorCallback_(feature, 0, 1);
const v0_b = this.colorCallback_(feature, 0, 2);
const v0_a = this.colorCallback_(feature, 0, 3);
const v1_r = this.colorCallback_(feature, 1, 0);
const v1_g = this.colorCallback_(feature, 1, 1);
const v1_b = this.colorCallback_(feature, 1, 2);
const v1_a = this.colorCallback_(feature, 1, 3);
const v2_r = this.colorCallback_(feature, 2, 0);
const v2_g = this.colorCallback_(feature, 2, 1);
const v2_b = this.colorCallback_(feature, 2, 2);
const v2_a = this.colorCallback_(feature, 2, 3);
const v3_r = this.colorCallback_(feature, 3, 0);
const v3_g = this.colorCallback_(feature, 3, 1);
const v3_b = this.colorCallback_(feature, 3, 2);
const v3_a = this.colorCallback_(feature, 3, 3);
const baseIndex = this.verticesBuffer_.getArray().length / stride;
this.verticesBuffer_.getArray().push(
x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha,
x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha,
x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha,
x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha
x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, v0_r, v0_g, v0_b, v0_a,
x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, v1_r, v1_g, v1_b, v1_a,
x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, v2_r, v2_g, v2_b, v2_a,
x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, v3_r, v3_g, v3_b, v3_a
);
this.indicesBuffer_.getArray().push(
baseIndex, baseIndex + 1, baseIndex + 3,
baseIndex + 1, baseIndex + 2, baseIndex + 3
);
});
this.helper_.flushBufferData(ARRAY_BUFFER, this.verticesBuffer_);
this.helper_.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
}
// write new data

View File

@@ -5,7 +5,6 @@
export {default as BingMaps} from './source/BingMaps.js';
export {default as CartoDB} from './source/CartoDB.js';
export {default as Cluster} from './source/Cluster.js';
export {default as IIIF} from './source/IIIF.js';
export {default as Image} from './source/Image.js';
export {default as ImageArcGISRest} from './source/ImageArcGISRest.js';
export {default as ImageCanvas} from './source/ImageCanvas.js';

View File

@@ -1,284 +0,0 @@
/**
* @module ol/source/IIIF
*/
import {DEFAULT_TILE_SIZE} from '../tilegrid/common.js';
import {getTopLeft} from '../extent.js';
import {CustomTile} from './Zoomify.js';
import {Versions} from '../format/IIIFInfo.js';
import {assert} from '../asserts.js';
import TileGrid from '../tilegrid/TileGrid.js';
import TileImage from './TileImage.js';
/**
* @typedef {Object} Options
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
* @property {number} [cacheSize]
* @property {null|string} [crossOrigin]
* @property {import("../extent.js").Extent} [extent=[0, -height, width, 0]]
* @property {string} [format='jpg'] Requested image format.
* @property {import("../proj.js").ProjectionLike} [projection]
* @property {string} [quality] Requested IIIF image quality. Default is 'native'
* for version 1, 'default' for versions 2 and 3.
* @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
* Higher values can increase reprojection performance, but decrease precision.
* @property {import("../size.js").Size} size Size of the image [width, height].
* @property {import("../size.js").Size[]} [sizes] Supported scaled image sizes.
* Content of the IIIF info.json 'sizes' property, but as array of Size objects.
* @property {import("./State.js").default} [state] Source state.
* @property {Array<string>} [supports=[]] Supported IIIF region and size calculation
* features.
* @property {number} [tilePixelRatio]
* @property {number|import("../size.js").Size} [tileSize] Tile size.
* Same tile size is used for all zoom levels. If tile size is a number,
* a square tile is assumed. If the IIIF image service supports arbitrary
* tiling (sizeByH, sizeByW, sizeByWh or sizeByPct as well as regionByPx or regionByPct
* are supported), the default tilesize is 256.
* @property {number} [transition]
* @property {string} [url] Base URL of the IIIF Image service.
* This should be the same as the IIIF Image @id.
* @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.
* 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.
*/
function formatPercentage(percentage) {
return percentage.toLocaleString('en', {maximumFractionDigits: 10});
}
/**
* @classdesc
* Layer source for IIIF Image API services.
* @api
*/
class IIIF extends TileImage {
constructor(opt_options) {
const options = opt_options || {};
let baseUrl = options.url || '';
baseUrl = baseUrl + (baseUrl.lastIndexOf('/') === baseUrl.length - 1 || baseUrl === '' ? '' : '/');
const version = options.version || Versions.VERSION2;
const sizes = options.sizes || [];
const size = options.size;
assert(size != undefined && Array.isArray(size) && size.length == 2 &&
!isNaN(size[0]) && size[0] > 0 && !isNaN(size[1]) && size[1] > 0, 60);
const width = size[0];
const height = size[1];
const tileSize = options.tileSize;
const format = options.format || 'jpg';
const quality = options.quality || (options.version == Versions.VERSION1 ? 'native' : 'default');
let resolutions = options.resolutions || [];
const supports = options.supports || [];
const extent = options.extent || [0, -height, width, 0];
const supportsListedSizes = sizes != undefined && Array.isArray(sizes) && sizes.length > 0;
const supportsListedTiles = tileSize != undefined && (Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0);
const supportsArbitraryTiling = supports != undefined && Array.isArray(supports) &&
(supports.includes('regionByPx') || supports.includes('regionByPct')) &&
(supports.includes('sizeByWh') || supports.includes('sizeByH') ||
supports.includes('sizeByW') || supports.includes('sizeByPct'));
let tileWidth,
tileHeight,
maxZoom;
resolutions.sort(function(a, b) {
return b - a;
});
if (supportsListedTiles || supportsArbitraryTiling) {
if (tileSize != undefined) {
if (Number.isInteger(tileSize) && tileSize > 0) {
tileWidth = tileSize;
tileHeight = tileSize;
} else if (Array.isArray(tileSize) && tileSize.length > 0) {
if (tileSize.length == 1 || tileSize[1] == undefined && Number.isInteger(tileSize[0])) {
tileWidth = tileSize[0];
tileHeight = tileSize[0];
}
if (tileSize.length == 2) {
if (Number.isInteger(tileSize[0]) && Number.isInteger(tileSize[1])) {
tileWidth = tileSize[0];
tileHeight = tileSize[1];
} else if (tileSize[0] == undefined && Number.isInteger(tileSize[1])) {
tileWidth = tileSize[1];
tileHeight = tileSize[1];
}
}
}
}
if (tileWidth === undefined || tileHeight === undefined) {
tileWidth = DEFAULT_TILE_SIZE;
tileHeight = DEFAULT_TILE_SIZE;
}
if (resolutions.length == 0) {
maxZoom = Math.max(
Math.ceil(Math.log(width / tileWidth) / Math.LN2),
Math.ceil(Math.log(height / tileHeight) / Math.LN2)
);
for (let i = maxZoom; i >= 0; i--) {
resolutions.push(Math.pow(2, i));
}
} else {
const maxScaleFactor = Math.max([...resolutions]);
// TODO maxScaleFactor might not be a power to 2
maxZoom = Math.round(Math.log(maxScaleFactor) / Math.LN2);
}
} else {
// No tile support.
tileWidth = width;
tileHeight = height;
resolutions = [];
if (supportsListedSizes) {
/*
* 'sizes' provided. Use full region in different resolutions. Every
* resolution has only one tile.
*/
sizes.sort(function(a, b) {
return a[0] - b[0];
});
maxZoom = -1;
const ignoredSizesIndex = [];
for (let i = 0; i < sizes.length; i++) {
const resolution = width / sizes[i][0];
if (resolutions.length > 0 && resolutions[resolutions.length - 1] == resolution) {
ignoredSizesIndex.push(i);
continue;
}
resolutions.push(resolution);
maxZoom++;
}
if (ignoredSizesIndex.length > 0) {
for (let i = 0; i < ignoredSizesIndex.length; i++) {
sizes.splice(ignoredSizesIndex[i] - i, 1);
}
}
} else {
// No useful image information at all. Try pseudo tile with full image.
resolutions.push(1);
sizes.push([width, height]);
maxZoom = 0;
}
}
const tileGrid = new TileGrid({
tileSize: [tileWidth, tileHeight],
extent: extent,
origin: getTopLeft(extent),
resolutions: resolutions
});
const tileUrlFunction = function(tileCoord, pixelRatio, projection) {
let regionParam,
sizeParam;
const zoom = tileCoord[0];
if (zoom > maxZoom) {
return;
}
const tileX = tileCoord[1],
tileY = tileCoord[2],
scale = resolutions[zoom];
if (tileX === undefined || tileY === undefined || scale === undefined ||
tileX < 0 || Math.ceil(width / scale / tileWidth) <= tileX ||
tileY < 0 || Math.ceil(height / scale / tileHeight) <= tileY) {
return;
}
if (supportsArbitraryTiling || supportsListedTiles) {
const regionX = tileX * tileWidth * scale,
regionY = tileY * tileHeight * scale;
let regionW = tileWidth * scale,
regionH = tileHeight * scale,
sizeW = tileWidth,
sizeH = tileHeight;
if (regionX + regionW > width) {
regionW = width - regionX;
}
if (regionY + regionH > height) {
regionH = height - regionY;
}
if (regionX + tileWidth * scale > width) {
sizeW = Math.floor((width - regionX + scale - 1) / scale);
}
if (regionY + tileHeight * scale > height) {
sizeH = Math.floor((height - regionY + scale - 1) / scale);
}
if (regionX == 0 && regionW == width && regionY == 0 && regionH == height) {
// canonical full image region parameter is 'full', not 'x,y,w,h'
regionParam = 'full';
} else if (!supportsArbitraryTiling || supports.includes('regionByPx')) {
regionParam = regionX + ',' + regionY + ',' + regionW + ',' + regionH;
} else if (supports.includes('regionByPct')) {
const pctX = formatPercentage(regionX / width * 100),
pctY = formatPercentage(regionY / height * 100),
pctW = formatPercentage(regionW / width * 100),
pctH = formatPercentage(regionH / height * 100);
regionParam = 'pct:' + pctX + ',' + pctY + ',' + pctW + ',' + pctH;
}
if (version == Versions.VERSION3 && (!supportsArbitraryTiling || supports.includes('sizeByWh'))) {
sizeParam = sizeW + ',' + sizeH;
} else if (!supportsArbitraryTiling || supports.includes('sizeByW')) {
sizeParam = sizeW + ',';
} else if (supports.includes('sizeByH')) {
sizeParam = ',' + sizeH;
} else if (supports.includes('sizeByWh')) {
sizeParam = sizeW + ',' + sizeH;
} else if (supports.includes('sizeByPct')) {
sizeParam = 'pct:' + formatPercentage(100 / scale);
}
} else {
regionParam = 'full';
if (supportsListedSizes) {
const regionWidth = sizes[zoom][0],
regionHeight = sizes[zoom][1];
if (version == Versions.VERSION3) {
if (regionWidth == width && regionHeight == height) {
sizeParam = 'max';
} else {
sizeParam = regionWidth + ',' + regionHeight;
}
} else {
if (regionWidth == width) {
sizeParam = 'full';
} else {
sizeParam = regionWidth + ',';
}
}
} else {
sizeParam = version == Versions.VERSION3 ? 'max' : 'full';
}
}
return baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format;
};
const IiifTileClass = CustomTile.bind(null, tileGrid);
super({
attributions: options.attributions,
attributionsCollapsible: options.attributionsCollapsible,
cacheSize: options.cacheSize,
crossOrigin: options.crossOrigin,
projection: options.projection,
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
state: options.state,
tileClass: IiifTileClass,
tileGrid: tileGrid,
tilePixelRatio: options.tilePixelRatio,
tileUrlFunction: tileUrlFunction,
transition: options.transition
});
/**
* @inheritDoc
*/
this.zDirection = options.zDirection;
}
}
export default IIIF;

Some files were not shown because too many files have changed in this diff Show More