diff --git a/examples/vector-wfs-geographic.html b/examples/vector-wfs-geographic.html new file mode 100644 index 0000000000..c48ea36bf2 --- /dev/null +++ b/examples/vector-wfs-geographic.html @@ -0,0 +1,16 @@ +--- +layout: example.html +title: WFS +shortdesc: Example of using WFS with a Tile strategy. +docs: > + This example loads new features from GeoServer WFS with a tile based loading strategy. + Calling the useGeographic function in the 'ol/proj' module + makes it so the map view uses geographic coordinates (even if the view projection is + not geographic). +tags: "vector, WFS, tile, strategy, loading, server, maptiler" +cloak: + - key: get_your_own_D6rA4zTHduk6KOKTXzGB + value: Get your own API key at https://www.maptiler.com/cloud/ +experimental: true +--- +
diff --git a/examples/vector-wfs-geographic.js b/examples/vector-wfs-geographic.js new file mode 100644 index 0000000000..dcc3ca8a6b --- /dev/null +++ b/examples/vector-wfs-geographic.js @@ -0,0 +1,60 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; +import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; +import XYZ from '../src/ol/source/XYZ.js'; +import {Stroke, Style} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {createXYZ} from '../src/ol/tilegrid.js'; +import {tile} from '../src/ol/loadingstrategy.js'; +import {useGeographic} from '../src/ol/proj.js'; + +useGeographic(); + +const vectorSource = new VectorSource({ + format: new GeoJSON(), + url: function (extent) { + return ( + 'https://ahocevar.com/geoserver/wfs?service=WFS&' + + 'version=1.1.0&request=GetFeature&typename=osm:water_areas&' + + 'outputFormat=application/json&srsname=EPSG:4326&' + + 'bbox=' + + extent.join(',') + + ',EPSG:4326' + ); + }, + strategy: tile(createXYZ({tileSize: 512})), +}); + +const vector = new VectorLayer({ + source: vectorSource, + style: new Style({ + stroke: new Stroke({ + color: 'rgba(0, 0, 255, 1.0)', + width: 2, + }), + }), +}); + +const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; +const attributions = + '© MapTiler ' + + '© OpenStreetMap contributors'; + +const raster = new TileLayer({ + source: new XYZ({ + attributions: attributions, + url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + maxZoom: 20, + }), +}); + +const map = new Map({ + layers: [raster, vector], + target: document.getElementById('map'), + view: new View({ + center: [-80.0298, 43.4578], + maxZoom: 19, + zoom: 12, + }), +}); diff --git a/src/ol/loadingstrategy.js b/src/ol/loadingstrategy.js index bee3ac26a5..e27301e895 100644 --- a/src/ol/loadingstrategy.js +++ b/src/ol/loadingstrategy.js @@ -2,6 +2,8 @@ * @module ol/loadingstrategy */ +import {fromUserExtent, fromUserResolution, toUserExtent} from './proj.js'; + /** * Strategy function for loading all features with a single request. * @param {import("./extent.js").Extent} extent Extent. @@ -28,7 +30,7 @@ export function bbox(extent, resolution) { /** * Creates a strategy function for loading features based on a tile grid. * @param {import("./tilegrid/TileGrid.js").default} tileGrid Tile grid. - * @return {function(import("./extent.js").Extent, number): Array} Loading strategy. + * @return {function(import("./extent.js").Extent, number, import("./proj.js").Projection): Array} Loading strategy. * @api */ export function tile(tileGrid) { @@ -36,11 +38,17 @@ export function tile(tileGrid) { /** * @param {import("./extent.js").Extent} extent Extent. * @param {number} resolution Resolution. + * @param {import("./proj.js").Projection} projection Projection. * @return {Array} Extents. */ - function (extent, resolution) { - const z = tileGrid.getZForResolution(resolution); - const tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + function (extent, resolution, projection) { + const z = tileGrid.getZForResolution( + fromUserResolution(resolution, projection) + ); + const tileRange = tileGrid.getTileRangeForExtentAndZ( + fromUserExtent(extent, projection), + z + ); /** @type {Array} */ const extents = []; /** @type {import("./tilecoord.js").TileCoord} */ @@ -55,7 +63,9 @@ export function tile(tileGrid) { tileCoord[2] <= tileRange.maxY; ++tileCoord[2] ) { - extents.push(tileGrid.getTileCoordExtent(tileCoord)); + extents.push( + toUserExtent(tileGrid.getTileCoordExtent(tileCoord), projection) + ); } } return extents; diff --git a/test/browser/spec/ol/loadingstrategy.test.js b/test/browser/spec/ol/loadingstrategy.test.js new file mode 100644 index 0000000000..0b734e60f4 --- /dev/null +++ b/test/browser/spec/ol/loadingstrategy.test.js @@ -0,0 +1,38 @@ +import {approximatelyEquals} from '../../../../src/ol/extent.js'; +import { + clearUserProjection, + get, + toUserExtent, + toUserResolution, + transformExtent, + useGeographic, +} from '../../../../src/ol/proj.js'; +import {createXYZ} from '../../../../src/ol/tilegrid.js'; +import {tile} from '../../../../src/ol/loadingstrategy.js'; + +describe('ol/loadingstrategy', function () { + describe('tile', function () { + afterEach(function () { + clearUserProjection(); + }); + it('uses a tile grid in view projection', function () { + useGeographic(); + const tileGrid = createXYZ(); + const strategy = tile(tileGrid); + const extent = tileGrid.getTileCoordExtent([1, 1, 1]); + const userExtent = toUserExtent(extent, get('EPSG:3857')); + const userResolution = toUserResolution( + tileGrid.getResolution(1), + get('EPSG:3857') + ); + const extents = strategy(userExtent, userResolution, get('EPSG:3857')); + expect( + approximatelyEquals( + transformExtent(extents[0], 'EPSG:4326', 'EPSG:3857'), + extent, + 1e-8 + ) + ).to.be(true); + }); + }); +});