-
-
-
-
-
OpenLayers
-
+
+
+
-
OpenLayers
-
+
+
+
+
+
OpenLayers
+
+
+
+
-
OpenLayers
+
+
+
+
+
+
+
+
+
+
+
+
+ This documentation is for OpenLayers v. The latest is v.
+
+
+
-
-
-
-
-
-
+
diff --git a/config/jsdoc/api/template/tmpl/method.tmpl b/config/jsdoc/api/template/tmpl/method.tmpl
index a5ddc77f5d..9ff68aa638 100644
--- a/config/jsdoc/api/template/tmpl/method.tmpl
+++ b/config/jsdoc/api/template/tmpl/method.tmpl
@@ -64,7 +64,7 @@ var self = this;
-
-
-
-
- This documentation is for OpenLayers v. The latest is v.
-
-
- -
-
- - () - ++ + () - diff --git a/config/jsdoc/api/template/tmpl/navigation.tmpl b/config/jsdoc/api/template/tmpl/navigation.tmpl index 074e99672f..50709af9cc 100644 --- a/config/jsdoc/api/template/tmpl/navigation.tmpl +++ b/config/jsdoc/api/template/tmpl/navigation.tmpl @@ -7,53 +7,64 @@ function toShortName(name) { function getItemCssClass(type) { if (type === 'module') { - return 'glyphicon-plus'; + return 'fa-plus'; } else if (type === 'class') { - return 'glyphicon-chevron-right'; + return 'fa-chevron-right'; } return ''; } -const printList = v => { ?> - - { - const cls = v.stability && v.stability !== 'stable' ? ' class="unstable"' : ''; ?> -
- > { + const shortName = toShortName(member.name); ?> +
- { + const shortName = toShortName(member.name); + const cls = member.stability && member.stability !== 'stable' ? ' class="unstable"' : ''; ?> +
- > { + const ancestor = self.find({longname: eventName})[0] || + {longname: eventName, name: eventName.split(/#?event:/)[1]}; + const eventEnum = ancestor.longname.split(/#?event:/)[0]; + if (self.find({longname: eventEnum})[0]) { + printListItemWithStability(ancestor); + } else { + const cls = ancestor.stability && ancestor.stability !== 'stable' ? ' class="unstable"' : ''; + const shortName = toShortName(ancestor.name); ?> +
- >
- +-+diff --git a/config/jsdoc/info/api-plugin.js b/config/jsdoc/info/api-plugin.js index afef0dc34e..2a3dd96610 100644 --- a/config/jsdoc/info/api-plugin.js +++ b/config/jsdoc/info/api-plugin.js @@ -1,15 +1,11 @@ - - /** * Handle the api annotation. * @param {Object} dictionary The tag dictionary. */ -exports.defineTags = function(dictionary) { - +exports.defineTags = function (dictionary) { dictionary.defineTag('api', { - onTagged: function(doclet, tag) { + onTagged: function (doclet, tag) { doclet.api = true; - } + }, }); - }; diff --git a/config/jsdoc/info/define-plugin.js b/config/jsdoc/info/define-plugin.js index 78634499ba..3d604db19a 100644 --- a/config/jsdoc/info/define-plugin.js +++ b/config/jsdoc/info/define-plugin.js @@ -5,31 +5,27 @@ * insensitive, with or without ticks). */ - const DEFAULT_VALUE = /default\s+is\s+`?(true|false)`?/i; - /** * Hook to define new tags. * @param {Object} dictionary The tag dictionary. */ -exports.defineTags = function(dictionary) { - +exports.defineTags = function (dictionary) { dictionary.defineTag('define', { canHaveType: true, mustHaveValue: true, - onTagged: function(doclet, tag) { + onTagged: function (doclet, tag) { const types = tag.value.type.names; if (types.length === 1 && types[0] === 'boolean') { const match = tag.value.description.match(DEFAULT_VALUE); if (match) { doclet.define = { - default: match[1] === 'true' + default: match[1] === 'true', }; doclet.description = tag.value.description; } } - } + }, }); - }; diff --git a/config/jsdoc/info/publish.js b/config/jsdoc/info/publish.js index bc01c31f89..f57c4dec57 100644 --- a/config/jsdoc/info/publish.js +++ b/config/jsdoc/info/publish.js @@ -5,18 +5,16 @@ const assert = require('assert'); const path = require('path'); - /** * Publish hook for the JSDoc template. Writes to JSON stdout. * @param {function} data The root of the Taffy DB containing doclet records. * @param {Object} opts Options. * @return {Promise} A promise that resolves when writing is complete. */ -exports.publish = function(data, opts) { - +exports.publish = function (data, opts) { function getTypes(data) { const types = []; - data.forEach(function(name) { + data.forEach(function (name) { types.push(name.replace(/^function$/, 'Function')); }); return types; @@ -27,19 +25,22 @@ exports.publish = function(data, opts) { const docs = data( [ {define: {isObject: true}}, - function() { + function () { if (this.kind == 'class') { if (!('extends' in this) || typeof this.api == 'boolean') { classes[this.longname] = this; return true; } } - return (typeof this.api == 'boolean' || - this.meta && (/[\\\/]externs$/).test(this.meta.path)); - } + return ( + typeof this.api == 'boolean' || + (this.meta && /[\\\/]externs$/.test(this.meta.path)) + ); + }, ], {kind: {'!is': 'file'}}, - {kind: {'!is': 'event'}}).get(); + {kind: {'!is': 'event'}} + ).get(); // get symbols data, filter out those that are members of private classes const symbols = []; @@ -49,117 +50,133 @@ exports.publish = function(data, opts) { let base = []; const augments = {}; const symbolsByName = {}; - docs.filter(function(doc) { - let include = true; - const constructor = doc.memberof; - if (constructor && constructor.substr(-1) === '_' && constructor.indexOf('module:') === -1) { - assert.strictEqual(doc.inherited, true, - 'Unexpected export on private class: ' + doc.longname); - include = false; - } - return include; - }).forEach(function(doc) { - const isExterns = (/[\\\/]externs$/).test(doc.meta.path); - if (doc.define) { - defines.push({ - name: doc.longname, - description: doc.description, - path: path.join(doc.meta.path, doc.meta.filename), - default: doc.define.default - }); - } else if (doc.kind == 'typedef' || doc.isEnum === true) { - typedefs.push({ - name: doc.longname, - types: getTypes(doc.type.names) - }); - } else { - const symbol = { - name: doc.longname, - kind: doc.kind, - description: doc.classdesc || doc.description, - path: path.join(doc.meta.path, doc.meta.filename) - }; - if (doc.augments) { - symbol.extends = doc.augments[0]; + docs + .filter(function (doc) { + let include = true; + const constructor = doc.memberof; + if ( + constructor && + constructor.substr(-1) === '_' && + constructor.indexOf('module:') === -1 + ) { + assert.strictEqual( + doc.inherited, + true, + 'Unexpected export on private class: ' + doc.longname + ); + include = false; } - if (doc.virtual) { - symbol.virtual = true; - } - if (doc.type) { - symbol.types = getTypes(doc.type.names); - } - if (doc.params) { - const params = []; - doc.params.forEach(function(param) { - const paramInfo = { - name: param.name - }; - params.push(paramInfo); - paramInfo.types = getTypes(param.type.names); - if (typeof param.variable == 'boolean') { - paramInfo.variable = param.variable; - } - if (typeof param.optional == 'boolean') { - paramInfo.optional = param.optional; - } - if (typeof param.nullable == 'boolean') { - paramInfo.nullable = param.nullable; - } + return include; + }) + .forEach(function (doc) { + const isExterns = /[\\\/]externs$/.test(doc.meta.path); + if (doc.define) { + defines.push({ + name: doc.longname, + description: doc.description, + path: path.join(doc.meta.path, doc.meta.filename), + default: doc.define.default, }); - symbol.params = params; - } - if (doc.returns) { - symbol.returns = { - types: getTypes(doc.returns[0].type.names) + } else if (doc.kind == 'typedef' || doc.isEnum === true) { + typedefs.push({ + name: doc.longname, + types: getTypes(doc.type.names), + }); + } else { + const symbol = { + name: doc.longname, + kind: doc.kind, + description: doc.classdesc || doc.description, + path: path.join(doc.meta.path, doc.meta.filename), }; - if (typeof doc.returns[0].nullable == 'boolean') { - symbol.returns.nullable = doc.returns[0].nullable; + if (doc.augments) { + symbol.extends = doc.augments[0]; } - } - if (doc.tags) { - doc.tags.every(function(tag) { - if (tag.title == 'template') { - symbol.template = tag.value; - return false; + if (doc.virtual) { + symbol.virtual = true; + } + if (doc.type) { + symbol.types = getTypes(doc.type.names); + } + if (doc.params) { + const params = []; + doc.params.forEach(function (param) { + const paramInfo = { + name: param.name, + }; + params.push(paramInfo); + paramInfo.types = getTypes(param.type.names); + if (typeof param.variable == 'boolean') { + paramInfo.variable = param.variable; + } + if (typeof param.optional == 'boolean') { + paramInfo.optional = param.optional; + } + if (typeof param.nullable == 'boolean') { + paramInfo.nullable = param.nullable; + } + }); + symbol.params = params; + } + if (doc.returns) { + symbol.returns = { + types: getTypes(doc.returns[0].type.names), + }; + if (typeof doc.returns[0].nullable == 'boolean') { + symbol.returns.nullable = doc.returns[0].nullable; } - return true; - }); - } - - const target = isExterns ? externs : (doc.api ? symbols : base); - const existingSymbol = symbolsByName[symbol.name]; - if (existingSymbol) { - const idx = target.indexOf(existingSymbol); - target.splice(idx, 1); - } - target.push(symbol); - symbolsByName[symbol.name] = symbol; - - if (doc.api && symbol.extends) { - while (symbol.extends in classes && !classes[symbol.extends].api && - classes[symbol.extends].augments) { - symbol.extends = classes[symbol.extends].augments[0]; } - if (symbol.extends) { - augments[symbol.extends] = true; + if (doc.tags) { + doc.tags.every(function (tag) { + if (tag.title == 'template') { + symbol.template = tag.value; + return false; + } + return true; + }); + } + + const target = isExterns ? externs : doc.api ? symbols : base; + const existingSymbol = symbolsByName[symbol.name]; + if (existingSymbol) { + const idx = target.indexOf(existingSymbol); + target.splice(idx, 1); + } + target.push(symbol); + symbolsByName[symbol.name] = symbol; + + if (doc.api && symbol.extends) { + while ( + symbol.extends in classes && + !classes[symbol.extends].api && + classes[symbol.extends].augments + ) { + symbol.extends = classes[symbol.extends].augments[0]; + } + if (symbol.extends) { + augments[symbol.extends] = true; + } } } - } + }); + + base = base.filter(function (symbol) { + return symbol.name in augments || symbol.virtual; }); - base = base.filter(function(symbol) { - return (symbol.name in augments || symbol.virtual); - }); - - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { process.stdout.write( - JSON.stringify({ - symbols: symbols, - defines: defines, - typedefs: typedefs, - externs: externs, - base: base - }, null, 2)); + JSON.stringify( + { + symbols: symbols, + defines: defines, + typedefs: typedefs, + externs: externs, + base: base, + }, + null, + 2 + ) + ); }); - }; diff --git a/config/jsdoc/info/virtual-plugin.js b/config/jsdoc/info/virtual-plugin.js index a1cb8ee8ec..f83a2dba26 100644 --- a/config/jsdoc/info/virtual-plugin.js +++ b/config/jsdoc/info/virtual-plugin.js @@ -2,15 +2,13 @@ * Handle the interface and abstract annotations. * @param {Object} dictionary The tag dictionary. */ -exports.defineTags = function(dictionary) { - +exports.defineTags = function (dictionary) { const classTag = dictionary.lookUp('class'); dictionary.defineTag('interface', { mustNotHaveValue: true, - onTagged: function(doclet, tag) { + onTagged: function (doclet, tag) { classTag.onTagged.apply(this, arguments); doclet.virtual = true; - } + }, }); - }; diff --git a/config/webpack-config-legacy-build.js b/config/webpack-config-legacy-build.js index ca374a0e61..6b4e60b5fa 100644 --- a/config/webpack-config-legacy-build.js +++ b/config/webpack-config-legacy-build.js @@ -3,11 +3,16 @@ module.exports = { entry: './build/index.js', devtool: 'source-map', mode: 'production', + resolve: { + alias: { + ol: path.resolve('./src/ol'), + }, + }, output: { path: path.resolve('./build/legacy'), filename: 'ol.js', library: 'ol', libraryTarget: 'umd', - libraryExport: 'default' - } + libraryExport: 'default', + }, }; diff --git a/doc/tutorials/raster-reprojection.md b/doc/tutorials/raster-reprojection.md index 167d25f353..b068f45e16 100644 --- a/doc/tutorials/raster-reprojection.md +++ b/doc/tutorials/raster-reprojection.md @@ -39,10 +39,10 @@ var map = new Map({ If a source (based on `ol/source/TileImage` or `ol/source/Image`) has a projection different from the current `ol/View`’s projection then the reprojection happens automatically under the hood. ### Examples -- [Raster reprojection demo](https://openlayers.org/en/master/examples/reprojection.html) -- [OpenStreetMap to WGS84 reprojection](https://openlayers.org/en/master/examples/reprojection-wgs84.html) -- [Reprojection with EPSG.io database search](https://openlayers.org/en/master/examples/reprojection-by-code.html) -- [Image reprojection](https://openlayers.org/en/master/examples/reprojection-image.html) +- [Raster reprojection demo](https://openlayers.org/en/latest/examples/reprojection.html) +- [OpenStreetMap to WGS84 reprojection](https://openlayers.org/en/latest/examples/reprojection-wgs84.html) +- [Reprojection with EPSG.io database search](https://openlayers.org/en/latest/examples/reprojection-by-code.html) +- [Image reprojection](https://openlayers.org/en/latest/examples/reprojection-image.html) ### Custom projection The easiest way to use a custom projection is to add the [Proj4js](http://proj4js.org/) library to your project and then define the projection using a proj4 definition string. It can be installed with @@ -125,7 +125,7 @@ Although this is mathematically correct behavior of the inverse transformation, A possible general solution would be to calculate the forward transformation for every vertex as well - but this would significantly decrease performance (especially for computationally expensive transformations). Therefore a recommended workaround is to define a proper visibility extent on the `ol.layer.Tile` in the view projection. -Setting such a limit is demonstrated in the [reprojection demo example](https://openlayers.org/en/master/examples/reprojection.html). +Setting such a limit is demonstrated in the [reprojection demo example](https://openlayers.org/en/latest/examples/reprojection.html). ### Resolution calculation When determining source tiles to load, the ideal source resolution needs to be calculated. diff --git a/examples/.eslintrc b/examples/.eslintrc index 769357d35a..c404b2e6e6 100644 --- a/examples/.eslintrc +++ b/examples/.eslintrc @@ -5,6 +5,7 @@ "common": false, "createMapboxStreetsV6Style": false, "d3": false, + "domtoimage": false, "geojsonvt": false, "GyroNorm": false, "jsPDF": false, diff --git a/examples/accessible.js b/examples/accessible.js index 6eb92a4da1..0feda2138f 100644 --- a/examples/accessible.js +++ b/examples/accessible.js @@ -1,29 +1,28 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -document.getElementById('zoom-out').onclick = function() { +document.getElementById('zoom-out').onclick = function () { const view = map.getView(); const zoom = view.getZoom(); view.setZoom(zoom - 1); }; -document.getElementById('zoom-in').onclick = function() { +document.getElementById('zoom-in').onclick = function () { const view = map.getView(); const zoom = view.getZoom(); view.setZoom(zoom + 1); diff --git a/examples/animation.js b/examples/animation.js index ad59685ab5..7d07a41306 100644 --- a/examples/animation.js +++ b/examples/animation.js @@ -1,9 +1,9 @@ import Map from '../src/ol/Map.js'; +import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; import View from '../src/ol/View.js'; import {easeIn, easeOut} from '../src/ol/easing.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import {fromLonLat} from '../src/ol/proj.js'; -import OSM from '../src/ol/source/OSM.js'; const london = fromLonLat([-0.12755, 51.507222]); const moscow = fromLonLat([37.6178, 55.7517]); @@ -13,7 +13,7 @@ const bern = fromLonLat([7.4458, 46.95]); const view = new View({ center: istanbul, - zoom: 6 + zoom: 6, }); const map = new Map({ @@ -21,10 +21,10 @@ const map = new Map({ layers: [ new TileLayer({ preload: 4, - source: new OSM() - }) + source: new OSM(), + }), ], - view: view + view: view, }); // A bounce easing method (from https://github.com/DmitryBaranovskiy/raphael). @@ -32,18 +32,18 @@ function bounce(t) { const s = 7.5625; const p = 2.75; let l; - if (t < (1 / p)) { + if (t < 1 / p) { l = s * t * t; } else { - if (t < (2 / p)) { - t -= (1.5 / p); + if (t < 2 / p) { + t -= 1.5 / p; l = s * t * t + 0.75; } else { - if (t < (2.5 / p)) { - t -= (2.25 / p); + if (t < 2.5 / p) { + t -= 2.25 / p; l = s * t * t + 0.9375; } else { - t -= (2.625 / p); + t -= 2.625 / p; l = s * t * t + 0.984375; } } @@ -53,77 +53,85 @@ function bounce(t) { // An elastic easing method (from https://github.com/DmitryBaranovskiy/raphael). function elastic(t) { - return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1; + return ( + Math.pow(2, -10 * t) * Math.sin(((t - 0.075) * (2 * Math.PI)) / 0.3) + 1 + ); } function onClick(id, callback) { document.getElementById(id).addEventListener('click', callback); } -onClick('rotate-left', function() { +onClick('rotate-left', function () { view.animate({ - rotation: view.getRotation() + Math.PI / 2 + rotation: view.getRotation() + Math.PI / 2, }); }); -onClick('rotate-right', function() { +onClick('rotate-right', function () { view.animate({ - rotation: view.getRotation() - Math.PI / 2 + rotation: view.getRotation() - Math.PI / 2, }); }); -onClick('rotate-around-rome', function() { +onClick('rotate-around-rome', function () { // Rotation animation takes the shortest arc, so animate in two parts const rotation = view.getRotation(); - view.animate({ - rotation: rotation + Math.PI, - anchor: rome, - easing: easeIn - }, { - rotation: rotation + 2 * Math.PI, - anchor: rome, - easing: easeOut - }); + view.animate( + { + rotation: rotation + Math.PI, + anchor: rome, + easing: easeIn, + }, + { + rotation: rotation + 2 * Math.PI, + anchor: rome, + easing: easeOut, + } + ); }); -onClick('pan-to-london', function() { +onClick('pan-to-london', function () { view.animate({ center: london, - duration: 2000 + duration: 2000, }); }); -onClick('elastic-to-moscow', function() { +onClick('elastic-to-moscow', function () { view.animate({ center: moscow, duration: 2000, - easing: elastic + easing: elastic, }); }); -onClick('bounce-to-istanbul', function() { +onClick('bounce-to-istanbul', function () { view.animate({ center: istanbul, duration: 2000, - easing: bounce + easing: bounce, }); }); -onClick('spin-to-rome', function() { +onClick('spin-to-rome', function () { // Rotation animation takes the shortest arc, so animate in two parts const center = view.getCenter(); - view.animate({ - center: [ - center[0] + (rome[0] - center[0]) / 2, - center[1] + (rome[1] - center[1]) / 2 - ], - rotation: Math.PI, - easing: easeIn - }, { - center: rome, - rotation: 2 * Math.PI, - easing: easeOut - }); + view.animate( + { + center: [ + center[0] + (rome[0] - center[0]) / 2, + center[1] + (rome[1] - center[1]) / 2, + ], + rotation: Math.PI, + easing: easeIn, + }, + { + center: rome, + rotation: 2 * Math.PI, + easing: easeOut, + } + ); }); function flyTo(location, done) { @@ -141,21 +149,28 @@ function flyTo(location, done) { done(complete); } } - view.animate({ - center: location, - duration: duration - }, callback); - view.animate({ - zoom: zoom - 1, - duration: duration / 2 - }, { - zoom: zoom, - duration: duration / 2 - }, callback); + view.animate( + { + center: location, + duration: duration, + }, + callback + ); + view.animate( + { + zoom: zoom - 1, + duration: duration / 2, + }, + { + zoom: zoom, + duration: duration / 2, + }, + callback + ); } -onClick('fly-to-bern', function() { - flyTo(bern, function() {}); +onClick('fly-to-bern', function () { + flyTo(bern, function () {}); }); function tour() { @@ -166,7 +181,7 @@ function tour() { ++index; if (index < locations.length) { const delay = index === 0 ? 0 : 750; - setTimeout(function() { + setTimeout(function () { flyTo(locations[index], next); }, delay); } else { diff --git a/examples/arcgis-image.html b/examples/arcgis-image.html index 87b6e43089..241e0c1def 100644 --- a/examples/arcgis-image.html +++ b/examples/arcgis-image.html @@ -6,6 +6,6 @@ docs: > This example shows how to use a dynamic ArcGIS REST MapService. This source type supports Map and Image Services. For dyamic ArcGIS services. -tags: arcgis, image, dynamiclayer" +tags: "arcgis, image, dynamiclayer" --- diff --git a/examples/arcgis-image.js b/examples/arcgis-image.js index aff5b8f2ee..321b39f25b 100644 --- a/examples/arcgis-image.js +++ b/examples/arcgis-image.js @@ -1,28 +1,29 @@ import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import {Tile as TileLayer, Image as ImageLayer} from '../src/ol/layer.js'; -import {OSM, ImageArcGISRest} from '../src/ol/source.js'; +import {ImageArcGISRest, OSM} from '../src/ol/source.js'; +import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; -const url = 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/' + - 'Specialty/ESRI_StateCityHighway_USA/MapServer'; +const url = + 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/' + + 'Specialty/ESRI_StateCityHighway_USA/MapServer'; const layers = [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new ImageLayer({ source: new ImageArcGISRest({ ratio: 1, params: {}, - url: url - }) - }) + url: url, + }), + }), ]; const map = new Map({ layers: layers, target: 'map', view: new View({ center: [-10997148, 4569099], - zoom: 4 - }) + zoom: 4, + }), }); diff --git a/examples/arcgis-tiled.html b/examples/arcgis-tiled.html index 576abf6b4d..a92546eca5 100644 --- a/examples/arcgis-tiled.html +++ b/examples/arcgis-tiled.html @@ -7,6 +7,6 @@ docs: > This source type supports Map and Image Services. For cached ArcGIS services, better performance is available by using- +-
-
-
-
-
-
-
+
- + + + self.find({longname: v})[0] || {longname: v, name: v.split(/#?event:/)[1]}); - listContent({fires: fires}, 'Fires', printListWithStability) - } + listContent(item, 'Members', printListItem); + listContent(item, 'Typedefs', printListItemWithStability); + listContent(item, 'Methods', printListItemWithStability); + listContent(item, 'Fires', printFiresListItem); }); ?>
ol/source/XYZinstead. -tags: arcgis, tile, tilelayer" +tags: "arcgis, tile, tilelayer" --- diff --git a/examples/arcgis-tiled.js b/examples/arcgis-tiled.js index 4377963891..64f98e4aae 100644 --- a/examples/arcgis-tiled.js +++ b/examples/arcgis-tiled.js @@ -1,27 +1,28 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import {OSM, TileArcGISRest} from '../src/ol/source.js'; -const url = 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/' + - 'Specialty/ESRI_StateCityHighway_USA/MapServer'; +const url = + 'https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/' + + 'Specialty/ESRI_StateCityHighway_USA/MapServer'; const layers = [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new TileLayer({ extent: [-13884991, 2870341, -7455066, 6338219], source: new TileArcGISRest({ - url: url - }) - }) + url: url, + }), + }), ]; const map = new Map({ layers: layers, target: 'map', view: new View({ center: [-10997148, 4569099], - zoom: 4 - }) + zoom: 4, + }), }); diff --git a/examples/attributions.js b/examples/attributions.js index 360a918917..9ee484c4af 100644 --- a/examples/attributions.js +++ b/examples/attributions.js @@ -1,24 +1,24 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, Attribution} from '../src/ol/control.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {Attribution, defaults as defaultControls} from '../src/ol/control.js'; const attribution = new Attribution({ - collapsible: false + collapsible: false, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], controls: defaultControls({attribution: false}).extend([attribution]), target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); function checkSize() { diff --git a/examples/bing-maps.html b/examples/bing-maps.html index a3e7b5b48f..2752130f9e 100644 --- a/examples/bing-maps.html +++ b/examples/bing-maps.html @@ -6,7 +6,7 @@ docs: >When the Bing Maps tile service doesn't have tiles for a given resolution and region it returns "placeholder" tiles indicating that. Zoom the map beyond level 19 to see the "placeholder" tiles. If you want OpenLayers to display stretched tiles in place of "placeholder" tiles beyond zoom level 19 then set
tags: "bing, bing-maps" cloak: - - key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5 + - key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp value: Your Bing Maps Key from http://www.bingmapsportal.com/ here --- diff --git a/examples/bing-maps.js b/examples/bing-maps.js index b0ecb7c2be..77bcdd2b69 100644 --- a/examples/bing-maps.js +++ b/examples/bing-maps.js @@ -1,38 +1,39 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import BingMaps from '../src/ol/source/BingMaps.js'; - +import Map from '../src/ol/Map.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const styles = [ 'RoadOnDemand', 'Aerial', 'AerialWithLabelsOnDemand', 'CanvasDark', - 'OrdnanceSurvey' + 'OrdnanceSurvey', ]; const layers = []; let i, ii; for (i = 0, ii = styles.length; i < ii; ++i) { - layers.push(new TileLayer({ - visible: false, - preload: Infinity, - source: new BingMaps({ - key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5', - imagerySet: styles[i] - // use maxZoom 19 to see stretched tiles instead of the BingMaps - // "no photos at this zoom level" tiles - // maxZoom: 19 + layers.push( + new TileLayer({ + visible: false, + preload: Infinity, + source: new BingMaps({ + key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp', + imagerySet: styles[i], + // use maxZoom 19 to see stretched tiles instead of the BingMaps + // "no photos at this zoom level" tiles + // maxZoom: 19 + }), }) - })); + ); } const map = new Map({ layers: layers, target: 'map', view: new View({ center: [-6655.5402445057125, 6709968.258934638], - zoom: 13 - }) + zoom: 13, + }), }); const select = document.getElementById('layer-select'); diff --git a/examples/box-selection.js b/examples/box-selection.js index 5f6b3de1a8..61962b310d 100644 --- a/examples/box-selection.js +++ b/examples/box-selection.js @@ -1,33 +1,31 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; 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 {DragBox, Select} from '../src/ol/interaction.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {platformModifierKeyOnly} from '../src/ol/events/condition.js'; const vectorSource = new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }); - const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new VectorLayer({ - source: vectorSource - }) + source: vectorSource, + }), ], target: 'map', view: new View({ center: [0, 0], zoom: 2, - constrainRotation: 16 - }) + constrainRotation: 16, + }), }); // a normal select interaction to handle click @@ -38,12 +36,12 @@ const selectedFeatures = select.getFeatures(); // a DragBox interaction used to select features by drawing boxes const dragBox = new DragBox({ - condition: platformModifierKeyOnly + condition: platformModifierKeyOnly, }); map.addInteraction(dragBox); -dragBox.on('boxend', function() { +dragBox.on('boxend', function () { // features that intersect the box geometry are added to the // collection of selected features @@ -54,7 +52,7 @@ dragBox.on('boxend', function() { const oblique = rotation % (Math.PI / 2) !== 0; const candidateFeatures = oblique ? [] : selectedFeatures; const extent = dragBox.getGeometry().getExtent(); - vectorSource.forEachFeatureIntersectingExtent(extent, function(feature) { + vectorSource.forEachFeatureIntersectingExtent(extent, function (feature) { candidateFeatures.push(feature); }); @@ -68,7 +66,7 @@ dragBox.on('boxend', function() { const geometry = dragBox.getGeometry().clone(); geometry.rotate(-rotation, anchor); const extent = geometry.getExtent(); - candidateFeatures.forEach(function(feature) { + candidateFeatures.forEach(function (feature) { const geometry = feature.getGeometry().clone(); geometry.rotate(-rotation, anchor); if (geometry.intersectsExtent(extent)) { @@ -76,18 +74,17 @@ dragBox.on('boxend', function() { } }); } - }); // clear selection when drawing a new box and when clicking on the map -dragBox.on('boxstart', function() { +dragBox.on('boxstart', function () { selectedFeatures.clear(); }); const infoBox = document.getElementById('info'); -selectedFeatures.on(['add', 'remove'], function() { - const names = selectedFeatures.getArray().map(function(feature) { +selectedFeatures.on(['add', 'remove'], function () { + const names = selectedFeatures.getArray().map(function (feature) { return feature.get('name'); }); if (names.length > 0) { diff --git a/examples/button-title.html b/examples/button-title.html index 84f1341dea..0f8540f42e 100644 --- a/examples/button-title.html +++ b/examples/button-title.html @@ -6,8 +6,8 @@ docs: > This example shows how to customize the buttons tooltips with Bootstrap. tags: "custom, tooltip" resources: - - https://code.jquery.com/jquery-2.2.3.min.js - - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css - - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js + - https://code.jquery.com/jquery-3.5.1.min.js + - https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css + - https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js --- diff --git a/examples/button-title.js b/examples/button-title.js index c48462a62f..b42183ea5d 100644 --- a/examples/button-title.js +++ b/examples/button-title.js @@ -1,26 +1,25 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [-8730000, 5930000], rotation: Math.PI / 5, - zoom: 8 - }) + zoom: 8, + }), }); - $('.ol-zoom-in, .ol-zoom-out').tooltip({ - placement: 'right' + placement: 'right', }); $('.ol-rotate-reset, .ol-attribution button[title]').tooltip({ - placement: 'left' + placement: 'left', }); diff --git a/examples/canvas-gradient-pattern.js b/examples/canvas-gradient-pattern.js index 1b91b8593d..3504e5e964 100644 --- a/examples/canvas-gradient-pattern.js +++ b/examples/canvas-gradient-pattern.js @@ -1,11 +1,11 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; -import {DEVICE_PIXEL_RATIO} from '../src/ol/has.js'; +import Map from '../src/ol/Map.js'; import VectorLayer from '../src/ol/layer/Vector.js'; -import {fromLonLat} from '../src/ol/proj.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; +import {DEVICE_PIXEL_RATIO} from '../src/ol/has.js'; import {Fill, Stroke, Style} from '../src/ol/style.js'; +import {fromLonLat} from '../src/ol/proj.js'; const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); @@ -15,7 +15,7 @@ const context = canvas.getContext('2d'); const pixelRatio = DEVICE_PIXEL_RATIO; // Generate a rainbow gradient -const gradient = (function() { +const gradient = (function () { const grad = context.createLinearGradient(0, 0, 512 * pixelRatio, 0); grad.addColorStop(0, 'red'); grad.addColorStop(1 / 6, 'orange'); @@ -28,7 +28,7 @@ const gradient = (function() { })(); // Generate a canvasPattern with two circles on white background -const pattern = (function() { +const pattern = (function () { canvas.width = 8 * pixelRatio; canvas.height = 8 * pixelRatio; // white background @@ -45,7 +45,7 @@ const pattern = (function() { context.arc(4 * pixelRatio, 4 * pixelRatio, 1.5 * pixelRatio, 0, 2 * Math.PI); context.fill(); return context.createPattern(canvas, 'repeat'); -}()); +})(); // Generate style for gradient or pattern fill const fill = new Fill(); @@ -53,8 +53,8 @@ const style = new Style({ fill: fill, stroke: new Stroke({ color: '#333', - width: 2 - }) + width: 2, + }), }); /** @@ -64,7 +64,7 @@ const style = new Style({ * @param {import("../src/ol/Feature.js").default} feature The feature to style. * @return {Style} The style to use for the feature. */ -const getStackedStyle = function(feature) { +const getStackedStyle = function (feature) { const id = feature.getId(); fill.setColor(id > 'J' ? gradient : pattern); return style; @@ -74,19 +74,17 @@ const getStackedStyle = function(feature) { const vectorLayer = new VectorLayer({ source: new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }), - style: getStackedStyle + style: getStackedStyle, }); // … finally create a map with that layer. const map = new Map({ - layers: [ - vectorLayer - ], + layers: [vectorLayer], target: 'map', view: new View({ center: fromLonLat([16, 48]), - zoom: 3 - }) + zoom: 3, + }), }); diff --git a/examples/canvas-tiles.js b/examples/canvas-tiles.js index b8fcb00220..df852b27e9 100644 --- a/examples/canvas-tiles.js +++ b/examples/canvas-tiles.js @@ -1,21 +1,20 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import {OSM, TileDebug} from '../src/ol/source.js'; - const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new TileLayer({ - source: new TileDebug() - }) + source: new TileDebug(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 1 - }) + zoom: 1, + }), }); diff --git a/examples/cartodb.js b/examples/cartodb.js index 81a27bca1b..c385fe1c5c 100644 --- a/examples/cartodb.js +++ b/examples/cartodb.js @@ -1,47 +1,48 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import {CartoDB, OSM} from '../src/ol/source.js'; const mapConfig = { - 'layers': [{ - 'type': 'cartodb', - 'options': { - 'cartocss_version': '2.1.1', - 'cartocss': '#layer { polygon-fill: #F00; }', - 'sql': 'select * from european_countries_e where area > 0' - } - }] + 'layers': [ + { + 'type': 'cartodb', + 'options': { + 'cartocss_version': '2.1.1', + 'cartocss': '#layer { polygon-fill: #F00; }', + 'sql': 'select * from european_countries_e where area > 0', + }, + }, + ], }; const cartoDBSource = new CartoDB({ account: 'documentation', - config: mapConfig + config: mapConfig, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new TileLayer({ - source: cartoDBSource - }) + source: cartoDBSource, + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); function setArea(n) { mapConfig.layers[0].options.sql = - 'select * from european_countries_e where area > ' + n; + 'select * from european_countries_e where area > ' + n; cartoDBSource.setConfig(mapConfig); } - -document.getElementById('country-area').addEventListener('change', function() { +document.getElementById('country-area').addEventListener('change', function () { setArea(this.value); }); diff --git a/examples/center.css b/examples/center.css index f3eea4d4cb..ea1b3377d3 100644 --- a/examples/center.css +++ b/examples/center.css @@ -6,15 +6,16 @@ width: 1000px; height: 600px; } -div.ol-zoom { +.map .ol-zoom { top: 178px; left: 158px; } -div.ol-rotate { +.map .ol-rotate { top: 178px; right: 58px; } -.map div.ol-attribution { +.map .ol-attribution, +.map .ol-attribution.ol-uncollapsible { bottom: 30px; right: 50px; } diff --git a/examples/center.js b/examples/center.js index 7f5ca270ad..df4d8fab3f 100644 --- a/examples/center.js +++ b/examples/center.js @@ -1,72 +1,83 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -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 {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; /** @type {VectorSourcemaxZoomto19in the options passed tool/source/BingMaps.} */ const source = new VectorSource({ url: 'data/geojson/switzerland.geojson', - format: new GeoJSON() + format: new GeoJSON(), }); const style = new Style({ fill: new Fill({ - color: 'rgba(255, 255, 255, 0.6)' + color: 'rgba(255, 255, 255, 0.6)', }), stroke: new Stroke({ color: '#319FD3', - width: 1 + width: 1, }), image: new CircleStyle({ radius: 5, fill: new Fill({ - color: 'rgba(255, 255, 255, 0.6)' + color: 'rgba(255, 255, 255, 0.6)', }), stroke: new Stroke({ color: '#319FD3', - width: 1 - }) - }) + width: 1, + }), + }), }); const vectorLayer = new VectorLayer({ source: source, - style: style + style: style, }); const view = new View({ center: [0, 0], - zoom: 1 + zoom: 1, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), - vectorLayer + vectorLayer, ], target: 'map', - view: view + view: view, }); -const zoomtoswitzerland = - document.getElementById('zoomtoswitzerland'); -zoomtoswitzerland.addEventListener('click', function() { - const feature = source.getFeatures()[0]; - const polygon = feature.getGeometry(); - view.fit(polygon, {padding: [170, 50, 30, 150]}); -}, false); +const zoomtoswitzerland = document.getElementById('zoomtoswitzerland'); +zoomtoswitzerland.addEventListener( + 'click', + function () { + const feature = source.getFeatures()[0]; + const polygon = feature.getGeometry(); + view.fit(polygon, {padding: [170, 50, 30, 150]}); + }, + false +); const zoomtolausanne = document.getElementById('zoomtolausanne'); -zoomtolausanne.addEventListener('click', function() { - const feature = source.getFeatures()[1]; - const point = feature.getGeometry(); - view.fit(point, {padding: [170, 50, 30, 150], minResolution: 50}); -}, false); +zoomtolausanne.addEventListener( + 'click', + function () { + const feature = source.getFeatures()[1]; + const point = feature.getGeometry(); + view.fit(point, {padding: [170, 50, 30, 150], minResolution: 50}); + }, + false +); const centerlausanne = document.getElementById('centerlausanne'); -centerlausanne.addEventListener('click', function() { - const feature = source.getFeatures()[1]; - const point = feature.getGeometry(); - const size = map.getSize(); - view.centerOn(point.getCoordinates(), size, [570, 500]); -}, false); +centerlausanne.addEventListener( + 'click', + function () { + const feature = source.getFeatures()[1]; + const point = feature.getGeometry(); + const size = map.getSize(); + view.centerOn(point.getCoordinates(), size, [570, 500]); + }, + false +); diff --git a/examples/chaikin.js b/examples/chaikin.js index 15112b9721..6f4406356b 100644 --- a/examples/chaikin.js +++ b/examples/chaikin.js @@ -1,8 +1,8 @@ +import Draw from '../src/ol/interaction/Draw.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; -import Draw from '../src/ol/interaction/Draw.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import smooth from 'chaikin-smooth'; @@ -21,17 +21,17 @@ const map = new Map({ layers: [ new TileLayer({ source: new OSM(), - opacity: 0.5 + opacity: 0.5, }), new VectorLayer({ - source: vectorSource - }) + source: vectorSource, + }), ], target: 'map', view: new View({ - center: [1078373.5950, 6871994.5910], - zoom: 5 - }) + center: [1078373.595, 6871994.591], + zoom: 5, + }), }); const shallSmoothen = document.getElementById('shall-smoothen'); @@ -39,10 +39,10 @@ const numIterations = document.getElementById('iterations'); const draw = new Draw({ source: vectorSource, - type: 'LineString' + type: 'LineString', }); map.addInteraction(draw); -draw.on('drawend', function(event) { +draw.on('drawend', function (event) { if (!shallSmoothen.checked) { return; } diff --git a/examples/cluster.js b/examples/cluster.js index b74f9194ab..944e1116b2 100644 --- a/examples/cluster.js +++ b/examples/cluster.js @@ -1,11 +1,16 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import View from '../src/ol/View.js'; +import { + Circle as CircleStyle, + Fill, + Stroke, + Style, + Text, +} from '../src/ol/style.js'; import {Cluster, OSM, Vector as VectorSource} from '../src/ol/source.js'; -import {Circle as CircleStyle, Fill, Stroke, Style, Text} from '../src/ol/style.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const distance = document.getElementById('distance'); @@ -18,18 +23,18 @@ for (let i = 0; i < count; ++i) { } const source = new VectorSource({ - features: features + features: features, }); const clusterSource = new Cluster({ distance: parseInt(distance.value, 10), - source: source + source: source, }); const styleCache = {}; const clusters = new VectorLayer({ source: clusterSource, - style: function(feature) { + style: function (feature) { const size = feature.get('features').length; let style = styleCache[size]; if (!style) { @@ -37,27 +42,27 @@ const clusters = new VectorLayer({ image: new CircleStyle({ radius: 10, stroke: new Stroke({ - color: '#fff' + color: '#fff', }), fill: new Fill({ - color: '#3399CC' - }) + color: '#3399CC', + }), }), text: new Text({ text: size.toString(), fill: new Fill({ - color: '#fff' - }) - }) + color: '#fff', + }), + }), }); styleCache[size] = style; } return style; - } + }, }); const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const map = new Map({ @@ -65,10 +70,10 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -distance.addEventListener('input', function() { +distance.addEventListener('input', function () { clusterSource.setDistance(parseInt(distance.value, 10)); }); diff --git a/examples/color-manipulation.js b/examples/color-manipulation.js index e249762850..dade6aeed2 100644 --- a/examples/color-manipulation.js +++ b/examples/color-manipulation.js @@ -1,23 +1,21 @@ +import ImageLayer from '../src/ol/layer/Image.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import ImageLayer from '../src/ol/layer/Image.js'; import {Raster as RasterSource, Stamen} from '../src/ol/source.js'; - /** * Color manipulation functions below are adapted from * https://github.com/d3/d3-color. */ -const Xn = 0.950470; +const Xn = 0.95047; const Yn = 1; -const Zn = 1.088830; +const Zn = 1.08883; const t0 = 4 / 29; const t1 = 6 / 29; const t2 = 3 * t1 * t1; const t3 = t1 * t1 * t1; const twoPi = 2 * Math.PI; - /** * Convert an RGB pixel into an HCL pixel. * @param {Array } pixel A pixel in RGB space. @@ -29,11 +27,14 @@ function rgb2hcl(pixel) { const blue = rgb2xyz(pixel[2]); const x = xyz2lab( - (0.4124564 * red + 0.3575761 * green + 0.1804375 * blue) / Xn); + (0.4124564 * red + 0.3575761 * green + 0.1804375 * blue) / Xn + ); const y = xyz2lab( - (0.2126729 * red + 0.7151522 * green + 0.0721750 * blue) / Yn); + (0.2126729 * red + 0.7151522 * green + 0.072175 * blue) / Yn + ); const z = xyz2lab( - (0.0193339 * red + 0.1191920 * green + 0.9503041 * blue) / Zn); + (0.0193339 * red + 0.119192 * green + 0.9503041 * blue) / Zn + ); const l = 116 * y - 16; const a = 500 * (x - y); @@ -52,7 +53,6 @@ function rgb2hcl(pixel) { return pixel; } - /** * Convert an HCL pixel into an RGB pixel. * @param {Array } pixel A pixel in HCL space. @@ -75,7 +75,7 @@ function hcl2rgb(pixel) { z = Zn * lab2xyz(z); pixel[0] = xyz2rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z); - pixel[1] = xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z); + pixel[1] = xyz2rgb(-0.969266 * x + 1.8760108 * y + 0.041556 * z); pixel[2] = xyz2rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z); return pixel; @@ -94,18 +94,21 @@ function rgb2xyz(x) { } function xyz2rgb(x) { - return 255 * (x <= 0.0031308 ? - 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055); + return ( + 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055) + ); } const raster = new RasterSource({ - sources: [new Stamen({ - layer: 'watercolor' - })], - operation: function(pixels, data) { + sources: [ + new Stamen({ + layer: 'watercolor', + }), + ], + operation: function (pixels, data) { const hcl = rgb2hcl(pixels[0]); - let h = hcl[0] + Math.PI * data.hue / 180; + let h = hcl[0] + (Math.PI * data.hue) / 180; if (h < 0) { h += twoPi; } else if (h > twoPi) { @@ -113,8 +116,8 @@ const raster = new RasterSource({ } hcl[0] = h; - hcl[1] *= (data.chroma / 100); - hcl[2] *= (data.lightness / 100); + hcl[1] *= data.chroma / 100; + hcl[2] *= data.lightness / 100; return hcl2rgb(hcl); }, @@ -132,13 +135,13 @@ const raster = new RasterSource({ t1: t1, t2: t2, t3: t3, - twoPi: twoPi - } + twoPi: twoPi, + }, }); const controls = {}; -raster.on('beforeoperations', function(event) { +raster.on('beforeoperations', function (event) { const data = event.data; for (const id in controls) { data[id] = Number(controls[id].value); @@ -148,22 +151,22 @@ raster.on('beforeoperations', function(event) { const map = new Map({ layers: [ new ImageLayer({ - source: raster - }) + source: raster, + }), ], target: 'map', view: new View({ center: [0, 2500000], zoom: 2, - maxZoom: 18 - }) + maxZoom: 18, + }), }); const controlIds = ['hue', 'chroma', 'lightness']; -controlIds.forEach(function(id) { +controlIds.forEach(function (id) { const control = document.getElementById(id); const output = document.getElementById(id + 'Out'); - control.addEventListener('input', function() { + control.addEventListener('input', function () { output.innerText = control.value; raster.changed(); }); diff --git a/examples/custom-controls.js b/examples/custom-controls.js index f39be07a83..10c578229f 100644 --- a/examples/custom-controls.js +++ b/examples/custom-controls.js @@ -1,16 +1,14 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, Control} from '../src/ol/control.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {Control, defaults as defaultControls} from '../src/ol/control.js'; // // Define rotate to north control. // class RotateNorthControl extends Control { - /** * @param {Object=} opt_options Control options. */ @@ -26,7 +24,7 @@ class RotateNorthControl extends Control { super({ element: element, - target: options.target + target: options.target, }); button.addEventListener('click', this.handleRotateNorth.bind(this), false); @@ -35,28 +33,23 @@ class RotateNorthControl extends Control { handleRotateNorth() { this.getMap().getView().setRotation(0); } - } - // // Create map, giving it a rotate to north control. // - const map = new Map({ - controls: defaultControls().extend([ - new RotateNorthControl() - ]), + controls: defaultControls().extend([new RotateNorthControl()]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], zoom: 3, - rotation: 1 - }) + rotation: 1, + }), }); diff --git a/examples/custom-interactions.js b/examples/custom-interactions.js index 9fa87a1b5f..ca75edf3ea 100644 --- a/examples/custom-interactions.js +++ b/examples/custom-interactions.js @@ -1,12 +1,14 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import {LineString, Point, Polygon} from '../src/ol/geom.js'; -import {defaults as defaultInteractions, Pointer as PointerInteraction} from '../src/ol/interaction.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {TileJSON, Vector as VectorSource} from '../src/ol/source.js'; import {Fill, Icon, Stroke, Style} from '../src/ol/style.js'; - +import {LineString, Point, Polygon} from '../src/ol/geom.js'; +import { + Pointer as PointerInteraction, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; +import {TileJSON, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; class Drag extends PointerInteraction { constructor() { @@ -14,7 +16,7 @@ class Drag extends PointerInteraction { handleDownEvent: handleDownEvent, handleDragEvent: handleDragEvent, handleMoveEvent: handleMoveEvent, - handleUpEvent: handleUpEvent + handleUpEvent: handleUpEvent, }); /** @@ -43,7 +45,6 @@ class Drag extends PointerInteraction { } } - /** * @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event. * @return {boolean} `true` to start the drag sequence. @@ -51,10 +52,9 @@ class Drag extends PointerInteraction { function handleDownEvent(evt) { const map = evt.map; - const feature = map.forEachFeatureAtPixel(evt.pixel, - function(feature) { - return feature; - }); + const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { + return feature; + }); if (feature) { this.coordinate_ = evt.coordinate; @@ -64,7 +64,6 @@ function handleDownEvent(evt) { return !!feature; } - /** * @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event. */ @@ -79,17 +78,15 @@ function handleDragEvent(evt) { this.coordinate_[1] = evt.coordinate[1]; } - /** * @param {import("../src/ol/MapBrowserEvent.js").default} evt Event. */ function handleMoveEvent(evt) { if (this.cursor_) { const map = evt.map; - const feature = map.forEachFeatureAtPixel(evt.pixel, - function(feature) { - return feature; - }); + const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { + return feature; + }); const element = evt.map.getTargetElement(); if (feature) { if (element.style.cursor != this.cursor_) { @@ -103,7 +100,6 @@ function handleMoveEvent(evt) { } } - /** * @return {boolean} `false` to stop the drag sequence. */ @@ -113,29 +109,43 @@ function handleUpEvent() { return false; } - const pointFeature = new Feature(new Point([0, 0])); const lineFeature = new Feature( - new LineString([[-1e7, 1e6], [-1e6, 3e6]])); + new LineString([ + [-1e7, 1e6], + [-1e6, 3e6], + ]) +); const polygonFeature = new Feature( - new Polygon([[[-3e6, -1e6], [-3e6, 1e6], - [-1e6, 1e6], [-1e6, -1e6], [-3e6, -1e6]]])); + new Polygon([ + [ + [-3e6, -1e6], + [-3e6, 1e6], + [-1e6, 1e6], + [-1e6, -1e6], + [-3e6, -1e6], + ], + ]) +); -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; const map = new Map({ interactions: defaultInteractions().extend([new Drag()]), layers: [ new TileLayer({ source: new TileJSON({ - url: 'https://a.tiles.mapbox.com/v4/aj.1x1-degrees.json?access_token=' + key - }) + url: + 'https://a.tiles.mapbox.com/v4/aj.1x1-degrees.json?access_token=' + + key, + }), }), new VectorLayer({ source: new VectorSource({ - features: [pointFeature, lineFeature, polygonFeature] + features: [pointFeature, lineFeature, polygonFeature], }), style: new Style({ image: new Icon({ @@ -143,21 +153,21 @@ const map = new Map({ anchorXUnits: 'fraction', anchorYUnits: 'pixels', opacity: 0.95, - src: 'data/icon.png' + src: 'data/icon.png', }), stroke: new Stroke({ width: 3, - color: [255, 0, 0, 1] + color: [255, 0, 0, 1], }), fill: new Fill({ - color: [0, 0, 255, 0.6] - }) - }) - }) + color: [0, 0, 255, 0.6], + }), + }), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/d3.js b/examples/d3.js index e15fe1da8d..ae6b352f71 100644 --- a/examples/d3.js +++ b/examples/d3.js @@ -1,24 +1,23 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {getWidth, getCenter} from '../src/ol/extent.js'; -import {Layer, Tile as TileLayer} from '../src/ol/layer.js'; import SourceState from '../src/ol/source/State.js'; -import {fromLonLat, toLonLat} from '../src/ol/proj.js'; import Stamen from '../src/ol/source/Stamen.js'; +import View from '../src/ol/View.js'; +import {Layer, Tile as TileLayer} from '../src/ol/layer.js'; +import {fromLonLat, toLonLat} from '../src/ol/proj.js'; +import {getCenter, getWidth} from '../src/ol/extent.js'; class CanvasLayer extends Layer { - constructor(options) { super(options); this.features = options.features; - this.svg = d3.select(document.createElement('div')).append('svg') + this.svg = d3 + .select(document.createElement('div')) + .append('svg') .style('position', 'absolute'); - this.svg.append('path') - .datum(this.features) - .attr('class', 'boundary'); + this.svg.append('path').datum(this.features).attr('class', 'boundary'); } getSourceState() { @@ -51,7 +50,10 @@ class CanvasLayer extends Layer { const scale = r / frameState.viewState.resolution; const center = toLonLat(getCenter(frameState.extent), projection); - d3Projection.scale(scale).center(center).translate([width / 2, height / 2]); + d3Projection + .scale(scale) + .center(center) + .translate([width / 2, height / 2]); d3Path = d3Path.projection(d3Projection); d3Path(this.features); @@ -59,8 +61,7 @@ class CanvasLayer extends Layer { this.svg.attr('width', width); this.svg.attr('height', height); - this.svg.select('path') - .attr('d', d3Path); + this.svg.select('path').attr('d', d3Path); return this.svg.node(); } @@ -70,25 +71,23 @@ const map = new Map({ layers: [ new TileLayer({ source: new Stamen({ - layer: 'watercolor' - }) - }) + layer: 'watercolor', + }), + }), ], target: 'map', view: new View({ center: fromLonLat([-97, 38]), - zoom: 4 - }) + zoom: 4, + }), }); - /** * Load the topojson data and create an ol/layer/Image for that data. */ -d3.json('data/topojson/us.json').then(function(us) { - +d3.json('data/topojson/us.json').then(function (us) { const layer = new CanvasLayer({ - features: topojson.feature(us, us.objects.counties) + features: topojson.feature(us, us.objects.counties), }); map.addLayer(layer); diff --git a/examples/data/fish.png b/examples/data/fish.png new file mode 100644 index 0000000000..8163d23285 Binary files /dev/null and b/examples/data/fish.png differ diff --git a/examples/data/square.svg b/examples/data/square.svg index 0b7a912a53..e7a5e249f3 100644 --- a/examples/data/square.svg +++ b/examples/data/square.svg @@ -2,6 +2,6 @@ diff --git a/examples/device-orientation.js b/examples/device-orientation.js index 8f7fd602d6..d45579d23d 100644 --- a/examples/device-orientation.js +++ b/examples/device-orientation.js @@ -1,32 +1,31 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import {toRadians} from '../src/ol/math.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {toRadians} from '../src/ol/math.js'; const view = new View({ center: [0, 0], - zoom: 2 + zoom: 2, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', - view: view + view: view, }); function el(id) { return document.getElementById(id); } - const gn = new GyroNorm(); -gn.init().then(function() { - gn.start(function(event) { +gn.init().then(function () { + gn.start(function (event) { const center = view.getCenter(); const resolution = view.getResolution(); const alpha = toRadians(event.do.alpha); diff --git a/examples/disable-image-smoothing.css b/examples/disable-image-smoothing.css new file mode 100644 index 0000000000..db58102d58 --- /dev/null +++ b/examples/disable-image-smoothing.css @@ -0,0 +1,15 @@ +@media (min-width: 800px) { + .wrapper { + display: flex; + } + .half { + padding: 0 10px; + width: 50%; + float: left; + } +} +#opacity { + display: inline-block; + width: 150px; + vertical-align: text-bottom; +} diff --git a/examples/disable-image-smoothing.html b/examples/disable-image-smoothing.html new file mode 100644 index 0000000000..39a452daa6 --- /dev/null +++ b/examples/disable-image-smoothing.html @@ -0,0 +1,45 @@ +--- +layout: example.html +title: Disable Image Smoothing +shortdesc: Example of disabling image smoothing +docs: > + Example of disabling image smoothing when using raster DEM (digital elevation model) data. + The imageSmoothing: falsesetting is used to disable canvas image smoothing during + reprojection and rendering. Elevation data is + calculated from the pixel value returned by forEachLayerAtPixel. For comparison a second map + with smoothing enabled returns inaccuate elevations which are very noticeable close to 3107 meters + due to how elevation is calculated from the pixel value. +tags: "disable image smoothing, xyz, maptiler, reprojection" +cloak: + - key: get_your_own_D6rA4zTHduk6KOKTXzGB + value: Get your own API key at https://www.maptiler.com/cloud/ +--- ++diff --git a/examples/disable-image-smoothing.js b/examples/disable-image-smoothing.js new file mode 100644 index 0000000000..0a6b23923a --- /dev/null +++ b/examples/disable-image-smoothing.js @@ -0,0 +1,120 @@ +import Map from '../src/ol/Map.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import XYZ from '../src/ol/source/XYZ.js'; + +const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; +const attributions = + '© MapTiler ' + + '© OpenStreetMap contributors'; + +const disabledLayer = new TileLayer({ + // specify className so forEachLayerAtPixel can distinguish layers + className: 'ol-layer-dem', + source: new XYZ({ + attributions: attributions, + url: + 'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' + key, + maxZoom: 10, + crossOrigin: '', + imageSmoothing: false, + }), +}); + +const imagery = new TileLayer({ + className: 'ol-layer-imagery', + source: new XYZ({ + attributions: attributions, + url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + maxZoom: 20, + crossOrigin: '', + }), +}); + +const enabledLayer = new TileLayer({ + source: new XYZ({ + attributions: attributions, + url: + 'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' + key, + maxZoom: 10, + crossOrigin: '', + }), +}); + +imagery.on('prerender', function (evt) { + // use opaque background to conceal DEM while fully opaque imagery renders + if (imagery.getOpacity() === 1) { + evt.context.fillStyle = 'white'; + evt.context.fillRect( + 0, + 0, + evt.context.canvas.width, + evt.context.canvas.height + ); + } +}); + +const control = document.getElementById('opacity'); +const output = document.getElementById('output'); +control.addEventListener('input', function () { + output.innerText = control.value; + imagery.setOpacity(control.value / 100); +}); +output.innerText = control.value; +imagery.setOpacity(control.value / 100); + +const view = new View({ + center: [6.893, 45.8295], + zoom: 16, + projection: 'EPSG:4326', +}); + +const map1 = new Map({ + target: 'map1', + layers: [disabledLayer, imagery], + view: view, +}); + +const map2 = new Map({ + target: 'map2', + layers: [enabledLayer], + view: view, +}); + +const info1 = document.getElementById('info1'); +const info2 = document.getElementById('info2'); + +const showElevations = function (evt) { + if (evt.dragging) { + return; + } + map1.forEachLayerAtPixel( + evt.pixel, + function (layer, pixel) { + const height = + -10000 + (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1; + info1.innerText = height.toFixed(1); + }, + { + layerFilter: function (layer) { + return layer === disabledLayer; + }, + } + ); + map2.forEachLayerAtPixel( + evt.pixel, + function (layer, pixel) { + const height = + -10000 + (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1; + info2.innerText = height.toFixed(1); + }, + { + layerFilter: function (layer) { + return layer === enabledLayer; + }, + } + ); +}; + +map1.on('pointermove', showElevations); +map2.on('pointermove', showElevations); diff --git a/examples/drag-and-drop-image-vector.js b/examples/drag-and-drop-image-vector.js index 56491c33dd..d230d1c7b6 100644 --- a/examples/drag-and-drop-image-vector.js +++ b/examples/drag-and-drop-image-vector.js @@ -1,22 +1,23 @@ import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; +import { + DragAndDrop, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; import {GPX, GeoJSON, IGC, KML, TopoJSON} from '../src/ol/format.js'; -import {defaults as defaultInteractions, DragAndDrop} from '../src/ol/interaction.js'; -import {VectorImage as VectorImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; -import {XYZ, Vector as VectorSource} from '../src/ol/source.js'; +import { + Tile as TileLayer, + VectorImage as VectorImageLayer, +} from '../src/ol/layer.js'; +import {Vector as VectorSource, XYZ} from '../src/ol/source.js'; const dragAndDropInteraction = new DragAndDrop({ - formatConstructors: [ - GPX, - GeoJSON, - IGC, - KML, - TopoJSON - ] + formatConstructors: [GPX, GeoJSON, IGC, KML, TopoJSON], }); const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const map = new Map({ @@ -25,31 +26,34 @@ const map = new Map({ new TileLayer({ source: new XYZ({ attributions: attributions, - url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, - maxZoom: 20 - }) - }) + url: + 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + maxZoom: 20, + }), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -dragAndDropInteraction.on('addfeatures', function(event) { +dragAndDropInteraction.on('addfeatures', function (event) { const vectorSource = new VectorSource({ - features: event.features + features: event.features, }); - map.addLayer(new VectorImageLayer({ - source: vectorSource - })); + map.addLayer( + new VectorImageLayer({ + source: vectorSource, + }) + ); map.getView().fit(vectorSource.getExtent()); }); -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { const features = []; - map.forEachFeatureAtPixel(pixel, function(feature) { + map.forEachFeatureAtPixel(pixel, function (feature) { features.push(feature); }); if (features.length > 0) { @@ -64,7 +68,7 @@ const displayFeatureInfo = function(pixel) { } }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } @@ -72,6 +76,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(pixel); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/drag-and-drop.js b/examples/drag-and-drop.js index 0f407fec82..04ba089aee 100644 --- a/examples/drag-and-drop.js +++ b/examples/drag-and-drop.js @@ -1,22 +1,20 @@ import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; +import { + DragAndDrop, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; import {GPX, GeoJSON, IGC, KML, TopoJSON} from '../src/ol/format.js'; -import {defaults as defaultInteractions, DragAndDrop} from '../src/ol/interaction.js'; import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {XYZ, Vector as VectorSource} from '../src/ol/source.js'; +import {Vector as VectorSource, XYZ} from '../src/ol/source.js'; const dragAndDropInteraction = new DragAndDrop({ - formatConstructors: [ - GPX, - GeoJSON, - IGC, - KML, - TopoJSON - ] + formatConstructors: [GPX, GeoJSON, IGC, KML, TopoJSON], }); const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const map = new Map({ @@ -25,31 +23,34 @@ const map = new Map({ new TileLayer({ source: new XYZ({ attributions: attributions, - url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, - maxZoom: 20 - }) - }) + url: + 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + maxZoom: 20, + }), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -dragAndDropInteraction.on('addfeatures', function(event) { +dragAndDropInteraction.on('addfeatures', function (event) { const vectorSource = new VectorSource({ - features: event.features + features: event.features, }); - map.addLayer(new VectorLayer({ - source: vectorSource - })); + map.addLayer( + new VectorLayer({ + source: vectorSource, + }) + ); map.getView().fit(vectorSource.getExtent()); }); -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { const features = []; - map.forEachFeatureAtPixel(pixel, function(feature) { + map.forEachFeatureAtPixel(pixel, function (feature) { features.push(feature); }); if (features.length > 0) { @@ -64,7 +65,7 @@ const displayFeatureInfo = function(pixel) { } }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } @@ -72,6 +73,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(pixel); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/drag-rotate-and-zoom.js b/examples/drag-rotate-and-zoom.js index 88e58a4f8a..f552b25553 100644 --- a/examples/drag-rotate-and-zoom.js +++ b/examples/drag-rotate-and-zoom.js @@ -1,22 +1,22 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultInteractions, DragRotateAndZoom} from '../src/ol/interaction.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import { + DragRotateAndZoom, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; const map = new Map({ - interactions: defaultInteractions().extend([ - new DragRotateAndZoom() - ]), + interactions: defaultInteractions().extend([new DragRotateAndZoom()]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/draw-and-modify-features.js b/examples/draw-and-modify-features.js index 0863a752fb..bc2a56773c 100644 --- a/examples/draw-and-modify-features.js +++ b/examples/draw-and-modify-features.js @@ -1,12 +1,12 @@ import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import {Draw, Modify, Snap} from '../src/ol/interaction.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import {Draw, Modify, Snap} from '../src/ol/interaction.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const source = new VectorSource(); @@ -14,19 +14,19 @@ const vector = new VectorLayer({ source: source, style: new Style({ fill: new Fill({ - color: 'rgba(255, 255, 255, 0.2)' + color: 'rgba(255, 255, 255, 0.2)', }), stroke: new Stroke({ color: '#ffcc33', - width: 2 + width: 2, }), image: new CircleStyle({ radius: 7, fill: new Fill({ - color: '#ffcc33' - }) - }) - }) + color: '#ffcc33', + }), + }), + }), }); const map = new Map({ @@ -34,8 +34,8 @@ const map = new Map({ target: 'map', view: new View({ center: [-11000000, 4600000], - zoom: 4 - }) + zoom: 4, + }), }); const modify = new Modify({source: source}); @@ -47,18 +47,17 @@ const typeSelect = document.getElementById('type'); function addInteractions() { draw = new Draw({ source: source, - type: typeSelect.value + type: typeSelect.value, }); map.addInteraction(draw); snap = new Snap({source: source}); map.addInteraction(snap); - } /** * Handle change event. */ -typeSelect.onchange = function() { +typeSelect.onchange = function () { map.removeInteraction(draw); map.removeInteraction(snap); addInteractions(); diff --git a/examples/draw-features.js b/examples/draw-features.js index 4d0d200b8f..cefff36c35 100644 --- a/examples/draw-features.js +++ b/examples/draw-features.js @@ -1,17 +1,17 @@ +import Draw from '../src/ol/interaction/Draw.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import Draw from '../src/ol/interaction/Draw.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const source = new VectorSource({wrapX: false}); const vector = new VectorLayer({ - source: source + source: source, }); const map = new Map({ @@ -19,8 +19,8 @@ const map = new Map({ target: 'map', view: new View({ center: [-11000000, 4600000], - zoom: 4 - }) + zoom: 4, + }), }); const typeSelect = document.getElementById('type'); @@ -31,17 +31,16 @@ function addInteraction() { if (value !== 'None') { draw = new Draw({ source: source, - type: typeSelect.value + type: typeSelect.value, }); map.addInteraction(draw); } } - /** * Handle change event. */ -typeSelect.onchange = function() { +typeSelect.onchange = function () { map.removeInteraction(draw); addInteraction(); }; diff --git a/examples/draw-freehand.js b/examples/draw-freehand.js index 92cefa6c89..d7d2b08057 100644 --- a/examples/draw-freehand.js +++ b/examples/draw-freehand.js @@ -1,17 +1,17 @@ +import Draw from '../src/ol/interaction/Draw.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import Draw from '../src/ol/interaction/Draw.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const source = new VectorSource({wrapX: false}); const vector = new VectorLayer({ - source: source + source: source, }); const map = new Map({ @@ -19,8 +19,8 @@ const map = new Map({ target: 'map', view: new View({ center: [-11000000, 4600000], - zoom: 4 - }) + zoom: 4, + }), }); const typeSelect = document.getElementById('type'); @@ -32,17 +32,16 @@ function addInteraction() { draw = new Draw({ source: source, type: typeSelect.value, - freehand: true + freehand: true, }); map.addInteraction(draw); } } - /** * Handle change event. */ -typeSelect.onchange = function() { +typeSelect.onchange = function () { map.removeInteraction(draw); addInteraction(); }; diff --git a/examples/draw-shapes.js b/examples/draw-shapes.js index 7ed90d5be0..f02fba2ac8 100644 --- a/examples/draw-shapes.js +++ b/examples/draw-shapes.js @@ -1,18 +1,21 @@ +import Draw, { + createBox, + createRegularPolygon, +} from '../src/ol/interaction/Draw.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Polygon from '../src/ol/geom/Polygon.js'; -import Draw, {createRegularPolygon, createBox} from '../src/ol/interaction/Draw.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import View from '../src/ol/View.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const source = new VectorSource({wrapX: false}); const vector = new VectorLayer({ - source: source + source: source, }); const map = new Map({ @@ -20,8 +23,8 @@ const map = new Map({ target: 'map', view: new View({ center: [-11000000, 4600000], - zoom: 4 - }) + zoom: 4, + }), }); const typeSelect = document.getElementById('type'); @@ -39,7 +42,7 @@ function addInteraction() { geometryFunction = createBox(); } else if (value === 'Star') { value = 'Circle'; - geometryFunction = function(coordinates, geometry) { + geometryFunction = function (coordinates, geometry) { const center = coordinates[0]; const last = coordinates[1]; const dx = center[0] - last[0]; @@ -49,7 +52,7 @@ function addInteraction() { const newCoordinates = []; const numPoints = 12; for (let i = 0; i < numPoints; ++i) { - const angle = rotation + i * 2 * Math.PI / numPoints; + const angle = rotation + (i * 2 * Math.PI) / numPoints; const fraction = i % 2 === 0 ? 1 : 0.5; const offsetX = radius * fraction * Math.cos(angle); const offsetY = radius * fraction * Math.sin(angle); @@ -67,17 +70,16 @@ function addInteraction() { draw = new Draw({ source: source, type: value, - geometryFunction: geometryFunction + geometryFunction: geometryFunction, }); map.addInteraction(draw); } } - /** * Handle change event. */ -typeSelect.onchange = function() { +typeSelect.onchange = function () { map.removeInteraction(draw); addInteraction(); }; diff --git a/examples/dynamic-data.js b/examples/dynamic-data.js index e65a0d21f7..deca3b51aa 100644 --- a/examples/dynamic-data.js +++ b/examples/dynamic-data.js @@ -1,13 +1,13 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {MultiPoint, Point} from '../src/ol/geom.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import {MultiPoint, Point} from '../src/ol/geom.js'; import {getVectorContext} from '../src/ol/render.js'; const tileLayer = new TileLayer({ - source: new OSM() + source: new OSM(), }); const map = new Map({ @@ -15,30 +15,30 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const imageStyle = new Style({ image: new CircleStyle({ radius: 5, fill: new Fill({color: 'yellow'}), - stroke: new Stroke({color: 'red', width: 1}) - }) + stroke: new Stroke({color: 'red', width: 1}), + }), }); const headInnerImageStyle = new Style({ image: new CircleStyle({ radius: 2, - fill: new Fill({color: 'blue'}) - }) + fill: new Fill({color: 'blue'}), + }), }); const headOuterImageStyle = new Style({ image: new CircleStyle({ radius: 5, - fill: new Fill({color: 'black'}) - }) + fill: new Fill({color: 'black'}), + }), }); const n = 200; @@ -46,16 +46,16 @@ const omegaTheta = 30000; // Rotation period in ms const R = 7e6; const r = 2e6; const p = 2e6; -tileLayer.on('postrender', function(event) { +tileLayer.on('postrender', function (event) { const vectorContext = getVectorContext(event); const frameState = event.frameState; - const theta = 2 * Math.PI * frameState.time / omegaTheta; + const theta = (2 * Math.PI * frameState.time) / omegaTheta; const coordinates = []; let i; for (i = 0; i < n; ++i) { - const t = theta + 2 * Math.PI * i / n; - const x = (R + r) * Math.cos(t) + p * Math.cos((R + r) * t / r); - const y = (R + r) * Math.sin(t) + p * Math.sin((R + r) * t / r); + const t = theta + (2 * Math.PI * i) / n; + const x = (R + r) * Math.cos(t) + p * Math.cos(((R + r) * t) / r); + const y = (R + r) * Math.sin(t) + p * Math.sin(((R + r) * t) / r); coordinates.push([x, y]); } vectorContext.setStyle(imageStyle); diff --git a/examples/earthquake-clusters.js b/examples/earthquake-clusters.js index e328f75562..8ffd0602a0 100644 --- a/examples/earthquake-clusters.js +++ b/examples/earthquake-clusters.js @@ -1,29 +1,38 @@ +import KML from '../src/ol/format/KML.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import {createEmpty, getWidth, getHeight, extend} from '../src/ol/extent.js'; -import KML from '../src/ol/format/KML.js'; -import {defaults as defaultInteractions, Select} from '../src/ol/interaction.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import { + Circle as CircleStyle, + Fill, + RegularShape, + Stroke, + Style, + Text, +} from '../src/ol/style.js'; import {Cluster, Stamen, Vector as VectorSource} from '../src/ol/source.js'; -import {Circle as CircleStyle, Fill, RegularShape, Stroke, Style, Text} from '../src/ol/style.js'; - +import { + Select, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {createEmpty, extend, getHeight, getWidth} from '../src/ol/extent.js'; const earthquakeFill = new Fill({ - color: 'rgba(255, 153, 0, 0.8)' + color: 'rgba(255, 153, 0, 0.8)', }); const earthquakeStroke = new Stroke({ color: 'rgba(255, 204, 0, 0.2)', - width: 1 + width: 1, }); const textFill = new Fill({ - color: '#fff' + color: '#fff', }); const textStroke = new Stroke({ color: 'rgba(0, 0, 0, 0.6)', - width: 3 + width: 3, }); const invisibleFill = new Fill({ - color: 'rgba(255, 255, 255, 0.01)' + color: 'rgba(255, 255, 255, 0.01)', }); function createEarthquakeStyle(feature) { @@ -42,14 +51,14 @@ function createEarthquakeStyle(feature) { points: 5, angle: Math.PI, fill: earthquakeFill, - stroke: earthquakeStroke - }) + stroke: earthquakeStroke, + }), }); } let maxFeatureCount; let vector = null; -const calculateClusterInfo = function(resolution) { +const calculateClusterInfo = function (resolution) { maxFeatureCount = 0; const features = vector.getSource().getFeatures(); let feature, radius; @@ -62,8 +71,7 @@ const calculateClusterInfo = function(resolution) { extend(extent, originalFeatures[j].getGeometry().getExtent()); } maxFeatureCount = Math.max(maxFeatureCount, jj); - radius = 0.25 * (getWidth(extent) + getHeight(extent)) / - resolution; + radius = (0.25 * (getWidth(extent) + getHeight(extent))) / resolution; feature.set('radius', radius); } }; @@ -81,14 +89,14 @@ function styleFunction(feature, resolution) { image: new CircleStyle({ radius: feature.get('radius'), fill: new Fill({ - color: [255, 153, 0, Math.min(0.8, 0.4 + (size / maxFeatureCount))] - }) + color: [255, 153, 0, Math.min(0.8, 0.4 + size / maxFeatureCount)], + }), }), text: new Text({ text: size.toString(), fill: textFill, - stroke: textStroke - }) + stroke: textStroke, + }), }); } else { const originalFeature = feature.get('features')[0]; @@ -98,12 +106,14 @@ function styleFunction(feature, resolution) { } function selectStyleFunction(feature) { - const styles = [new Style({ - image: new CircleStyle({ - radius: feature.get('radius'), - fill: invisibleFill - }) - })]; + const styles = [ + new Style({ + image: new CircleStyle({ + radius: feature.get('radius'), + fill: invisibleFill, + }), + }), + ]; const originalFeatures = feature.get('features'); let originalFeature; for (let i = originalFeatures.length - 1; i >= 0; --i) { @@ -119,31 +129,32 @@ vector = new VectorLayer({ source: new VectorSource({ url: 'data/kml/2012_Earthquakes_Mag5.kml', format: new KML({ - extractStyles: false - }) - }) + extractStyles: false, + }), + }), }), - style: styleFunction + style: styleFunction, }); const raster = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); const map = new Map({ layers: [raster, vector], - interactions: defaultInteractions().extend([new Select({ - condition: function(evt) { - return evt.type == 'pointermove' || - evt.type == 'singleclick'; - }, - style: selectStyleFunction - })]), + interactions: defaultInteractions().extend([ + new Select({ + condition: function (evt) { + return evt.type == 'pointermove' || evt.type == 'singleclick'; + }, + style: selectStyleFunction, + }), + ]), target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/earthquake-custom-symbol.html b/examples/earthquake-custom-symbol.html index 729d8eb3e7..34dd810d67 100644 --- a/examples/earthquake-custom-symbol.html +++ b/examples/earthquake-custom-symbol.html @@ -1,7 +1,7 @@ --- layout: example.html title: Earthquakes with custom symbols -shortdesc: Demonstrates the use of `toCanvas` to create custom icon symbols. +shortdesc: Demonstrates the use of `toContext` to create custom icon symbols. docs: > This example parses a KML file and renders the features as a vector layer. The layer is given a++Smoothing Disabled
+ ++ +++ ++++Uncorrected Comparison
+ ++ ++stylethat renders earthquake locations with a custom lightning symbol and a size relative to their magnitude. tags: "KML, vector, style, canvas, symbol" diff --git a/examples/earthquake-custom-symbol.js b/examples/earthquake-custom-symbol.js index 917c1ada8e..45659589b4 100644 --- a/examples/earthquake-custom-symbol.js +++ b/examples/earthquake-custom-symbol.js @@ -1,22 +1,29 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import KML from '../src/ol/format/KML.js'; +import Map from '../src/ol/Map.js'; import Polygon from '../src/ol/geom/Polygon.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {toContext} from '../src/ol/render.js'; import Stamen from '../src/ol/source/Stamen.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Fill, Icon, Stroke, Style} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {toContext} from '../src/ol/render.js'; - -const symbol = [[0, 0], [4, 2], [6, 0], [10, 5], [6, 3], [4, 5], [0, 0]]; +const symbol = [ + [0, 0], + [4, 2], + [6, 0], + [10, 5], + [6, 3], + [4, 5], + [0, 0], +]; let scale; -const scaleFunction = function(coordinate) { +const scaleFunction = function (coordinate) { return [coordinate[0] * scale, coordinate[1] * scale]; }; const styleCache = {}; -const styleFunction = function(feature) { +const styleFunction = function (feature) { // 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a // standards-violatingtag in each Placemark. We extract it from // the Placemark's name instead. @@ -27,19 +34,23 @@ const styleFunction = function(feature) { let style = styleCache[size]; if (!style) { const canvas = document.createElement('canvas'); - const vectorContext = toContext(canvas.getContext('2d'), - {size: [size, size], pixelRatio: 1}); - vectorContext.setStyle(new Style({ - fill: new Fill({color: 'rgba(255, 153, 0, 0.4)'}), - stroke: new Stroke({color: 'rgba(255, 204, 0, 0.2)', width: 2}) - })); + const vectorContext = toContext(canvas.getContext('2d'), { + size: [size, size], + pixelRatio: 1, + }); + vectorContext.setStyle( + new Style({ + fill: new Fill({color: 'rgba(255, 153, 0, 0.4)'}), + stroke: new Stroke({color: 'rgba(255, 204, 0, 0.2)', width: 2}), + }) + ); vectorContext.drawGeometry(new Polygon([symbol.map(scaleFunction)])); style = new Style({ image: new Icon({ img: canvas, imgSize: [size, size], - rotation: 1.2 - }) + rotation: 1.2, + }), }); styleCache[size] = style; } @@ -50,16 +61,16 @@ const vector = new VectorLayer({ source: new VectorSource({ url: 'data/kml/2012_Earthquakes_Mag5.kml', format: new KML({ - extractStyles: false - }) + extractStyles: false, + }), }), - style: styleFunction + style: styleFunction, }); const raster = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); const map = new Map({ @@ -67,6 +78,6 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/edit-geographic.js b/examples/edit-geographic.js index 6c0cd07c1f..857e06ee20 100644 --- a/examples/edit-geographic.js +++ b/examples/edit-geographic.js @@ -1,46 +1,46 @@ -import {Map, View} from '../src/ol/index.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; -import {Modify, Select, Draw, Snap} from '../src/ol/interaction.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {Draw, Modify, Select, Snap} from '../src/ol/interaction.js'; +import {Map, View} from '../src/ol/index.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {useGeographic} from '../src/ol/proj.js'; useGeographic(); const source = new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }); const map = new Map({ target: 'map', layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new VectorLayer({ - source: source - }) + source: source, + }), ], view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const select = new Select(); const modify = new Modify({ - features: select.getFeatures() + features: select.getFeatures(), }); const draw = new Draw({ type: 'Polygon', - source: source + source: source, }); const snap = new Snap({ - source: source + source: source, }); function removeInteractions() { diff --git a/examples/epsg-4326.js b/examples/epsg-4326.js index 86cf815629..9ac4146e40 100644 --- a/examples/epsg-4326.js +++ b/examples/epsg-4326.js @@ -1,9 +1,8 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, ScaleLine} from '../src/ol/control.js'; import TileLayer from '../src/ol/layer/Tile.js'; import TileWMS from '../src/ol/source/TileWMS.js'; - +import View from '../src/ol/View.js'; +import {ScaleLine, defaults as defaultControls} from '../src/ol/control.js'; const layers = [ new TileLayer({ @@ -11,23 +10,23 @@ const layers = [ url: 'https://ahocevar.com/geoserver/wms', params: { 'LAYERS': 'ne:NE1_HR_LC_SR_W_DR', - 'TILED': true - } - }) - }) + 'TILED': true, + }, + }), + }), ]; const map = new Map({ controls: defaultControls().extend([ new ScaleLine({ - units: 'degrees' - }) + units: 'degrees', + }), ]), layers: layers, target: 'map', view: new View({ projection: 'EPSG:4326', center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/es2015-custom-element.html b/examples/es2015-custom-element.html new file mode 100644 index 0000000000..a9d76bc683 --- /dev/null +++ b/examples/es2015-custom-element.html @@ -0,0 +1,9 @@ +--- +layout: example.html +title: Custom map element +shortdesc: Example of a custom element with a map. +docs: > + The example creates and registers a custom element, `ol-map`, which contains a simple map. **Note:** Only works in browsers that supports `ShadowRoot`. +tags: "es2015, web-component, custom-element, shadow-dom" +--- + diff --git a/examples/es2015-custom-element.js b/examples/es2015-custom-element.js new file mode 100644 index 0000000000..4a4dbd8901 --- /dev/null +++ b/examples/es2015-custom-element.js @@ -0,0 +1,41 @@ +import Map from '../src/ol/Map.js'; +import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; + +class OLComponent extends HTMLElement { + constructor() { + super(); + this.shadow = this.attachShadow({mode: 'open'}); + const link = document.createElement('link'); + link.setAttribute('rel', 'stylesheet'); + link.setAttribute('href', 'css/ol.css'); + this.shadow.appendChild(link); + const style = document.createElement('style'); + style.innerText = ` + :host { + display: block; + } + `; + this.shadow.appendChild(style); + const div = document.createElement('div'); + div.style.width = '100%'; + div.style.height = '100%'; + this.shadow.appendChild(div); + + this.map = new Map({ + target: div, + layers: [ + new TileLayer({ + source: new OSM(), + }), + ], + view: new View({ + center: [0, 0], + zoom: 2, + }), + }); + } +} + +customElements.define('ol-map', OLComponent); diff --git a/examples/export-map.js b/examples/export-map.js index 0039f0f1d8..ca3836b8ef 100644 --- a/examples/export-map.js +++ b/examples/export-map.js @@ -1,48 +1,57 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -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 {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new VectorLayer({ source: new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }), - opacity: 0.5 - }) + opacity: 0.5, + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -document.getElementById('export-png').addEventListener('click', function() { - map.once('rendercomplete', function() { +document.getElementById('export-png').addEventListener('click', function () { + map.once('rendercomplete', function () { const mapCanvas = document.createElement('canvas'); const size = map.getSize(); mapCanvas.width = size[0]; mapCanvas.height = size[1]; const mapContext = mapCanvas.getContext('2d'); - Array.prototype.forEach.call(document.querySelectorAll('.ol-layer canvas'), function(canvas) { - if (canvas.width > 0) { - const opacity = canvas.parentNode.style.opacity; - mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity); - const transform = canvas.style.transform; - // Get the transform parameters from the style's transform matrix - const matrix = transform.match(/^matrix\(([^\(]*)\)$/)[1].split(',').map(Number); - // Apply the transform to the export map context - CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix); - mapContext.drawImage(canvas, 0, 0); + Array.prototype.forEach.call( + document.querySelectorAll('.ol-layer canvas'), + function (canvas) { + if (canvas.width > 0) { + const opacity = canvas.parentNode.style.opacity; + mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity); + const transform = canvas.style.transform; + // Get the transform parameters from the style's transform matrix + const matrix = transform + .match(/^matrix\(([^\(]*)\)$/)[1] + .split(',') + .map(Number); + // Apply the transform to the export map context + CanvasRenderingContext2D.prototype.setTransform.apply( + mapContext, + matrix + ); + mapContext.drawImage(canvas, 0, 0); + } } - }); + ); if (navigator.msSaveBlob) { // link download attribuute does not work on MS browsers navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png'); diff --git a/examples/export-pdf.js b/examples/export-pdf.js index 97dac9b59e..3d1bb4fcc0 100644 --- a/examples/export-pdf.js +++ b/examples/export-pdf.js @@ -1,94 +1,110 @@ import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; 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 {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const format = new WKT(); const feature = format.readFeature( 'POLYGON((10.689697265625 -25.0927734375, 34.595947265625 ' + - '-20.1708984375, 38.814697265625 -35.6396484375, 13.502197265625 ' + - '-39.1552734375, 10.689697265625 -25.0927734375))'); + '-20.1708984375, 38.814697265625 -35.6396484375, 13.502197265625 ' + + '-39.1552734375, 10.689697265625 -25.0927734375))' +); feature.getGeometry().transform('EPSG:4326', 'EPSG:3857'); const vector = new VectorLayer({ source: new VectorSource({ - features: [feature] + features: [feature], }), - opacity: 0.5 + opacity: 0.5, }); - const map = new Map({ layers: [raster, vector], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); - const dims = { a0: [1189, 841], a1: [841, 594], a2: [594, 420], a3: [420, 297], a4: [297, 210], - a5: [210, 148] + a5: [210, 148], }; - const exportButton = document.getElementById('export-pdf'); -exportButton.addEventListener('click', function() { +exportButton.addEventListener( + 'click', + function () { + exportButton.disabled = true; + document.body.style.cursor = 'progress'; - exportButton.disabled = true; - document.body.style.cursor = 'progress'; + const format = document.getElementById('format').value; + const resolution = document.getElementById('resolution').value; + const dim = dims[format]; + const width = Math.round((dim[0] * resolution) / 25.4); + const height = Math.round((dim[1] * resolution) / 25.4); + const size = map.getSize(); + const viewResolution = map.getView().getResolution(); - const format = document.getElementById('format').value; - const resolution = document.getElementById('resolution').value; - const dim = dims[format]; - const width = Math.round(dim[0] * resolution / 25.4); - const height = Math.round(dim[1] * resolution / 25.4); - const size = map.getSize(); - const viewResolution = map.getView().getResolution(); - - map.once('rendercomplete', function() { - const mapCanvas = document.createElement('canvas'); - mapCanvas.width = width; - mapCanvas.height = height; - const mapContext = mapCanvas.getContext('2d'); - Array.prototype.forEach.call(document.querySelectorAll('.ol-layer canvas'), function(canvas) { - if (canvas.width > 0) { - const opacity = canvas.parentNode.style.opacity; - mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity); - const transform = canvas.style.transform; - // Get the transform parameters from the style's transform matrix - const matrix = transform.match(/^matrix\(([^\(]*)\)$/)[1].split(',').map(Number); - // Apply the transform to the export map context - CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix); - mapContext.drawImage(canvas, 0, 0); - } + map.once('rendercomplete', function () { + const mapCanvas = document.createElement('canvas'); + mapCanvas.width = width; + mapCanvas.height = height; + const mapContext = mapCanvas.getContext('2d'); + Array.prototype.forEach.call( + document.querySelectorAll('.ol-layer canvas'), + function (canvas) { + if (canvas.width > 0) { + const opacity = canvas.parentNode.style.opacity; + mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity); + const transform = canvas.style.transform; + // Get the transform parameters from the style's transform matrix + const matrix = transform + .match(/^matrix\(([^\(]*)\)$/)[1] + .split(',') + .map(Number); + // Apply the transform to the export map context + CanvasRenderingContext2D.prototype.setTransform.apply( + mapContext, + matrix + ); + mapContext.drawImage(canvas, 0, 0); + } + } + ); + const pdf = new jsPDF('landscape', undefined, format); + pdf.addImage( + mapCanvas.toDataURL('image/jpeg'), + 'JPEG', + 0, + 0, + dim[0], + dim[1] + ); + pdf.save('map.pdf'); + // Reset original map size + map.setSize(size); + map.getView().setResolution(viewResolution); + exportButton.disabled = false; + document.body.style.cursor = 'auto'; }); - const pdf = new jsPDF('landscape', undefined, format); - pdf.addImage(mapCanvas.toDataURL('image/jpeg'), 'JPEG', 0, 0, dim[0], dim[1]); - pdf.save('map.pdf'); - // Reset original map size - map.setSize(size); - map.getView().setResolution(viewResolution); - exportButton.disabled = false; - document.body.style.cursor = 'auto'; - }); - // Set print size - const printSize = [width, height]; - map.setSize(printSize); - const scaling = Math.min(width / size[0], height / size[1]); - map.getView().setResolution(viewResolution / scaling); - -}, false); + // Set print size + const printSize = [width, height]; + map.setSize(printSize); + const scaling = Math.min(width / size[0], height / size[1]); + map.getView().setResolution(viewResolution / scaling); + }, + false +); diff --git a/examples/extent-constrained.js b/examples/extent-constrained.js index 70613dd536..1fbdb14ac9 100644 --- a/examples/extent-constrained.js +++ b/examples/extent-constrained.js @@ -1,25 +1,24 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; -import {defaults as defaultControls} from '../src/ol/control.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import ZoomSlider from '../src/ol/control/ZoomSlider.js'; +import {defaults as defaultControls} from '../src/ol/control.js'; const view = new View({ center: [328627.563458, 5921296.662223], zoom: 8, - extent: [-572513.341856, 5211017.966314, - 916327.095083, 6636950.728974] + extent: [-572513.341856, 5211017.966314, 916327.095083, 6636950.728974], }); new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], keyboardEventTarget: document, target: 'map', view: view, - controls: defaultControls().extend([new ZoomSlider()]) + controls: defaultControls().extend([new ZoomSlider()]), }); diff --git a/examples/extent-interaction.js b/examples/extent-interaction.js index 0925665abf..dbd519a137 100644 --- a/examples/extent-interaction.js +++ b/examples/extent-interaction.js @@ -1,43 +1,31 @@ +import ExtentInteraction from '../src/ol/interaction/Extent.js'; +import GeoJSON from '../src/ol/format/GeoJSON.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.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'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {shiftKeyOnly} from '../src/ol/events/condition.js'; const vectorSource = new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new VectorLayer({ - source: vectorSource - }) + source: vectorSource, + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -const extent = new ExtentInteraction(); +const extent = new ExtentInteraction({condition: shiftKeyOnly}); map.addInteraction(extent); -extent.setActive(false); - -//Enable interaction by holding shift -window.addEventListener('keydown', function(event) { - if (event.keyCode == 16) { - extent.setActive(true); - } -}); -window.addEventListener('keyup', function(event) { - if (event.keyCode == 16) { - extent.setActive(false); - } -}); diff --git a/examples/feature-animation.js b/examples/feature-animation.js index 27fcec3eed..c1391ff2a1 100644 --- a/examples/feature-animation.js +++ b/examples/feature-animation.js @@ -1,19 +1,19 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import {unByKey} from '../src/ol/Observable.js'; -import View from '../src/ol/View.js'; -import {easeOut} from '../src/ol/easing.js'; import Point from '../src/ol/geom/Point.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {fromLonLat} from '../src/ol/proj.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Stroke, Style} from '../src/ol/style.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {easeOut} from '../src/ol/easing.js'; +import {fromLonLat} from '../src/ol/proj.js'; import {getVectorContext} from '../src/ol/render.js'; +import {unByKey} from '../src/ol/Observable.js'; const tileLayer = new TileLayer({ source: new OSM({ - wrapX: false - }) + wrapX: false, + }), }); const map = new Map({ @@ -22,15 +22,15 @@ const map = new Map({ view: new View({ center: [0, 0], zoom: 1, - multiWorld: true - }) + multiWorld: true, + }), }); const source = new VectorSource({ - wrapX: false + wrapX: false, }); const vector = new VectorLayer({ - source: source + source: source, }); map.addLayer(vector); @@ -62,9 +62,9 @@ function flash(feature) { radius: radius, stroke: new Stroke({ color: 'rgba(255, 0, 0, ' + opacity + ')', - width: 0.25 + opacity - }) - }) + width: 0.25 + opacity, + }), + }), }); vectorContext.setStyle(style); @@ -78,7 +78,7 @@ function flash(feature) { } } -source.on('addfeature', function(e) { +source.on('addfeature', function (e) { flash(e.feature); }); diff --git a/examples/feature-move-animation.js b/examples/feature-move-animation.js index e3c38fdc9a..3210ad650d 100644 --- a/examples/feature-move-animation.js +++ b/examples/feature-move-animation.js @@ -1,12 +1,18 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import Polyline from '../src/ol/format/Polyline.js'; import Point from '../src/ol/geom/Point.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import XYZ from '../src/ol/source/XYZ.js'; +import Polyline from '../src/ol/format/Polyline.js'; import VectorSource from '../src/ol/source/Vector.js'; -import {Circle as CircleStyle, Fill, Icon, Stroke, Style} from '../src/ol/style.js'; +import View from '../src/ol/View.js'; +import XYZ from '../src/ol/source/XYZ.js'; +import { + Circle as CircleStyle, + Fill, + Icon, + Stroke, + Style, +} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {getVectorContext} from '../src/ol/render.js'; // This long string is placed here due to jsFiddle limitations. @@ -50,14 +56,16 @@ const polyline = [ 'ab@`CuOlC}YnAcV`@_^m@aeB}@yk@YuTuBg^uCkZiGk\\yGeY}Lu_@oOsZiTe[uWi[sl@', 'mo@soAauAsrBgzBqgAglAyd@ig@asAcyAklA}qAwHkGi{@s~@goAmsAyDeEirB_{B}IsJ', 'uEeFymAssAkdAmhAyTcVkFeEoKiH}l@kp@wg@sj@ku@ey@uh@kj@}EsFmG}Jk^_r@_f@m', - '~@ym@yjA??a@cFd@kBrCgDbAUnAcBhAyAdk@et@??kF}D??OL' + '~@ym@yjA??a@cFd@kBrCgDbAUnAcBhAyAdk@et@??kF}D??OL', ].join(''); -const route = /** @type {import("../src/ol/geom/LineString.js").default} */ (new Polyline({ - factor: 1e6 -}).readGeometry(polyline, { +const route = /** @type {import("../src/ol/geom/LineString.js").default} */ (new Polyline( + { + factor: 1e6, + } +).readGeometry(polyline, { dataProjection: 'EPSG:4326', - featureProjection: 'EPSG:3857' + featureProjection: 'EPSG:3857', })); const routeCoords = route.getCoordinates(); @@ -65,42 +73,46 @@ const routeLength = routeCoords.length; const routeFeature = new Feature({ type: 'route', - geometry: route + geometry: route, }); -const geoMarker = /** @type Feature */(new Feature({ - type: 'geoMarker', - geometry: new Point(routeCoords[0]) -})); +const geoMarker = /** @type Feature */ (new Feature( + { + type: 'geoMarker', + geometry: new Point(routeCoords[0]), + } +)); const startMarker = new Feature({ type: 'icon', - geometry: new Point(routeCoords[0]) + geometry: new Point(routeCoords[0]), }); const endMarker = new Feature({ type: 'icon', - geometry: new Point(routeCoords[routeLength - 1]) + geometry: new Point(routeCoords[routeLength - 1]), }); const styles = { 'route': new Style({ stroke: new Stroke({ - width: 6, color: [237, 212, 0, 0.8] - }) + width: 6, + color: [237, 212, 0, 0.8], + }), }), 'icon': new Style({ image: new Icon({ anchor: [0.5, 1], - src: 'data/icon.png' - }) + src: 'data/icon.png', + }), }), 'geoMarker': new Style({ image: new CircleStyle({ radius: 7, fill: new Fill({color: 'black'}), stroke: new Stroke({ - color: 'white', width: 2 - }) - }) - }) + color: 'white', + width: 2, + }), + }), + }), }; let animating = false; @@ -110,19 +122,20 @@ const startButton = document.getElementById('start-animation'); const vectorLayer = new VectorLayer({ source: new VectorSource({ - features: [routeFeature, geoMarker, startMarker, endMarker] + features: [routeFeature, geoMarker, startMarker, endMarker], }), - style: function(feature) { + style: function (feature) { // hide geoMarker if animation is active if (animating && feature.get('type') === 'geoMarker') { return null; } return styles[feature.get('type')]; - } + }, }); const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const center = [-5639523.95, -3501274.52]; @@ -132,21 +145,21 @@ const map = new Map({ center: center, zoom: 10, minZoom: 2, - maxZoom: 19 + maxZoom: 19, }), layers: [ new TileLayer({ source: new XYZ({ attributions: attributions, url: 'https://api.maptiler.com/maps/hybrid/{z}/{x}/{y}.jpg?key=' + key, - tileSize: 512 - }) + tileSize: 512, + }), }), - vectorLayer - ] + vectorLayer, + ], }); -const moveFeature = function(event) { +const moveFeature = function (event) { const vectorContext = getVectorContext(event); const frameState = event.frameState; @@ -154,7 +167,7 @@ const moveFeature = function(event) { const elapsedTime = frameState.time - now; // here the trick to increase speed is to jump some indexes // on lineString coordinates - const index = Math.round(speed * elapsedTime / 1000); + const index = Math.round((speed * elapsedTime) / 1000); if (index >= routeLength) { stopAnimation(true); @@ -186,7 +199,6 @@ function startAnimation() { } } - /** * @param {boolean} ended end of animation. */ diff --git a/examples/filter-points-webgl.js b/examples/filter-points-webgl.js index b2d39f0bd6..2306684b78 100644 --- a/examples/filter-points-webgl.js +++ b/examples/filter-points-webgl.js @@ -1,61 +1,54 @@ -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.js'; +import Map from '../src/ol/Map.js'; import Point from '../src/ol/geom/Point.js'; +import Stamen from '../src/ol/source/Stamen.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js'; import {Vector} from '../src/ol/source.js'; import {fromLonLat} from '../src/ol/proj.js'; -import Stamen from '../src/ol/source/Stamen.js'; -import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js'; const vectorSource = new Vector({ - attributions: 'NASA' + attributions: 'NASA', }); const oldColor = 'rgba(242,56,22,0.61)'; const newColor = '#ffe52c'; const period = 12; // animation period in seconds -const animRatio = - ['^', - ['/', - ['%', - ['+', - ['time'], - [ - 'interpolate', - ['linear'], - ['get', 'year'], - 1850, 0, - 2015, period - ] - ], - period +const animRatio = [ + '^', + [ + '/', + [ + '%', + [ + '+', + ['time'], + ['interpolate', ['linear'], ['get', 'year'], 1850, 0, 2015, period], ], - period + period, ], - 0.5 - ]; + period, + ], + 0.5, +]; const style = { variables: { minYear: 1850, - maxYear: 2015 + maxYear: 2015, }, filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']], symbol: { symbolType: 'circle', - size: ['*', + size: [ + '*', ['interpolate', ['linear'], ['get', 'mass'], 0, 8, 200000, 26], - ['-', 1.75, ['*', animRatio, 0.75]] + ['-', 1.75, ['*', animRatio, 0.75]], ], - color: ['interpolate', - ['linear'], - animRatio, - 0, newColor, - 1, oldColor - ], - opacity: ['-', 1.0, ['*', animRatio, 0.75]] - } + color: ['interpolate', ['linear'], animRatio, 0, newColor, 1, oldColor], + opacity: ['-', 1.0, ['*', animRatio, 0.75]], + }, }; // handle input values & events @@ -85,7 +78,7 @@ updateStatusText(); // load data const client = new XMLHttpRequest(); client.open('GET', 'data/csv/meteorite_landings.csv'); -client.onload = function() { +client.onload = function () { const csv = client.responseText; const features = []; @@ -102,11 +95,13 @@ client.onload = function() { continue; } - features.push(new Feature({ - mass: parseFloat(line[1]) || 0, - year: parseInt(line[2]) || 0, - geometry: new Point(coords) - })); + features.push( + new Feature({ + mass: parseFloat(line[1]) || 0, + year: parseInt(line[2]) || 0, + geometry: new Point(coords), + }) + ); } vectorSource.addFeatures(features); @@ -117,20 +112,20 @@ const map = new Map({ layers: [ new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }), new WebGLPointsLayer({ style: style, source: vectorSource, - disableHitDetection: true - }) + disableHitDetection: true, + }), ], target: document.getElementById('map'), view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); // animate the map diff --git a/examples/flight-animation.js b/examples/flight-animation.js index 9445a8d14b..932c579108 100644 --- a/examples/flight-animation.js +++ b/examples/flight-animation.js @@ -1,79 +1,81 @@ import Feature from '../src/ol/Feature.js'; -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import LineString from '../src/ol/geom/LineString.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import Map from '../src/ol/Map.js'; import Stamen from '../src/ol/source/Stamen.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Stroke, Style} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {getVectorContext} from '../src/ol/render.js'; const tileLayer = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); const map = new Map({ - layers: [ - tileLayer - ], + layers: [tileLayer], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const style = new Style({ stroke: new Stroke({ color: '#EAE911', - width: 2 - }) + width: 2, + }), }); const flightsSource = new VectorSource({ wrapX: false, - attributions: 'Flight data by ' + - 'OpenFlights,', - loader: function() { + attributions: + 'Flight data by ' + + 'OpenFlights,', + loader: function () { const url = 'data/openflights/flights.json'; - fetch(url).then(function(response) { - return response.json(); - }).then(function(json) { - const flightsData = json.flights; - for (let i = 0; i < flightsData.length; i++) { - const flight = flightsData[i]; - const from = flight[0]; - const to = flight[1]; + fetch(url) + .then(function (response) { + return response.json(); + }) + .then(function (json) { + const flightsData = json.flights; + for (let i = 0; i < flightsData.length; i++) { + const flight = flightsData[i]; + const from = flight[0]; + const to = flight[1]; - // create an arc circle between the two locations - const arcGenerator = new arc.GreatCircle( - {x: from[1], y: from[0]}, - {x: to[1], y: to[0]}); + // create an arc circle between the two locations + const arcGenerator = new arc.GreatCircle( + {x: from[1], y: from[0]}, + {x: to[1], y: to[0]} + ); - const arcLine = arcGenerator.Arc(100, {offset: 10}); - if (arcLine.geometries.length === 1) { - const line = new LineString(arcLine.geometries[0].coords); - line.transform('EPSG:4326', 'EPSG:3857'); + const arcLine = arcGenerator.Arc(100, {offset: 10}); + if (arcLine.geometries.length === 1) { + const line = new LineString(arcLine.geometries[0].coords); + line.transform('EPSG:4326', 'EPSG:3857'); - const feature = new Feature({ - geometry: line, - finished: false - }); - // add the feature with a delay so that the animation - // for all features does not start at the same time - addLater(feature, i * 50); + const feature = new Feature({ + geometry: line, + finished: false, + }); + // add the feature with a delay so that the animation + // for all features does not start at the same time + addLater(feature, i * 50); + } } - } - tileLayer.on('postrender', animateFlights); - }); - } + tileLayer.on('postrender', animateFlights); + }); + }, }); const flightsLayer = new VectorLayer({ source: flightsSource, - style: function(feature) { + style: function (feature) { // if the animation is still active for a feature, do not // render the feature with the layer style if (feature.get('finished')) { @@ -81,7 +83,7 @@ const flightsLayer = new VectorLayer({ } else { return null; } - } + }, }); map.addLayer(flightsLayer); @@ -117,7 +119,7 @@ function animateFlights(event) { } function addLater(feature, timeout) { - window.setTimeout(function() { + window.setTimeout(function () { feature.set('start', new Date().getTime()); flightsSource.addFeature(feature); }, timeout); diff --git a/examples/fractal.js b/examples/fractal.js index 1953c417bd..d31f4ba1e5 100644 --- a/examples/fractal.js +++ b/examples/fractal.js @@ -1,9 +1,9 @@ import Feature from '../src/ol/Feature.js'; -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import LineString from '../src/ol/geom/LineString.js'; +import Map from '../src/ol/Map.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; const radius = 10e6; const cos30 = Math.cos(Math.PI / 6); @@ -12,15 +12,18 @@ const rise = radius * sin30; const run = radius * cos30; const triangle = new LineString([ - [0, radius], [run, -rise], [-run, -rise], [0, radius] + [0, radius], + [run, -rise], + [-run, -rise], + [0, radius], ]); const feature = new Feature(triangle); const layer = new VectorLayer({ source: new VectorSource({ - features: [feature] - }) + features: [feature], + }), }); const map = new Map({ @@ -28,8 +31,8 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 1 - }) + zoom: 1, + }), }); function makeFractal(depth) { @@ -59,19 +62,19 @@ function injectNodes(startNode) { // first point at 1/3 along the segment const firstNode = { - point: [start[0] + dx / 3, start[1] + dy / 3] + point: [start[0] + dx / 3, start[1] + dy / 3], }; // second point at peak of _/\_ const r = Math.sqrt(dx * dx + dy * dy) / (2 * cos30); const a = Math.atan2(dy, dx) + Math.PI / 6; const secondNode = { - point: [start[0] + r * Math.cos(a), start[1] + r * Math.sin(a)] + point: [start[0] + r * Math.cos(a), start[1] + r * Math.sin(a)], }; // third point at 2/3 along the segment const thirdNode = { - point: [end[0] - dx / 3, end[1] - dy / 3] + point: [end[0] - dx / 3, end[1] - dy / 3], }; startNode.next = firstNode; @@ -80,15 +83,14 @@ function injectNodes(startNode) { thirdNode.next = endNode; } - function coordsToGraph(coordinates) { const graph = { - point: coordinates[0] + point: coordinates[0], }; const length = coordinates.length; for (let level = 0, node = graph; level < length - 1; ++level) { node.next = { - point: coordinates[level + 1] + point: coordinates[level + 1], }; node = node.next; } @@ -111,12 +113,11 @@ function update() { let updateTimer; - /** * Regenerate fractal on depth change. Change events are debounced so updates * only occur every 200ms. */ -depthInput.onchange = function() { +depthInput.onchange = function () { window.clearTimeout(updateTimer); updateTimer = window.setTimeout(update, 200); }; diff --git a/examples/full-screen-drag-rotate-and-zoom.css b/examples/full-screen-drag-rotate-and-zoom.css index ead380e32a..9dd0bbfcef 100644 --- a/examples/full-screen-drag-rotate-and-zoom.css +++ b/examples/full-screen-drag-rotate-and-zoom.css @@ -9,6 +9,6 @@ height: 100%; } /* position the rotate control lower than usual */ -.ol-rotate { +.map .ol-rotate { top: 3em; } diff --git a/examples/full-screen-drag-rotate-and-zoom.js b/examples/full-screen-drag-rotate-and-zoom.js index b393feac6f..10b447f739 100644 --- a/examples/full-screen-drag-rotate-and-zoom.js +++ b/examples/full-screen-drag-rotate-and-zoom.js @@ -1,35 +1,35 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, FullScreen} from '../src/ol/control.js'; -import {defaults as defaultInteractions, DragRotateAndZoom} from '../src/ol/interaction.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; - +import { + DragRotateAndZoom, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; +import {FullScreen, defaults as defaultControls} from '../src/ol/control.js'; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const map = new Map({ - controls: defaultControls().extend([ - new FullScreen() - ]), - interactions: defaultInteractions().extend([ - new DragRotateAndZoom() - ]), + controls: defaultControls().extend([new FullScreen()]), + interactions: defaultInteractions().extend([new DragRotateAndZoom()]), layers: [ new TileLayer({ source: new XYZ({ attributions: attributions, - url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, - maxZoom: 20 - }) - }) + url: + 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + maxZoom: 20, + }), + }), ], target: 'map', view: new View({ center: [-33519607, 5616436], rotation: -Math.PI / 8, - zoom: 8 - }) + zoom: 8, + }), }); diff --git a/examples/full-screen-source.css b/examples/full-screen-source.css index 958e346cc5..6692649886 100644 --- a/examples/full-screen-source.css +++ b/examples/full-screen-source.css @@ -16,7 +16,7 @@ height: 400px; } -.ol-rotate { +.map .ol-rotate { top: 3em; } diff --git a/examples/full-screen-source.js b/examples/full-screen-source.js index ef2f46b068..1abdaecd12 100644 --- a/examples/full-screen-source.js +++ b/examples/full-screen-source.js @@ -1,26 +1,25 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, FullScreen} from '../src/ol/control.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {FullScreen, defaults as defaultControls} from '../src/ol/control.js'; const view = new View({ center: [-9101767, 2822912], - zoom: 14 + zoom: 14, }); const map = new Map({ controls: defaultControls().extend([ new FullScreen({ - source: 'fullscreen' - }) + source: 'fullscreen', + }), ]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', - view: view + view: view, }); diff --git a/examples/full-screen.css b/examples/full-screen.css index 5bb198a848..2ec512bf8b 100644 --- a/examples/full-screen.css +++ b/examples/full-screen.css @@ -8,6 +8,6 @@ .map:fullscreen { height: 100%; } -.ol-rotate { +.map .ol-rotate { top: 3em; } diff --git a/examples/full-screen.js b/examples/full-screen.js index d11a409817..d16fe12055 100644 --- a/examples/full-screen.js +++ b/examples/full-screen.js @@ -1,32 +1,31 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, FullScreen} from '../src/ol/control.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; - +import {FullScreen, defaults as defaultControls} from '../src/ol/control.js'; const view = new View({ center: [-9101767, 2822912], - zoom: 14 + zoom: 14, }); const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const map = new Map({ - controls: defaultControls().extend([ - new FullScreen() - ]), + controls: defaultControls().extend([new FullScreen()]), layers: [ new TileLayer({ source: new XYZ({ attributions: attributions, - url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, - maxZoom: 20 - }) - }) + url: + 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + maxZoom: 20, + }), + }), ], target: 'map', - view: view + view: view, }); diff --git a/examples/geographic.js b/examples/geographic.js index 44adf0f95a..462847a43b 100644 --- a/examples/geographic.js +++ b/examples/geographic.js @@ -1,9 +1,9 @@ -import {useGeographic} from '../src/ol/proj.js'; -import {Map, View, Feature, Overlay} from '../src/ol/index.js'; -import {Point} from '../src/ol/geom.js'; -import {Vector as VectorLayer, Tile as TileLayer} from '../src/ol/layer.js'; +import {Circle, Fill, Style} from '../src/ol/style.js'; +import {Feature, Map, Overlay, View} from '../src/ol/index.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; -import {Style, Circle, Fill} from '../src/ol/style.js'; +import {Point} from '../src/ol/geom.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {useGeographic} from '../src/ol/proj.js'; useGeographic(); @@ -15,26 +15,24 @@ const map = new Map({ target: 'map', view: new View({ center: place, - zoom: 8 + zoom: 8, }), layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), new VectorLayer({ source: new VectorSource({ - features: [ - new Feature(point) - ] + features: [new Feature(point)], }), style: new Style({ image: new Circle({ radius: 9, - fill: new Fill({color: 'red'}) - }) - }) - }) - ] + fill: new Fill({color: 'red'}), + }), + }), + }), + ], }); const element = document.getElementById('popup'); @@ -43,7 +41,7 @@ const popup = new Overlay({ element: element, positioning: 'bottom-center', stopEvent: false, - offset: [0, -10] + offset: [0, -10], }); map.addOverlay(popup); @@ -58,13 +56,13 @@ function formatCoordinate(coordinate) { } const info = document.getElementById('info'); -map.on('moveend', function() { +map.on('moveend', function () { const view = map.getView(); const center = view.getCenter(); info.innerHTML = formatCoordinate(center); }); -map.on('click', function(event) { +map.on('click', function (event) { const feature = map.getFeaturesAtPixel(event.pixel)[0]; if (feature) { const coordinate = feature.getGeometry().getCoordinates(); @@ -72,7 +70,7 @@ map.on('click', function(event) { $(element).popover({ placement: 'top', html: true, - content: formatCoordinate(coordinate) + content: formatCoordinate(coordinate), }); $(element).popover('show'); } else { @@ -80,7 +78,7 @@ map.on('click', function(event) { } }); -map.on('pointermove', function(event) { +map.on('pointermove', function (event) { if (map.hasFeatureAtPixel(event.pixel)) { map.getViewport().style.cursor = 'pointer'; } else { diff --git a/examples/geojson-vt.js b/examples/geojson-vt.js index a61ca1fd50..a19a8f1748 100644 --- a/examples/geojson-vt.js +++ b/examples/geojson-vt.js @@ -1,13 +1,16 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; import OSM from '../src/ol/source/OSM.js'; -import VectorTileSource from '../src/ol/source/VectorTile.js'; -import {Tile as TileLayer, VectorTile as VectorTileLayer} from '../src/ol/layer.js'; import Projection from '../src/ol/proj/Projection.js'; +import VectorTileSource from '../src/ol/source/VectorTile.js'; +import View from '../src/ol/View.js'; +import { + Tile as TileLayer, + VectorTile as VectorTileLayer, +} from '../src/ol/layer.js'; // Converts geojson-vt data to GeoJSON -const replacer = function(key, value) { +const replacer = function (key, value) { if (value.geometry) { let type; const rawType = value.type; @@ -37,9 +40,9 @@ const replacer = function(key, value) { 'type': 'Feature', 'geometry': { 'type': type, - 'coordinates': geometry + 'coordinates': geometry, }, - 'properties': value.tags + 'properties': value.tags, }; } else { return value; @@ -49,44 +52,62 @@ const replacer = function(key, value) { const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const url = 'data/geojson/countries.geojson'; -fetch(url).then(function(response) { - return response.json(); -}).then(function(json) { - const tileIndex = geojsonvt(json, { - extent: 4096, - debug: 1 - }); - const vectorSource = new VectorTileSource({ - format: new GeoJSON({ +fetch(url) + .then(function (response) { + return response.json(); + }) + .then(function (json) { + const tileIndex = geojsonvt(json, { + extent: 4096, + debug: 1, + }); + const format = new GeoJSON({ // Data returned from geojson-vt is in tile pixel units dataProjection: new Projection({ code: 'TILE_PIXELS', units: 'tile-pixels', - extent: [0, 0, 4096, 4096] - }) - }), - tileUrlFunction: function(tileCoord) { - const data = tileIndex.getTile(tileCoord[0], tileCoord[1], tileCoord[2]); - const geojson = JSON.stringify({ - type: 'FeatureCollection', - features: data ? data.features : [] - }, replacer); - return 'data:application/json;charset=UTF-8,' + geojson; - } + extent: [0, 0, 4096, 4096], + }), + }); + const vectorSource = new VectorTileSource({ + tileUrlFunction: function (tileCoord) { + // Use the tile coordinate as a pseudo URL for caching purposes + return JSON.stringify(tileCoord); + }, + tileLoadFunction: function (tile, url) { + const tileCoord = JSON.parse(url); + const data = tileIndex.getTile( + tileCoord[0], + tileCoord[1], + tileCoord[2] + ); + const geojson = JSON.stringify( + { + type: 'FeatureCollection', + features: data ? data.features : [], + }, + replacer + ); + const features = format.readFeatures(geojson, { + extent: vectorSource.getTileGrid().getTileCoordExtent(tileCoord), + featureProjection: map.getView().getProjection(), + }); + tile.setFeatures(features); + }, + }); + const vectorLayer = new VectorTileLayer({ + source: vectorSource, + }); + map.addLayer(vectorLayer); }); - const vectorLayer = new VectorTileLayer({ - source: vectorSource - }); - map.addLayer(vectorLayer); -}); diff --git a/examples/geojson.js b/examples/geojson.js index 28c69856c4..19d4b46f87 100644 --- a/examples/geojson.js +++ b/examples/geojson.js @@ -1,85 +1,84 @@ +import Circle from '../src/ol/geom/Circle.js'; import Feature from '../src/ol/Feature.js'; +import GeoJSON from '../src/ol/format/GeoJSON.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import GeoJSON from '../src/ol/format/GeoJSON.js'; -import Circle from '../src/ol/geom/Circle.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; - +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const image = new CircleStyle({ radius: 5, fill: null, - stroke: new Stroke({color: 'red', width: 1}) + stroke: new Stroke({color: 'red', width: 1}), }); const styles = { 'Point': new Style({ - image: image + image: image, }), 'LineString': new Style({ stroke: new Stroke({ color: 'green', - width: 1 - }) + width: 1, + }), }), 'MultiLineString': new Style({ stroke: new Stroke({ color: 'green', - width: 1 - }) + width: 1, + }), }), 'MultiPoint': new Style({ - image: image + image: image, }), 'MultiPolygon': new Style({ stroke: new Stroke({ color: 'yellow', - width: 1 + width: 1, }), fill: new Fill({ - color: 'rgba(255, 255, 0, 0.1)' - }) + color: 'rgba(255, 255, 0, 0.1)', + }), }), 'Polygon': new Style({ stroke: new Stroke({ color: 'blue', lineDash: [4], - width: 3 + width: 3, }), fill: new Fill({ - color: 'rgba(0, 0, 255, 0.1)' - }) + color: 'rgba(0, 0, 255, 0.1)', + }), }), 'GeometryCollection': new Style({ stroke: new Stroke({ color: 'magenta', - width: 2 + width: 2, }), fill: new Fill({ - color: 'magenta' + color: 'magenta', }), image: new CircleStyle({ radius: 10, fill: null, stroke: new Stroke({ - color: 'magenta' - }) - }) + color: 'magenta', + }), + }), }), 'Circle': new Style({ stroke: new Stroke({ color: 'red', - width: 2 + width: 2, }), fill: new Fill({ - color: 'rgba(255,0,0,0.2)' - }) - }) + color: 'rgba(255,0,0,0.2)', + }), + }), }; -const styleFunction = function(feature) { +const styleFunction = function (feature) { return styles[feature.getGeometry().getType()]; }; @@ -88,93 +87,159 @@ const geojsonObject = { 'crs': { 'type': 'name', 'properties': { - 'name': 'EPSG:3857' - } + 'name': 'EPSG:3857', + }, }, - 'features': [{ - 'type': 'Feature', - 'geometry': { - 'type': 'Point', - 'coordinates': [0, 0] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'LineString', - 'coordinates': [[4e6, -2e6], [8e6, 2e6]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'LineString', - 'coordinates': [[4e6, 2e6], [8e6, -2e6]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [[[-5e6, -1e6], [-4e6, 1e6], [-3e6, -1e6]]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiLineString', - 'coordinates': [ - [[-1e6, -7.5e5], [-1e6, 7.5e5]], - [[1e6, -7.5e5], [1e6, 7.5e5]], - [[-7.5e5, -1e6], [7.5e5, -1e6]], - [[-7.5e5, 1e6], [7.5e5, 1e6]] - ] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiPolygon', - 'coordinates': [ - [[[-5e6, 6e6], [-5e6, 8e6], [-3e6, 8e6], [-3e6, 6e6]]], - [[[-2e6, 6e6], [-2e6, 8e6], [0, 8e6], [0, 6e6]]], - [[[1e6, 6e6], [1e6, 8e6], [3e6, 8e6], [3e6, 6e6]]] - ] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'GeometryCollection', - 'geometries': [{ - 'type': 'LineString', - 'coordinates': [[-5e6, -5e6], [0, -5e6]] - }, { + 'features': [ + { + 'type': 'Feature', + 'geometry': { 'type': 'Point', - 'coordinates': [4e6, -5e6] - }, { + 'coordinates': [0, 0], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [ + [4e6, -2e6], + [8e6, 2e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [ + [4e6, 2e6], + [8e6, -2e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { 'type': 'Polygon', - 'coordinates': [[[1e6, -6e6], [2e6, -4e6], [3e6, -6e6]]] - }] - } - }] + 'coordinates': [ + [ + [-5e6, -1e6], + [-4e6, 1e6], + [-3e6, -1e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiLineString', + 'coordinates': [ + [ + [-1e6, -7.5e5], + [-1e6, 7.5e5], + ], + [ + [1e6, -7.5e5], + [1e6, 7.5e5], + ], + [ + [-7.5e5, -1e6], + [7.5e5, -1e6], + ], + [ + [-7.5e5, 1e6], + [7.5e5, 1e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiPolygon', + 'coordinates': [ + [ + [ + [-5e6, 6e6], + [-5e6, 8e6], + [-3e6, 8e6], + [-3e6, 6e6], + ], + ], + [ + [ + [-2e6, 6e6], + [-2e6, 8e6], + [0, 8e6], + [0, 6e6], + ], + ], + [ + [ + [1e6, 6e6], + [1e6, 8e6], + [3e6, 8e6], + [3e6, 6e6], + ], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'GeometryCollection', + 'geometries': [ + { + 'type': 'LineString', + 'coordinates': [ + [-5e6, -5e6], + [0, -5e6], + ], + }, + { + 'type': 'Point', + 'coordinates': [4e6, -5e6], + }, + { + 'type': 'Polygon', + 'coordinates': [ + [ + [1e6, -6e6], + [2e6, -4e6], + [3e6, -6e6], + ], + ], + }, + ], + }, + }, + ], }; const vectorSource = new VectorSource({ - features: (new GeoJSON()).readFeatures(geojsonObject) + features: new GeoJSON().readFeatures(geojsonObject), }); vectorSource.addFeature(new Feature(new Circle([5e6, 7e6], 1e6))); const vectorLayer = new VectorLayer({ source: vectorSource, - style: styleFunction + style: styleFunction, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), - vectorLayer + vectorLayer, ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/geolocation-orientation.js b/examples/geolocation-orientation.js index b9eae92681..adbc9091d8 100644 --- a/examples/geolocation-orientation.js +++ b/examples/geolocation-orientation.js @@ -1,27 +1,27 @@ import Geolocation from '../src/ol/Geolocation.js'; -import Map from '../src/ol/Map.js'; -import Overlay from '../src/ol/Overlay.js'; -import View from '../src/ol/View.js'; import LineString from '../src/ol/geom/LineString.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import {fromLonLat} from '../src/ol/proj.js'; +import Map from '../src/ol/Map.js'; import OSM from '../src/ol/source/OSM.js'; +import Overlay from '../src/ol/Overlay.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {fromLonLat} from '../src/ol/proj.js'; // creating the view const view = new View({ center: fromLonLat([5.8713, 45.6452]), - zoom: 19 + zoom: 19, }); const tileLayer = new TileLayer({ - source: new OSM() + source: new OSM(), }); // creating the map const map = new Map({ layers: [tileLayer], target: 'map', - view: view + view: view, }); // Geolocation marker @@ -29,7 +29,7 @@ const markerEl = document.getElementById('geolocation_marker'); const marker = new Overlay({ positioning: 'center-center', element: markerEl, - stopEvent: false + stopEvent: false, }); map.addOverlay(marker); @@ -44,14 +44,14 @@ const geolocation = new Geolocation({ trackingOptions: { maximumAge: 10000, enableHighAccuracy: true, - timeout: 600000 - } + timeout: 600000, + }, }); let deltaMean = 500; // the geolocation sampling period mean in ms // Listen to position changes -geolocation.on('change', function() { +geolocation.on('change', function () { const position = geolocation.getPosition(); const accuracy = geolocation.getAccuracy(); const heading = geolocation.getHeading() || 0; @@ -71,27 +71,27 @@ geolocation.on('change', function() { 'Accuracy: ' + accuracy, 'Heading: ' + Math.round(radToDeg(heading)) + '°', 'Speed: ' + (speed * 3.6).toFixed(1) + ' km/h', - 'Delta: ' + Math.round(deltaMean) + 'ms' + 'Delta: ' + Math.round(deltaMean) + 'ms', ].join('
'); document.getElementById('info').innerHTML = html; }); -geolocation.on('error', function() { +geolocation.on('error', function () { alert('geolocation error'); // FIXME we should remove the coordinates in positions }); // convert radians to degrees function radToDeg(rad) { - return rad * 360 / (Math.PI * 2); + return (rad * 360) / (Math.PI * 2); } // convert degrees to radians function degToRad(deg) { - return deg * Math.PI * 2 / 360; + return (deg * Math.PI * 2) / 360; } // modulo for negative values function mod(n) { - return ((n % (2 * Math.PI)) + (2 * Math.PI)) % (2 * Math.PI); + return ((n % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI); } function addPosition(position, heading, m, speed) { @@ -105,7 +105,7 @@ function addPosition(position, heading, m, speed) { // force the rotation change to be less than 180° if (Math.abs(headingDiff) > Math.PI) { - const sign = (headingDiff >= 0) ? 1 : -1; + const sign = headingDiff >= 0 ? 1 : -1; headingDiff = -sign * (2 * Math.PI - Math.abs(headingDiff)); } heading = prevHeading + headingDiff; @@ -130,8 +130,8 @@ function getCenterWithHeading(position, rotation, resolution) { const height = size[1]; return [ - position[0] - Math.sin(rotation) * height * resolution * 1 / 4, - position[1] + Math.cos(rotation) * height * resolution * 1 / 4 + position[0] - (Math.sin(rotation) * height * resolution * 1) / 4, + position[1] + (Math.cos(rotation) * height * resolution * 1) / 4, ]; } @@ -147,61 +147,69 @@ function updateView() { view.setCenter(getCenterWithHeading(c, -c[2], view.getResolution())); view.setRotation(-c[2]); marker.setPosition(c); + map.render(); } } // geolocate device const geolocateBtn = document.getElementById('geolocate'); -geolocateBtn.addEventListener('click', function() { - geolocation.setTracking(true); // Start position tracking +geolocateBtn.addEventListener( + 'click', + function () { + geolocation.setTracking(true); // Start position tracking - tileLayer.on('postrender', updateView); - map.render(); + tileLayer.on('postrender', updateView); + map.render(); - disableButtons(); -}, false); + disableButtons(); + }, + false +); // simulate device move let simulationData; const client = new XMLHttpRequest(); client.open('GET', 'data/geolocation-orientation.json'); - /** * Handle data loading. */ -client.onload = function() { +client.onload = function () { simulationData = JSON.parse(client.responseText).data; }; client.send(); const simulateBtn = document.getElementById('simulate'); -simulateBtn.addEventListener('click', function() { - const coordinates = simulationData; +simulateBtn.addEventListener( + 'click', + function () { + const coordinates = simulationData; - const first = coordinates.shift(); - simulatePositionChange(first); + const first = coordinates.shift(); + simulatePositionChange(first); - let prevDate = first.timestamp; - function geolocate() { - const position = coordinates.shift(); - if (!position) { - return; + let prevDate = first.timestamp; + function geolocate() { + const position = coordinates.shift(); + if (!position) { + return; + } + const newDate = position.timestamp; + simulatePositionChange(position); + window.setTimeout(function () { + prevDate = newDate; + geolocate(); + }, (newDate - prevDate) / 0.5); } - const newDate = position.timestamp; - simulatePositionChange(position); - window.setTimeout(function() { - prevDate = newDate; - geolocate(); - }, (newDate - prevDate) / 0.5); - } - geolocate(); + geolocate(); - tileLayer.on('postrender', updateView); - map.render(); + tileLayer.on('postrender', updateView); + map.render(); - disableButtons(); -}, false); + disableButtons(); + }, + false +); function simulatePositionChange(position) { const coords = position.coords; diff --git a/examples/geolocation.js b/examples/geolocation.js index 4ca461308f..625c25c682 100644 --- a/examples/geolocation.js +++ b/examples/geolocation.js @@ -1,45 +1,45 @@ import Feature from '../src/ol/Feature.js'; import Geolocation from '../src/ol/Geolocation.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const view = new View({ center: [0, 0], - zoom: 2 + zoom: 2, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', - view: view + view: view, }); const geolocation = new Geolocation({ // enableHighAccuracy must be set to true to have the heading value. trackingOptions: { - enableHighAccuracy: true + enableHighAccuracy: true, }, - projection: view.getProjection() + projection: view.getProjection(), }); function el(id) { return document.getElementById(id); } -el('track').addEventListener('change', function() { +el('track').addEventListener('change', function () { geolocation.setTracking(this.checked); }); // update the HTML page when the position changes. -geolocation.on('change', function() { +geolocation.on('change', function () { el('accuracy').innerText = geolocation.getAccuracy() + ' [m]'; el('altitude').innerText = geolocation.getAltitude() + ' [m]'; el('altitudeAccuracy').innerText = geolocation.getAltitudeAccuracy() + ' [m]'; @@ -48,40 +48,41 @@ geolocation.on('change', function() { }); // handle geolocation error. -geolocation.on('error', function(error) { +geolocation.on('error', function (error) { const info = document.getElementById('info'); info.innerHTML = error.message; info.style.display = ''; }); const accuracyFeature = new Feature(); -geolocation.on('change:accuracyGeometry', function() { +geolocation.on('change:accuracyGeometry', function () { accuracyFeature.setGeometry(geolocation.getAccuracyGeometry()); }); const positionFeature = new Feature(); -positionFeature.setStyle(new Style({ - image: new CircleStyle({ - radius: 6, - fill: new Fill({ - color: '#3399CC' +positionFeature.setStyle( + new Style({ + image: new CircleStyle({ + radius: 6, + fill: new Fill({ + color: '#3399CC', + }), + stroke: new Stroke({ + color: '#fff', + width: 2, + }), }), - stroke: new Stroke({ - color: '#fff', - width: 2 - }) }) -})); +); -geolocation.on('change:position', function() { +geolocation.on('change:position', function () { const coordinates = geolocation.getPosition(); - positionFeature.setGeometry(coordinates ? - new Point(coordinates) : null); + positionFeature.setGeometry(coordinates ? new Point(coordinates) : null); }); new VectorLayer({ map: map, source: new VectorSource({ - features: [accuracyFeature, positionFeature] - }) + features: [accuracyFeature, positionFeature], + }), }); diff --git a/examples/getfeatureinfo-image.js b/examples/getfeatureinfo-image.js index 109b2eabea..aa2cc832d7 100644 --- a/examples/getfeatureinfo-image.js +++ b/examples/getfeatureinfo-image.js @@ -1,37 +1,39 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import ImageLayer from '../src/ol/layer/Image.js'; import ImageWMS from '../src/ol/source/ImageWMS.js'; - +import Map from '../src/ol/Map.js'; +import View from '../src/ol/View.js'; const wmsSource = new ImageWMS({ url: 'https://ahocevar.com/geoserver/wms', params: {'LAYERS': 'ne:ne'}, serverType: 'geoserver', - crossOrigin: 'anonymous' + crossOrigin: 'anonymous', }); const wmsLayer = new ImageLayer({ - source: wmsSource + source: wmsSource, }); const view = new View({ center: [0, 0], - zoom: 1 + zoom: 1, }); const map = new Map({ layers: [wmsLayer], target: 'map', - view: view + view: view, }); -map.on('singleclick', function(evt) { +map.on('singleclick', function (evt) { document.getElementById('info').innerHTML = ''; const viewResolution = /** @type {number} */ (view.getResolution()); const url = wmsSource.getFeatureInfoUrl( - evt.coordinate, viewResolution, 'EPSG:3857', - {'INFO_FORMAT': 'text/html'}); + evt.coordinate, + viewResolution, + 'EPSG:3857', + {'INFO_FORMAT': 'text/html'} + ); if (url) { fetch(url) .then((response) => response.text()) @@ -41,12 +43,12 @@ map.on('singleclick', function(evt) { } }); -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } const pixel = map.getEventPixel(evt.originalEvent); - const hit = map.forEachLayerAtPixel(pixel, function() { + const hit = map.forEachLayerAtPixel(pixel, function () { return true; }); map.getTargetElement().style.cursor = hit ? 'pointer' : ''; diff --git a/examples/getfeatureinfo-layers.js b/examples/getfeatureinfo-layers.js index f3e779bd9e..650ed91f55 100644 --- a/examples/getfeatureinfo-layers.js +++ b/examples/getfeatureinfo-layers.js @@ -1,23 +1,27 @@ import WMSGetFeatureInfo from '../src/ol/format/WMSGetFeatureInfo.js'; -fetch('data/wmsgetfeatureinfo/osm-restaurant-hotel.xml').then(function(response) { - return response.text(); -}).then(function(response) { +fetch('data/wmsgetfeatureinfo/osm-restaurant-hotel.xml') + .then(function (response) { + return response.text(); + }) + .then(function (response) { + // this is the standard way to read the features + const allFeatures = new WMSGetFeatureInfo().readFeatures(response); + document.getElementById('all').innerText = allFeatures.length.toString(); - // this is the standard way to read the features - const allFeatures = new WMSGetFeatureInfo().readFeatures(response); - document.getElementById('all').innerText = allFeatures.length.toString(); + // when specifying the 'layers' options, only the features of those + // layers are returned by the format + const hotelFeatures = new WMSGetFeatureInfo({ + layers: ['hotel'], + }).readFeatures(response); + document.getElementById( + 'hotel' + ).innerText = hotelFeatures.length.toString(); - // when specifying the 'layers' options, only the features of those - // layers are returned by the format - const hotelFeatures = new WMSGetFeatureInfo({ - layers: ['hotel'] - }).readFeatures(response); - document.getElementById('hotel').innerText = hotelFeatures.length.toString(); - - const restaurantFeatures = new WMSGetFeatureInfo({ - layers: ['restaurant'] - }).readFeatures(response); - document.getElementById('restaurant').innerText = restaurantFeatures.length.toString(); - -}); + const restaurantFeatures = new WMSGetFeatureInfo({ + layers: ['restaurant'], + }).readFeatures(response); + document.getElementById( + 'restaurant' + ).innerText = restaurantFeatures.length.toString(); + }); diff --git a/examples/getfeatureinfo-tile.js b/examples/getfeatureinfo-tile.js index 574535bbe4..db354c3808 100644 --- a/examples/getfeatureinfo-tile.js +++ b/examples/getfeatureinfo-tile.js @@ -1,37 +1,39 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; import TileWMS from '../src/ol/source/TileWMS.js'; - +import View from '../src/ol/View.js'; const wmsSource = new TileWMS({ url: 'https://ahocevar.com/geoserver/wms', params: {'LAYERS': 'ne:ne', 'TILED': true}, serverType: 'geoserver', - crossOrigin: 'anonymous' + crossOrigin: 'anonymous', }); const wmsLayer = new TileLayer({ - source: wmsSource + source: wmsSource, }); const view = new View({ center: [0, 0], - zoom: 1 + zoom: 1, }); const map = new Map({ layers: [wmsLayer], target: 'map', - view: view + view: view, }); -map.on('singleclick', function(evt) { +map.on('singleclick', function (evt) { document.getElementById('info').innerHTML = ''; const viewResolution = /** @type {number} */ (view.getResolution()); const url = wmsSource.getFeatureInfoUrl( - evt.coordinate, viewResolution, 'EPSG:3857', - {'INFO_FORMAT': 'text/html'}); + evt.coordinate, + viewResolution, + 'EPSG:3857', + {'INFO_FORMAT': 'text/html'} + ); if (url) { fetch(url) .then((response) => response.text()) @@ -41,12 +43,12 @@ map.on('singleclick', function(evt) { } }); -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } const pixel = map.getEventPixel(evt.originalEvent); - const hit = map.forEachLayerAtPixel(pixel, function() { + const hit = map.forEachLayerAtPixel(pixel, function () { return true; }); map.getTargetElement().style.cursor = hit ? 'pointer' : ''; diff --git a/examples/gpx.js b/examples/gpx.js index 7570048b55..60803a680b 100644 --- a/examples/gpx.js +++ b/examples/gpx.js @@ -1,58 +1,59 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GPX from '../src/ol/format/GPX.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import XYZ from '../src/ol/source/XYZ.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 {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +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 - }) + maxZoom: 20, + }), }); const style = { 'Point': new Style({ image: new CircleStyle({ fill: new Fill({ - color: 'rgba(255,255,0,0.4)' + color: 'rgba(255,255,0,0.4)', }), radius: 5, stroke: new Stroke({ color: '#ff0', - width: 1 - }) - }) + width: 1, + }), + }), }), 'LineString': new Style({ stroke: new Stroke({ color: '#f00', - width: 3 - }) + width: 3, + }), }), 'MultiLineString': new Style({ stroke: new Stroke({ color: '#0f0', - width: 3 - }) - }) + width: 3, + }), + }), }; const vector = new VectorLayer({ source: new VectorSource({ url: 'data/gpx/fells_loop.gpx', - format: new GPX() + format: new GPX(), }), - style: function(feature) { + style: function (feature) { return style[feature.getGeometry().getType()]; - } + }, }); const map = new Map({ @@ -60,13 +61,13 @@ const map = new Map({ target: document.getElementById('map'), view: new View({ center: [-7916041.528716288, 5228379.045749711], - zoom: 12 - }) + zoom: 12, + }), }); -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { const features = []; - map.forEachFeatureAtPixel(pixel, function(feature) { + map.forEachFeatureAtPixel(pixel, function (feature) { features.push(feature); }); if (features.length > 0) { @@ -83,7 +84,7 @@ const displayFeatureInfo = function(pixel) { } }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } @@ -91,6 +92,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(pixel); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/graticule.js b/examples/graticule.js index 32d2196b9b..812829c054 100644 --- a/examples/graticule.js +++ b/examples/graticule.js @@ -1,33 +1,32 @@ import Graticule from '../src/ol/layer/Graticule.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import {fromLonLat} from '../src/ol/proj.js'; import OSM from '../src/ol/source/OSM.js'; import Stroke from '../src/ol/style/Stroke.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {fromLonLat} from '../src/ol/proj.js'; const map = new Map({ layers: [ new TileLayer({ source: new OSM({ - wrapX: false - }) + wrapX: false, + }), }), new Graticule({ // the style to use for the lines, optional. strokeStyle: new Stroke({ color: 'rgba(255,120,0,0.9)', width: 2, - lineDash: [0.5, 4] + lineDash: [0.5, 4], }), showLabels: true, - wrapX: false - }) + wrapX: false, + }), ], target: 'map', view: new View({ center: fromLonLat([4.8, 47.75]), - zoom: 5 - }) + zoom: 5, + }), }); diff --git a/examples/heatmap-earthquakes.js b/examples/heatmap-earthquakes.js index 93256ab1a8..c07661b088 100644 --- a/examples/heatmap-earthquakes.js +++ b/examples/heatmap-earthquakes.js @@ -1,9 +1,9 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import KML from '../src/ol/format/KML.js'; -import {Heatmap as HeatmapLayer, Tile as TileLayer} from '../src/ol/layer.js'; +import Map from '../src/ol/Map.js'; import Stamen from '../src/ol/source/Stamen.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; +import {Heatmap as HeatmapLayer, Tile as TileLayer} from '../src/ol/layer.js'; const blur = document.getElementById('blur'); const radius = document.getElementById('radius'); @@ -12,25 +12,25 @@ const vector = new HeatmapLayer({ source: new VectorSource({ url: 'data/kml/2012_Earthquakes_Mag5.kml', format: new KML({ - extractStyles: false - }) + extractStyles: false, + }), }), blur: parseInt(blur.value, 10), radius: parseInt(radius.value, 10), - weight: function(feature) { + weight: function (feature) { // 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a // standards-violatingtag in each Placemark. We extract it from // the Placemark's name instead. const name = feature.get('name'); const magnitude = parseFloat(name.substr(2)); return magnitude - 5; - } + }, }); const raster = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); new Map({ @@ -38,17 +38,17 @@ new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -const blurHandler = function() { +const blurHandler = function () { vector.setBlur(parseInt(blur.value, 10)); }; blur.addEventListener('input', blurHandler); blur.addEventListener('change', blurHandler); -const radiusHandler = function() { +const radiusHandler = function () { vector.setRadius(parseInt(radius.value, 10)); }; radius.addEventListener('input', radiusHandler); diff --git a/examples/here-maps.js b/examples/here-maps.js index 94112d64b1..341ae2bb10 100644 --- a/examples/here-maps.js +++ b/examples/here-maps.js @@ -1,6 +1,6 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; const appId = 'kDm0Jq1K4Ak7Bwtn8uvk'; @@ -11,60 +11,66 @@ const hereLayers = [ type: 'maptile', scheme: 'normal.day', app_id: appId, - app_code: appCode + app_code: appCode, }, { base: 'base', type: 'maptile', scheme: 'normal.day.transit', app_id: appId, - app_code: appCode + app_code: appCode, }, { base: 'base', type: 'maptile', scheme: 'pedestrian.day', app_id: appId, - app_code: appCode + app_code: appCode, }, { base: 'aerial', type: 'maptile', scheme: 'terrain.day', app_id: appId, - app_code: appCode + app_code: appCode, }, { base: 'aerial', type: 'maptile', scheme: 'satellite.day', app_id: appId, - app_code: appCode + app_code: appCode, }, { base: 'aerial', type: 'maptile', scheme: 'hybrid.day', app_id: appId, - app_code: appCode - } + app_code: appCode, + }, ]; -const urlTpl = 'https://{1-4}.{base}.maps.cit.api.here.com' + +const urlTpl = + 'https://{1-4}.{base}.maps.cit.api.here.com' + '/{type}/2.1/maptile/newest/{scheme}/{z}/{x}/{y}/256/png' + '?app_id={app_id}&app_code={app_code}'; const layers = []; let i, ii; for (i = 0, ii = hereLayers.length; i < ii; ++i) { const layerDesc = hereLayers[i]; - layers.push(new TileLayer({ - visible: false, - preload: Infinity, - source: new XYZ({ - url: createUrl(urlTpl, layerDesc), - attributions: 'Map Tiles © ' + new Date().getFullYear() + ' ' + - 'HERE' + layers.push( + new TileLayer({ + visible: false, + preload: Infinity, + source: new XYZ({ + url: createUrl(urlTpl, layerDesc), + attributions: + 'Map Tiles © ' + + new Date().getFullYear() + + ' ' + + 'HERE', + }), }) - })); + ); } const map = new Map({ @@ -72,8 +78,8 @@ const map = new Map({ target: 'map', view: new View({ center: [921371.9389, 6358337.7609], - zoom: 10 - }) + zoom: 10, + }), }); function createUrl(tpl, layerDesc) { diff --git a/examples/hit-tolerance.js b/examples/hit-tolerance.js index a337485f8e..443abb7ee5 100644 --- a/examples/hit-tolerance.js +++ b/examples/hit-tolerance.js @@ -1,29 +1,34 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; import Feature from '../src/ol/Feature.js'; import LineString from '../src/ol/geom/LineString.js'; +import Map from '../src/ol/Map.js'; +import View from '../src/ol/View.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; import {Stroke, Style} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const style = new Style({ stroke: new Stroke({ color: 'black', - width: 1 - }) + width: 1, + }), }); -const feature = new Feature(new LineString([[-4000000, 0], [4000000, 0]])); +const feature = new Feature( + new LineString([ + [-4000000, 0], + [4000000, 0], + ]) +); const vector = new VectorLayer({ source: new VectorSource({ - features: [feature] + features: [feature], }), - style: style + style: style, }); const map = new Map({ @@ -31,21 +36,25 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); let hitTolerance; const statusElement = document.getElementById('status'); -map.on('singleclick', function(e) { +map.on('singleclick', function (e) { let hit = false; - map.forEachFeatureAtPixel(e.pixel, function() { - hit = true; - }, { - hitTolerance: hitTolerance - }); + map.forEachFeatureAtPixel( + e.pixel, + function () { + hit = true; + }, + { + hitTolerance: hitTolerance, + } + ); if (hit) { style.getStroke().setColor('green'); statusElement.innerHTML = ' A feature got hit!'; @@ -59,7 +68,7 @@ map.on('singleclick', function(e) { const selectHitToleranceElement = document.getElementById('hitTolerance'); const circleCanvas = document.getElementById('circle'); -const changeHitTolerance = function() { +const changeHitTolerance = function () { hitTolerance = parseInt(selectHitToleranceElement.value, 10); const size = 2 * hitTolerance + 2; @@ -68,7 +77,13 @@ const changeHitTolerance = function() { const ctx = circleCanvas.getContext('2d'); ctx.clearRect(0, 0, size, size); ctx.beginPath(); - ctx.arc(hitTolerance + 1, hitTolerance + 1, hitTolerance + 0.5, 0, 2 * Math.PI); + ctx.arc( + hitTolerance + 1, + hitTolerance + 1, + hitTolerance + 0.5, + 0, + 2 * Math.PI + ); ctx.fill(); ctx.stroke(); }; diff --git a/examples/hitdetect-vector.js b/examples/hitdetect-vector.js index d09cc96c4e..df9620f014 100644 --- a/examples/hitdetect-vector.js +++ b/examples/hitdetect-vector.js @@ -1,40 +1,39 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Fill, Stroke, Style, Text} from '../src/ol/style.js'; - const style = new Style({ fill: new Fill({ - color: 'rgba(255, 255, 255, 0.6)' + color: 'rgba(255, 255, 255, 0.6)', }), stroke: new Stroke({ color: '#319FD3', - width: 1 + width: 1, }), text: new Text({ font: '12px Calibri,sans-serif', fill: new Fill({ - color: '#000' + color: '#000', }), stroke: new Stroke({ color: '#fff', - width: 3 - }) - }) + width: 3, + }), + }), }); const vectorLayer = new VectorLayer({ source: new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }), - style: function(feature) { + style: function (feature) { style.getText().setText(feature.get('name')); return style; - } + }, }); const map = new Map({ @@ -42,43 +41,42 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 1 - }) + zoom: 1, + }), }); const highlightStyle = new Style({ stroke: new Stroke({ color: '#f00', - width: 1 + width: 1, }), fill: new Fill({ - color: 'rgba(255,0,0,0.1)' + color: 'rgba(255,0,0,0.1)', }), text: new Text({ font: '12px Calibri,sans-serif', fill: new Fill({ - color: '#000' + color: '#000', }), stroke: new Stroke({ color: '#f00', - width: 3 - }) - }) + width: 3, + }), + }), }); const featureOverlay = new VectorLayer({ source: new VectorSource(), map: map, - style: function(feature) { + style: function (feature) { highlightStyle.getText().setText(feature.get('name')); return highlightStyle; - } + }, }); let highlight; -const displayFeatureInfo = function(pixel) { - - vectorLayer.getFeatures(pixel).then(function(features) { +const displayFeatureInfo = function (pixel) { + vectorLayer.getFeatures(pixel).then(function (features) { const feature = features.length ? features[0] : undefined; const info = document.getElementById('info'); if (features.length) { @@ -97,10 +95,9 @@ const displayFeatureInfo = function(pixel) { highlight = feature; } }); - }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } @@ -108,6 +105,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(pixel); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/icon-color.js b/examples/icon-color.js index e88e3d52b8..098319a119 100644 --- a/examples/icon-color.js +++ b/examples/icon-color.js @@ -1,71 +1,76 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {fromLonLat} from '../src/ol/proj.js'; import TileJSON from '../src/ol/source/TileJSON.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Icon, Style} from '../src/ol/style.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {fromLonLat} from '../src/ol/proj.js'; const rome = new Feature({ - geometry: new Point(fromLonLat([12.5, 41.9])) + geometry: new Point(fromLonLat([12.5, 41.9])), }); const london = new Feature({ - geometry: new Point(fromLonLat([-0.12755, 51.507222])) + geometry: new Point(fromLonLat([-0.12755, 51.507222])), }); const madrid = new Feature({ - geometry: new Point(fromLonLat([-3.683333, 40.4])) + geometry: new Point(fromLonLat([-3.683333, 40.4])), }); -rome.setStyle(new Style({ - image: new Icon({ - color: '#8959A8', - crossOrigin: 'anonymous', - src: 'data/square.svg' +rome.setStyle( + new Style({ + image: new Icon({ + color: '#8959A8', + crossOrigin: 'anonymous', + imgSize: [20, 20], + src: 'data/square.svg', + }), }) -})); +); -london.setStyle(new Style({ - image: new Icon({ - color: '#4271AE', - crossOrigin: 'anonymous', - src: 'data/dot.png' +london.setStyle( + new Style({ + image: new Icon({ + color: '#4271AE', + crossOrigin: 'anonymous', + src: 'data/dot.png', + }), }) -})); +); -madrid.setStyle(new Style({ - image: new Icon({ - color: [113, 140, 0], - crossOrigin: 'anonymous', - src: 'data/dot.png' +madrid.setStyle( + new Style({ + image: new Icon({ + color: [113, 140, 0], + crossOrigin: 'anonymous', + src: 'data/dot.png', + }), }) -})); - +); const vectorSource = new VectorSource({ - features: [rome, london, madrid] + features: [rome, london, madrid], }); const vectorLayer = new VectorLayer({ - source: vectorSource + source: vectorSource, }); const rasterLayer = new TileLayer({ source: new TileJSON({ url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json', - crossOrigin: '' - }) + crossOrigin: '', + }), }); const map = new Map({ layers: [rasterLayer, vectorLayer], target: document.getElementById('map'), view: new View({ - center: fromLonLat([2.896372, 44.60240]), - zoom: 3 - }) + center: fromLonLat([2.896372, 44.6024]), + zoom: 3, + }), }); diff --git a/examples/icon-negative.js b/examples/icon-negative.js index dfa83db624..3380580d18 100644 --- a/examples/icon-negative.js +++ b/examples/icon-negative.js @@ -1,13 +1,12 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; import Select from '../src/ol/interaction/Select.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import Stamen from '../src/ol/source/Stamen.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Icon, Style} from '../src/ol/style.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; function createStyle(src, img) { return new Style({ @@ -16,8 +15,8 @@ function createStyle(src, img) { crossOrigin: 'anonymous', src: src, img: img, - imgSize: img ? [img.width, img.height] : undefined - }) + imgSize: img ? [img.width, img.height] : undefined, + }), }); } @@ -27,25 +26,25 @@ iconFeature.set('style', createStyle('data/icon.png', undefined)); const map = new Map({ layers: [ new TileLayer({ - source: new Stamen({layer: 'watercolor'}) + source: new Stamen({layer: 'watercolor'}), }), new VectorLayer({ - style: function(feature) { + style: function (feature) { return feature.get('style'); }, - source: new VectorSource({features: [iconFeature]}) - }) + source: new VectorSource({features: [iconFeature]}), + }), ], target: document.getElementById('map'), view: new View({ center: [0, 0], - zoom: 3 - }) + zoom: 3, + }), }); const selectStyle = {}; const select = new Select({ - style: function(feature) { + style: function (feature) { const image = feature.get('style').getImage().getImage(); if (!selectStyle[image.src]) { const canvas = document.createElement('canvas'); @@ -62,11 +61,12 @@ const select = new Select({ selectStyle[image.src] = createStyle(undefined, canvas); } return selectStyle[image.src]; - } + }, }); map.addInteraction(select); -map.on('pointermove', function(evt) { - map.getTargetElement().style.cursor = - map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : ''; +map.on('pointermove', function (evt) { + map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel) + ? 'pointer' + : ''; }); diff --git a/examples/icon-scale.html b/examples/icon-scale.html new file mode 100644 index 0000000000..50f8f73646 --- /dev/null +++ b/examples/icon-scale.html @@ -0,0 +1,16 @@ +--- +layout: example.html +title: Icon Scale +shortdesc: Example of scaling icons and labels. +docs: > + Icons and labels can be scaled in both dimensions if required. A negative value will flip the image + or text around its anchor point (reversed text is not suitable for line placement). A newline + character inserted in label text is interpreted in a vector layer, but will not be shown in + a vector context. +tags: "vector, style, icon, label, scale" +resources: + - https://code.jquery.com/jquery-2.2.3.min.js + - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css + - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js +--- + diff --git a/examples/icon-scale.js b/examples/icon-scale.js new file mode 100644 index 0000000000..741f87c225 --- /dev/null +++ b/examples/icon-scale.js @@ -0,0 +1,133 @@ +import Feature from '../src/ol/Feature.js'; +import Map from '../src/ol/Map.js'; +import Overlay from '../src/ol/Overlay.js'; +import Point from '../src/ol/geom/Point.js'; +import TileJSON from '../src/ol/source/TileJSON.js'; +import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; +import {Icon, Style, Text} from '../src/ol/style.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {fromLonLat} from '../src/ol/proj.js'; +import {getVectorContext} from '../src/ol/render.js'; + +const rasterLayer = new TileLayer({ + source: new TileJSON({ + url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json', + crossOrigin: '', + }), +}); + +const iconFeature = new Feature({ + geometry: new Point(fromLonLat([0, -10])), + name: 'Fish.1', +}); + +const feature1 = new Feature({ + geometry: new Point(fromLonLat([0, -10])), + name: 'Fish.1 Island', +}); + +const feature2 = new Feature({ + geometry: new Point(fromLonLat([-30, 10])), + name: 'Fish.2 Island', +}); + +const iconStyle = new Style({ + image: new Icon({ + anchor: [0.5, 0.9], + src: 'data/fish.png', + crossOrigin: '', + scale: [0, 0], + rotation: Math.PI / 4, + }), + text: new Text({ + text: 'FISH\nTEXT', + scale: [0, 0], + rotation: Math.PI / 4, + textAlign: 'center', + textBaseline: 'top', + }), +}); + +let i = 0; +let j = 45; + +iconFeature.setStyle(function () { + const x = Math.sin((i * Math.PI) / 180) * 3; + const y = Math.sin((j * Math.PI) / 180) * 4; + iconStyle.getImage().setScale([x, y]); + iconStyle.getText().setScale([x, y]); + return iconStyle; +}); + +rasterLayer.on('postrender', function (event) { + const vectorContext = getVectorContext(event); + const x = Math.cos((i * Math.PI) / 180) * 3; + const y = Math.cos((j * Math.PI) / 180) * 4; + iconStyle.getImage().setScale([x, y]); + iconStyle.getText().setScale([x, y]); + vectorContext.drawFeature(feature2, iconStyle); +}); + +const vectorSource = new VectorSource({ + features: [iconFeature, feature1, feature2], +}); + +const vectorLayer = new VectorLayer({ + source: vectorSource, +}); + +const map = new Map({ + layers: [rasterLayer, vectorLayer], + target: document.getElementById('map'), + view: new View({ + center: fromLonLat([-15, 0]), + zoom: 3, + }), +}); + +setInterval(function () { + i = (i + 4) % 360; + j = (j + 5) % 360; + vectorSource.changed(); +}, 1000); + +const element = document.getElementById('popup'); + +const popup = new Overlay({ + element: element, + positioning: 'bottom-center', + stopEvent: false, + offset: [0, -50], +}); +map.addOverlay(popup); + +// display popup on click +map.on('click', function (evt) { + const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { + return feature; + }); + $(element).popover('destroy'); + if (feature) { + const coordinates = feature.getGeometry().getCoordinates(); + popup.setPosition(coordinates); + $(element).popover({ + placement: 'top', + html: true, + animation: false, + content: feature.get('name'), + }); + $(element).popover('show'); + } +}); + +// change mouse cursor when over marker +map.on('pointermove', function (e) { + if (e.dragging) { + $(element).popover('destroy'); + return; + } + const pixel = map.getEventPixel(e.originalEvent); + const hit = map.hasFeatureAtPixel(pixel); + map.getTarget().style.cursor = hit ? 'pointer' : ''; +}); diff --git a/examples/icon-sprite-webgl.html b/examples/icon-sprite-webgl.html index 2a6bce2201..66e83e231e 100644 --- a/examples/icon-sprite-webgl.html +++ b/examples/icon-sprite-webgl.html @@ -15,8 +15,8 @@ docs: > tags: "webgl, icon, sprite, point, ufo" experimental: true cloak: - - key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg - value: Your Mapbox access token from https://mapbox.com/ here + - key: get_your_own_D6rA4zTHduk6KOKTXzGB + value: Get your own API key at https://www.maptiler.com/cloud/ ---Current sighting:diff --git a/examples/icon-sprite-webgl.js b/examples/icon-sprite-webgl.js index ce2adb7649..6008e19a2a 100644 --- a/examples/icon-sprite-webgl.js +++ b/examples/icon-sprite-webgl.js @@ -1,34 +1,39 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import TileJSON from '../src/ol/source/TileJSON.js'; import Feature from '../src/ol/Feature.js'; +import Map from '../src/ol/Map.js'; import Point from '../src/ol/geom/Point.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js'; +import XYZ from '../src/ol/source/XYZ.js'; import {Vector} from '../src/ol/source.js'; import {fromLonLat} from '../src/ol/proj.js'; -import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js'; -const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg'; +const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; +const attributions = + '© MapTiler ' + + '© OpenStreetMap contributors'; const map = new Map({ layers: [ new TileLayer({ - source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?secure&access_token=' + key, - crossOrigin: 'anonymous' - }) - }) + source: new XYZ({ + attributions: attributions, + url: + 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, + tileSize: 512, + }), + }), ], target: document.getElementById('map'), view: new View({ center: [0, 4000000], - zoom: 2 - }) + zoom: 2, + }), }); const vectorSource = new Vector({ features: [], - attributions: 'National UFO Reporting Center' + attributions: 'National UFO Reporting Center', }); const oldColor = [255, 160, 110]; @@ -37,13 +42,13 @@ const size = 16; const style = { variables: { - filterShape: 'all' + filterShape: 'all', }, filter: [ 'case', ['!=', ['var', 'filterShape'], 'all'], ['==', ['get', 'shape'], ['var', 'filterShape']], - true + true, ], symbol: { symbolType: 'image', @@ -53,44 +58,51 @@ const style = { 'interpolate', ['linear'], ['get', 'year'], - 1950, oldColor, - 2013, newColor + 1950, + oldColor, + 2013, + newColor, ], rotateWithView: false, - offset: [ - 0, - 0 - ], + offset: [0, 0], textureCoord: [ 'match', ['get', 'shape'], - 'light', [0, 0, 0.25, 0.5], - 'sphere', [0.25, 0, 0.5, 0.5], - 'circle', [0.25, 0, 0.5, 0.5], - 'disc', [0.5, 0, 0.75, 0.5], - 'oval', [0.5, 0, 0.75, 0.5], - 'triangle', [0.75, 0, 1, 0.5], - 'fireball', [0, 0.5, 0.25, 1], - [0.75, 0.5, 1, 1] - ] - } + 'light', + [0, 0, 0.25, 0.5], + 'sphere', + [0.25, 0, 0.5, 0.5], + 'circle', + [0.25, 0, 0.5, 0.5], + 'disc', + [0.5, 0, 0.75, 0.5], + 'oval', + [0.5, 0, 0.75, 0.5], + 'triangle', + [0.75, 0, 1, 0.5], + 'fireball', + [0, 0.5, 0.25, 1], + [0.75, 0.5, 1, 1], + ], + }, }; // key is shape name, value is sightings count const shapeTypes = { - all: 0 + all: 0, }; const shapeSelect = document.getElementById('shape-filter'); -shapeSelect.addEventListener('input', function() { - style.variables.filterShape = shapeSelect.options[shapeSelect.selectedIndex].value; +shapeSelect.addEventListener('input', function () { + style.variables.filterShape = + shapeSelect.options[shapeSelect.selectedIndex].value; map.render(); }); function fillShapeSelect() { Object.keys(shapeTypes) - .sort(function(a, b) { + .sort(function (a, b) { return shapeTypes[b] - shapeTypes[a]; }) - .forEach(function(shape) { + .forEach(function (shape) { const option = document.createElement('option'); option.text = `${shape} (${shapeTypes[shape]} sightings)`; option.value = shape; @@ -100,7 +112,7 @@ function fillShapeSelect() { const client = new XMLHttpRequest(); client.open('GET', 'data/csv/ufo_sighting_data.csv'); -client.onload = function() { +client.onload = function () { const csv = client.responseText; const features = []; @@ -122,13 +134,15 @@ client.onload = function() { shapeTypes[shape] = (shapeTypes[shape] ? shapeTypes[shape] : 0) + 1; shapeTypes['all']++; - features.push(new Feature({ - datetime: line[0], - year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int - shape: shape, - duration: line[3], - geometry: new Point(coords) - })); + features.push( + new Feature({ + datetime: line[0], + year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int + shape: shape, + duration: line[3], + geometry: new Point(coords), + }) + ); } vectorSource.addFeatures(features); fillShapeSelect(); @@ -138,21 +152,28 @@ client.send(); map.addLayer( new WebGLPointsLayer({ source: vectorSource, - style: style + style: style, }) ); const info = document.getElementById('info'); -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (map.getView().getInteracting() || map.getView().getAnimating()) { return; } const pixel = evt.pixel; info.innerText = ''; - map.forEachFeatureAtPixel(pixel, function(feature) { + map.forEachFeatureAtPixel(pixel, function (feature) { const datetime = feature.get('datetime'); const duration = feature.get('duration'); const shape = feature.get('shape'); - info.innerText = 'On ' + datetime + ', lasted ' + duration + ' seconds and had a "' + shape + '" shape.'; + info.innerText = + 'On ' + + datetime + + ', lasted ' + + duration + + ' seconds and had a "' + + shape + + '" shape.'; }); }); diff --git a/examples/icon.js b/examples/icon.js index cb427a5984..1c9a79a0b3 100644 --- a/examples/icon.js +++ b/examples/icon.js @@ -1,19 +1,18 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; import Overlay from '../src/ol/Overlay.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import TileJSON from '../src/ol/source/TileJSON.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Icon, Style} from '../src/ol/style.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const iconFeature = new Feature({ geometry: new Point([0, 0]), name: 'Null Island', population: 4000, - rainfall: 500 + rainfall: 500, }); const iconStyle = new Style({ @@ -21,25 +20,25 @@ const iconStyle = new Style({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', - src: 'data/icon.png' - }) + src: 'data/icon.png', + }), }); iconFeature.setStyle(iconStyle); const vectorSource = new VectorSource({ - features: [iconFeature] + features: [iconFeature], }); const vectorLayer = new VectorLayer({ - source: vectorSource + source: vectorSource, }); const rasterLayer = new TileLayer({ source: new TileJSON({ url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json', - crossOrigin: '' - }) + crossOrigin: '', + }), }); const map = new Map({ @@ -47,8 +46,8 @@ const map = new Map({ target: document.getElementById('map'), view: new View({ center: [0, 0], - zoom: 3 - }) + zoom: 3, + }), }); const element = document.getElementById('popup'); @@ -57,23 +56,22 @@ const popup = new Overlay({ element: element, positioning: 'bottom-center', stopEvent: false, - offset: [0, -50] + offset: [0, -50], }); map.addOverlay(popup); // display popup on click -map.on('click', function(evt) { - const feature = map.forEachFeatureAtPixel(evt.pixel, - function(feature) { - return feature; - }); +map.on('click', function (evt) { + const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { + return feature; + }); if (feature) { const coordinates = feature.getGeometry().getCoordinates(); popup.setPosition(coordinates); $(element).popover({ placement: 'top', html: true, - content: feature.get('name') + content: feature.get('name'), }); $(element).popover('show'); } else { @@ -82,7 +80,7 @@ map.on('click', function(evt) { }); // change mouse cursor when over marker -map.on('pointermove', function(e) { +map.on('pointermove', function (e) { if (e.dragging) { $(element).popover('destroy'); return; diff --git a/examples/igc.js b/examples/igc.js index 261108f59a..9fb6719696 100644 --- a/examples/igc.js +++ b/examples/igc.js @@ -1,33 +1,32 @@ import Feature from '../src/ol/Feature.js'; -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import IGC from '../src/ol/format/IGC.js'; -import {LineString, Point} from '../src/ol/geom.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import Map from '../src/ol/Map.js'; import OSM, {ATTRIBUTION} from '../src/ol/source/OSM.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import {LineString, Point} from '../src/ol/geom.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; import {getVectorContext} from '../src/ol/render.js'; - const colors = { 'Clement Latour': 'rgba(0, 0, 255, 0.7)', 'Damien de Baesnt': 'rgba(0, 215, 255, 0.7)', 'Sylvain Dhonneur': 'rgba(0, 165, 255, 0.7)', 'Tom Payne': 'rgba(0, 255, 255, 0.7)', - 'Ulrich Prinz': 'rgba(0, 215, 255, 0.7)' + 'Ulrich Prinz': 'rgba(0, 215, 255, 0.7)', }; const styleCache = {}; -const styleFunction = function(feature) { +const styleFunction = function (feature) { const color = colors[feature.get('PLT')]; let style = styleCache[color]; if (!style) { style = new Style({ stroke: new Stroke({ color: color, - width: 3 - }) + width: 3, + }), }); styleCache[color] = style; } @@ -41,13 +40,13 @@ const igcUrls = [ 'data/igc/Damien-de-Baenst.igc', 'data/igc/Sylvain-Dhonneur.igc', 'data/igc/Tom-Payne.igc', - 'data/igc/Ulrich-Prinz.igc' + 'data/igc/Ulrich-Prinz.igc', ]; function get(url, callback) { const client = new XMLHttpRequest(); client.open('GET', url); - client.onload = function() { + client.onload = function () { callback(client.responseText); }; client.send(); @@ -55,9 +54,10 @@ function get(url, callback) { const igcFormat = new IGC(); for (let i = 0; i < igcUrls.length; ++i) { - get(igcUrls[i], function(data) { - const features = igcFormat.readFeatures(data, - {featureProjection: 'EPSG:3857'}); + get(igcUrls[i], function (data) { + const features = igcFormat.readFeatures(data, { + featureProjection: 'EPSG:3857', + }); vectorSource.addFeatures(features); }); } @@ -65,9 +65,9 @@ for (let i = 0; i < igcUrls.length; ++i) { const time = { start: Infinity, stop: -Infinity, - duration: 0 + duration: 0, }; -vectorSource.on('addfeature', function(event) { +vectorSource.on('addfeature', function (event) { const geometry = event.feature.getGeometry(); time.start = Math.min(time.start, geometry.getFirstCoordinate()[2]); time.stop = Math.max(time.stop, geometry.getLastCoordinate()[2]); @@ -76,7 +76,7 @@ vectorSource.on('addfeature', function(event) { const vectorLayer = new VectorLayer({ source: vectorSource, - style: styleFunction + style: styleFunction, }); const map = new Map({ @@ -85,25 +85,25 @@ const map = new Map({ source: new OSM({ attributions: [ 'All maps © OpenCycleMap', - ATTRIBUTION + ATTRIBUTION, ], - url: 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + - '?apikey=0e6fc415256d4fbb9b5166a718591d71' - }) + url: + 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + + '?apikey=0e6fc415256d4fbb9b5166a718591d71', + }), }), - vectorLayer + vectorLayer, ], target: 'map', view: new View({ center: [703365.7089403362, 5714629.865071137], - zoom: 9 - }) + zoom: 9, + }), }); - let point = null; let line = null; -const displaySnap = function(coordinate) { +const displaySnap = function (coordinate) { const closestFeature = vectorSource.getClosestFeatureToCoordinate(coordinate); const info = document.getElementById('info'); if (closestFeature === null) { @@ -120,7 +120,7 @@ const displaySnap = function(coordinate) { } const date = new Date(closestPoint[2] * 1000); info.innerHTML = - closestFeature.get('PLT') + ' (' + date.toUTCString() + ')'; + closestFeature.get('PLT') + ' (' + date.toUTCString() + ')'; const coordinates = [coordinate, [closestPoint[0], closestPoint[1]]]; if (line === null) { line = new LineString(coordinates); @@ -131,7 +131,7 @@ const displaySnap = function(coordinate) { map.render(); }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } @@ -139,23 +139,23 @@ map.on('pointermove', function(evt) { displaySnap(coordinate); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displaySnap(evt.coordinate); }); const stroke = new Stroke({ color: 'rgba(255,0,0,0.9)', - width: 1 + width: 1, }); const style = new Style({ stroke: stroke, image: new CircleStyle({ radius: 5, fill: null, - stroke: stroke - }) + stroke: stroke, + }), }); -vectorLayer.on('postrender', function(evt) { +vectorLayer.on('postrender', function (evt) { const vectorContext = getVectorContext(evt); vectorContext.setStyle(style); if (point !== null) { @@ -173,16 +173,16 @@ const featureOverlay = new VectorLayer({ image: new CircleStyle({ radius: 5, fill: new Fill({ - color: 'rgba(255,0,0,0.9)' - }) - }) - }) + color: 'rgba(255,0,0,0.9)', + }), + }), + }), }); -document.getElementById('time').addEventListener('input', function() { +document.getElementById('time').addEventListener('input', function () { const value = parseInt(this.value, 10) / 100; - const m = time.start + (time.duration * value); - vectorSource.forEachFeature(function(feature) { + const m = time.start + time.duration * value; + vectorSource.forEachFeature(function (feature) { const geometry = /** @type {import("../src/ol/geom/LineString.js").default} */ (feature.getGeometry()); const coordinate = geometry.getCoordinateAtM(m, true); let highlight = feature.get('highlight'); diff --git a/examples/iiif.js b/examples/iiif.js index b2fc4e4e59..882e67fcbc 100644 --- a/examples/iiif.js +++ b/examples/iiif.js @@ -1,45 +1,53 @@ -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'; +import Map from '../src/ol/Map.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.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'); + 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; + 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.'; }); - }).catch(function() { - notifyDiv.textContent = 'Could not read data from URL.'; - }); } -displayButton.addEventListener('click', function() { +displayButton.addEventListener('click', function () { refreshMap(urlInput.value); }); diff --git a/examples/image-filter.js b/examples/image-filter.js index db6a8105f6..d798f39e49 100644 --- a/examples/image-filter.js +++ b/examples/image-filter.js @@ -1,11 +1,12 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; -import {fromLonLat} from '../src/ol/proj.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; +import {fromLonLat} from '../src/ol/proj.js'; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const imagery = new TileLayer({ @@ -13,8 +14,8 @@ const imagery = new TileLayer({ attributions: attributions, url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, maxZoom: 20, - crossOrigin: '' - }) + crossOrigin: '', + }), }); const map = new Map({ @@ -22,52 +23,25 @@ const map = new Map({ target: 'map', view: new View({ center: fromLonLat([-120, 50]), - zoom: 6 - }) + zoom: 6, + }), }); const kernels = { - none: [ - 0, 0, 0, - 0, 1, 0, - 0, 0, 0 - ], - sharpen: [ - 0, -1, 0, - -1, 5, -1, - 0, -1, 0 - ], - sharpenless: [ - 0, -1, 0, - -1, 10, -1, - 0, -1, 0 - ], - blur: [ - 1, 1, 1, - 1, 1, 1, - 1, 1, 1 - ], - shadow: [ - 1, 2, 1, - 0, 1, 0, - -1, -2, -1 - ], - emboss: [ - -2, 1, 0, - -1, 1, 1, - 0, 1, 2 - ], - edge: [ - 0, 1, 0, - 1, -4, 1, - 0, 1, 0 - ] + none: [0, 0, 0, 0, 1, 0, 0, 0, 0], + sharpen: [0, -1, 0, -1, 5, -1, 0, -1, 0], + sharpenless: [0, -1, 0, -1, 10, -1, 0, -1, 0], + blur: [1, 1, 1, 1, 1, 1, 1, 1, 1], + shadow: [1, 2, 1, 0, 1, 0, -1, -2, -1], + emboss: [-2, 1, 0, -1, 1, 1, 0, 1, 2], + edge: [0, 1, 0, 1, -4, 1, 0, 1, 0], }; function normalize(kernel) { const len = kernel.length; const normal = new Array(len); - let i, sum = 0; + let i, + sum = 0; for (i = 0; i < len; ++i) { sum += kernel[i]; } @@ -86,24 +60,21 @@ function normalize(kernel) { const select = document.getElementById('kernel'); let selectedKernel = normalize(kernels[select.value]); - /** * Update the kernel and re-render on change. */ -select.onchange = function() { +select.onchange = function () { selectedKernel = normalize(kernels[select.value]); map.render(); }; - /** * Apply a filter on "postrender" events. */ -imagery.on('postrender', function(event) { +imagery.on('postrender', function (event) { convolve(event.context, selectedKernel); }); - /** * Apply a convolution kernel to canvas. This works for any size kernel, but * performance starts degrading above 3 x 3. @@ -126,14 +97,21 @@ function convolve(context, kernel) { for (let pixelY = 0; pixelY < height; ++pixelY) { const pixelsAbove = pixelY * width; for (let pixelX = 0; pixelX < width; ++pixelX) { - let r = 0, g = 0, b = 0, a = 0; + let r = 0, + g = 0, + b = 0, + a = 0; for (let kernelY = 0; kernelY < size; ++kernelY) { for (let kernelX = 0; kernelX < size; ++kernelX) { const weight = kernel[kernelY * size + kernelX]; const neighborY = Math.min( - height - 1, Math.max(0, pixelY + kernelY - half)); + height - 1, + Math.max(0, pixelY + kernelY - half) + ); const neighborX = Math.min( - width - 1, Math.max(0, pixelX + kernelX - half)); + width - 1, + Math.max(0, pixelX + kernelX - half) + ); const inputIndex = (neighborY * width + neighborX) * 4; r += inputData[inputIndex] * weight; g += inputData[inputIndex + 1] * weight; diff --git a/examples/image-load-events.js b/examples/image-load-events.js index 5d2518da22..7bc8725591 100644 --- a/examples/image-load-events.js +++ b/examples/image-load-events.js @@ -1,8 +1,7 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import ImageLayer from '../src/ol/layer/Image.js'; import ImageWMS from '../src/ol/source/ImageWMS.js'; - +import Map from '../src/ol/Map.js'; +import View from '../src/ol/View.js'; /** * Renders a progress bar. @@ -15,11 +14,10 @@ function Progress(el) { this.loaded = 0; } - /** * Increment the count of loading tiles. */ -Progress.prototype.addLoading = function() { +Progress.prototype.addLoading = function () { if (this.loading === 0) { this.show(); } @@ -27,48 +25,44 @@ Progress.prototype.addLoading = function() { this.update(); }; - /** * Increment the count of loaded tiles. */ -Progress.prototype.addLoaded = function() { +Progress.prototype.addLoaded = function () { const this_ = this; - setTimeout(function() { + setTimeout(function () { ++this_.loaded; this_.update(); }, 100); }; - /** * Update the progress bar. */ -Progress.prototype.update = function() { - const width = (this.loaded / this.loading * 100).toFixed(1) + '%'; +Progress.prototype.update = function () { + const width = ((this.loaded / this.loading) * 100).toFixed(1) + '%'; this.el.style.width = width; if (this.loading === this.loaded) { this.loading = 0; this.loaded = 0; const this_ = this; - setTimeout(function() { + setTimeout(function () { this_.hide(); }, 500); } }; - /** * Show the progress bar. */ -Progress.prototype.show = function() { +Progress.prototype.show = function () { this.el.style.visibility = 'visible'; }; - /** * Hide the progress bar. */ -Progress.prototype.hide = function() { +Progress.prototype.hide = function () { if (this.loading === this.loaded) { this.el.style.visibility = 'hidden'; this.el.style.width = 0; @@ -80,27 +74,25 @@ const progress = new Progress(document.getElementById('progress')); const source = new ImageWMS({ url: 'https://ahocevar.com/geoserver/wms', params: {'LAYERS': 'topp:states'}, - serverType: 'geoserver' + serverType: 'geoserver', }); -source.on('imageloadstart', function() { +source.on('imageloadstart', function () { progress.addLoading(); }); -source.on('imageloadend', function() { +source.on('imageloadend', function () { progress.addLoaded(); }); -source.on('imageloaderror', function() { +source.on('imageloaderror', function () { progress.addLoaded(); }); const map = new Map({ - layers: [ - new ImageLayer({source: source}) - ], + layers: [new ImageLayer({source: source})], target: 'map', view: new View({ center: [-10997148, 4569099], - zoom: 4 - }) + zoom: 4, + }), }); diff --git a/examples/image-vector-layer.js b/examples/image-vector-layer.js index cd24c917b4..5339c43cbc 100644 --- a/examples/image-vector-layer.js +++ b/examples/image-vector-layer.js @@ -1,21 +1,20 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; import VectorImageLayer from '../src/ol/layer/VectorImage.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Fill, Stroke, Style, Text} from '../src/ol/style.js'; - const style = new Style({ fill: new Fill({ - color: 'rgba(255, 255, 255, 0.6)' + color: 'rgba(255, 255, 255, 0.6)', }), stroke: new Stroke({ color: '#319FD3', - width: 1 + width: 1, }), - text: new Text() + text: new Text(), }); const map = new Map({ @@ -24,19 +23,19 @@ const map = new Map({ imageRatio: 2, source: new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }), - style: function(feature) { + style: function (feature) { style.getText().setText(feature.get('name')); return style; - } - }) + }, + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 1 - }) + zoom: 1, + }), }); const featureOverlay = new VectorLayer({ @@ -45,45 +44,48 @@ const featureOverlay = new VectorLayer({ style: new Style({ stroke: new Stroke({ color: '#f00', - width: 1 + width: 1, }), fill: new Fill({ - color: 'rgba(255,0,0,0.1)' - }) - }) + color: 'rgba(255,0,0,0.1)', + }), + }), }); let highlight; -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { + map + .getLayers() + .item(0) + .getFeatures(pixel) + .then(function (features) { + const feature = features.length > 0 ? features[0] : undefined; - map.getLayers().item(0).getFeatures(pixel).then(function(features) { - const feature = features.length > 0 ? features[0] : undefined; - - const info = document.getElementById('info'); - if (feature) { - info.innerHTML = feature.getId() + ': ' + feature.get('name'); - } else { - info.innerHTML = ' '; - } - - if (feature !== highlight) { - if (highlight) { - featureOverlay.getSource().removeFeature(highlight); - } + const info = document.getElementById('info'); if (feature) { - featureOverlay.getSource().addFeature(feature); + info.innerHTML = feature.getId() + ': ' + feature.get('name'); + } else { + info.innerHTML = ' '; } - highlight = feature; - } - }); + + if (feature !== highlight) { + if (highlight) { + featureOverlay.getSource().removeFeature(highlight); + } + if (feature) { + featureOverlay.getSource().addFeature(feature); + } + highlight = feature; + } + }); }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (!evt.dragging) { displayFeatureInfo(evt.pixel); } }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/immediate-geographic.js b/examples/immediate-geographic.js index 7c92cf0459..cc21f14383 100644 --- a/examples/immediate-geographic.js +++ b/examples/immediate-geographic.js @@ -1,18 +1,18 @@ +import Stamen from '../src/ol/source/Stamen.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import {Circle, Fill, Style} from '../src/ol/style.js'; import {Map, View} from '../src/ol/index.js'; import {Point} from '../src/ol/geom.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import Stamen from '../src/ol/source/Stamen.js'; -import {Circle, Fill, Style} from '../src/ol/style.js'; import {getVectorContext} from '../src/ol/render.js'; -import {useGeographic} from '../src/ol/proj.js'; import {upAndDown} from '../src/ol/easing.js'; +import {useGeographic} from '../src/ol/proj.js'; useGeographic(); const layer = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); const map = new Map({ @@ -20,17 +20,17 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const image = new Circle({ radius: 8, - fill: new Fill({color: 'rgb(255, 153, 0)'}) + fill: new Fill({color: 'rgb(255, 153, 0)'}), }); const style = new Style({ - image: image + image: image, }); const n = 1000; @@ -42,7 +42,7 @@ for (let i = 0; i < n; ++i) { geometries[i] = new Point([lon, lat]); } -layer.on('postrender', function(event) { +layer.on('postrender', function (event) { const vectorContext = getVectorContext(event); for (let i = 0; i < n; ++i) { diff --git a/examples/index.html b/examples/index.html index 4acb81f718..06d1a153dd 100644 --- a/examples/index.html +++ b/examples/index.html @@ -4,38 +4,21 @@ - + + -OpenLayers Examples -- -+-- - -
OpenLayers
-
- +
OpenLayers
+
+
+
+
+
-- + + diff --git a/examples/index.js b/examples/index.js new file mode 100644 index 0000000000..f6d2c2efde --- /dev/null +++ b/examples/index.js @@ -0,0 +1,113 @@ +(function () { + 'use strict'; + /* global info, jugl */ + let template, target; + + function listExamples(examples) { + target.innerHTML = ''; + template.process({ + context: {examples: examples}, + clone: true, + parent: target, + }); + document.getElementById('count').innerHTML = ' ' + examples.length + ' '; + } + + let timerId; + function inputChange() { + if (timerId) { + window.clearTimeout(timerId); + } + const text = this.value; + timerId = window.setTimeout(function () { + filterList(text); + }, 500); + } + + function getMatchingExamples(text) { + text = text.trim(); + if (text.length === 0) { + return info.examples; + } + const words = text.toLowerCase().split(/\W+/); + const scores = {}; + const updateScores = function (dict, word) { + // eslint-disable-next-line prefer-const + for (let exIndex in dict) { + let exScore = scores[exIndex]; + if (!exScore) { + exScore = {}; + scores[exIndex] = exScore; + } + exScore[word] = (exScore[word] || 0) + dict[exIndex]; + } + }; + words.forEach(function (word) { + const dict = info.index[word]; + if (dict) { + updateScores(dict, word); + } else { + const r = new RegExp(word); + // eslint-disable-next-line prefer-const + for (let idx in info.index) { + if (r.test(idx)) { + updateScores(info.index[idx], word); + } + } + } + }); + const examples = []; + // eslint-disable-next-line prefer-const + for (let exIndex in scores) { + const ex = info.examples[exIndex]; + ex.score = 0; + ex.words = 0; + // eslint-disable-next-line prefer-const + for (let word in scores[exIndex]) { + ex.score += scores[exIndex][word]; + ex.words++; + } + examples.push(ex); + } + // sort examples, first by number of words matched, then + // by word frequency + examples.sort(function (a, b) { + return a.score - b.score || a.words - b.words; + }); + return examples; + } + + function filterList(text) { + const examples = getMatchingExamples(text); + listExamples(examples); + } + + function parseParams() { + const params = {}; + const list = window.location.search + .substring(1) + .replace(/\+/g, '%20') + .split('&'); + for (let i = 0; i < list.length; ++i) { + const pair = list[i].split('='); + if (pair.length === 2) { + params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); + } + } + return params; + } + + window.addEventListener('load', function () { + for (let i = 0; i < info.examples.length; ++i) { + info.examples[i].link += window.location.search; + } + template = new jugl.Template('template'); + target = document.getElementById('examples'); + const params = parseParams(); + const text = params['q'] || ''; + const input = document.getElementById('keywords'); + input.addEventListener('input', inputChange); + input.value = text; + filterList(text); + }); +})(); diff --git a/examples/jsts.html b/examples/jsts.html index bb6db6f424..ceec03958d 100644 --- a/examples/jsts.html +++ b/examples/jsts.html @@ -7,6 +7,6 @@ docs: > with OpenLayers. tags: "vector, jsts, buffer" resources: - - https://unpkg.com/jsts@2.0.2/dist/jsts.min.js + - https://unpkg.com/jsts@2.3.0/dist/jsts.min.js --- diff --git a/examples/jsts.js b/examples/jsts.js index 1d64cc2281..ebe4af642a 100644 --- a/examples/jsts.js +++ b/examples/jsts.js @@ -1,43 +1,62 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {fromLonLat} from '../src/ol/proj.js'; +import LinearRing from '../src/ol/geom/LinearRing.js'; +import Map from '../src/ol/Map.js'; import OSM from '../src/ol/source/OSM.js'; import VectorSource from '../src/ol/source/Vector.js'; -import LinearRing from '../src/ol/geom/LinearRing.js'; -import {Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon} from '../src/ol/geom.js'; +import View from '../src/ol/View.js'; +import { + LineString, + MultiLineString, + MultiPoint, + MultiPolygon, + Point, + Polygon, +} from '../src/ol/geom.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {fromLonLat} from '../src/ol/proj.js'; const source = new VectorSource(); -fetch('data/geojson/roads-seoul.geojson').then(function(response) { - return response.json(); -}).then(function(json) { - const format = new GeoJSON(); - const features = format.readFeatures(json, {featureProjection: 'EPSG:3857'}); +fetch('data/geojson/roads-seoul.geojson') + .then(function (response) { + return response.json(); + }) + .then(function (json) { + const format = new GeoJSON(); + const features = format.readFeatures(json, { + featureProjection: 'EPSG:3857', + }); - const parser = new jsts.io.OL3Parser(); - parser.inject(Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon); + const parser = new jsts.io.OL3Parser(); + parser.inject( + Point, + LineString, + LinearRing, + Polygon, + MultiPoint, + MultiLineString, + MultiPolygon + ); - for (let i = 0; i < features.length; i++) { - const feature = features[i]; - // convert the OpenLayers geometry to a JSTS geometry - const jstsGeom = parser.read(feature.getGeometry()); + for (let i = 0; i < features.length; i++) { + const feature = features[i]; + // convert the OpenLayers geometry to a JSTS geometry + const jstsGeom = parser.read(feature.getGeometry()); - // create a buffer of 40 meters around each line - const buffered = jstsGeom.buffer(40); + // create a buffer of 40 meters around each line + const buffered = jstsGeom.buffer(40); - // convert back from JSTS and replace the geometry on the feature - feature.setGeometry(parser.write(buffered)); - } + // convert back from JSTS and replace the geometry on the feature + feature.setGeometry(parser.write(buffered)); + } - source.addFeatures(features); -}); + source.addFeatures(features); + }); const vectorLayer = new VectorLayer({ - source: source + source: source, }); const rasterLayer = new TileLayer({ - source: new OSM() + source: new OSM(), }); const map = new Map({ @@ -45,6 +64,6 @@ const map = new Map({ target: document.getElementById('map'), view: new View({ center: fromLonLat([126.979293, 37.528787]), - zoom: 15 - }) + zoom: 15, + }), }); diff --git a/examples/kml-earthquakes.js b/examples/kml-earthquakes.js index 3ccd3ae988..b2ea2b175d 100644 --- a/examples/kml-earthquakes.js +++ b/examples/kml-earthquakes.js @@ -1,14 +1,13 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import KML from '../src/ol/format/KML.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import Map from '../src/ol/Map.js'; import Stamen from '../src/ol/source/Stamen.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const styleCache = {}; -const styleFunction = function(feature) { +const styleFunction = function (feature) { // 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a // standards-violatingtag in each Placemark. We extract it from // the Placemark's name instead. @@ -21,13 +20,13 @@ const styleFunction = function(feature) { image: new CircleStyle({ radius: radius, fill: new Fill({ - color: 'rgba(255, 153, 0, 0.4)' + color: 'rgba(255, 153, 0, 0.4)', }), stroke: new Stroke({ color: 'rgba(255, 204, 0, 0.2)', - width: 1 - }) - }) + width: 1, + }), + }), }); styleCache[radius] = style; } @@ -38,16 +37,16 @@ const vector = new VectorLayer({ source: new VectorSource({ url: 'data/kml/2012_Earthquakes_Mag5.kml', format: new KML({ - extractStyles: false - }) + extractStyles: false, + }), }), - style: styleFunction + style: styleFunction, }); const raster = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); const map = new Map({ @@ -55,26 +54,27 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const info = $('#info'); info.tooltip({ animation: false, - trigger: 'manual' + trigger: 'manual', }); -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { info.css({ left: pixel[0] + 'px', - top: (pixel[1] - 15) + 'px' + top: pixel[1] - 15 + 'px', }); - const feature = map.forEachFeatureAtPixel(pixel, function(feature) { + const feature = map.forEachFeatureAtPixel(pixel, function (feature) { return feature; }); if (feature) { - info.tooltip('hide') + info + .tooltip('hide') .attr('data-original-title', feature.get('name')) .tooltip('fixTitle') .tooltip('show'); @@ -83,7 +83,7 @@ const displayFeatureInfo = function(pixel) { } }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { info.tooltip('hide'); return; @@ -91,6 +91,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(map.getEventPixel(evt.originalEvent)); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/kml-timezones.js b/examples/kml-timezones.js index 7c60c0a01e..497cf87c47 100644 --- a/examples/kml-timezones.js +++ b/examples/kml-timezones.js @@ -1,11 +1,10 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import KML from '../src/ol/format/KML.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import Map from '../src/ol/Map.js'; import Stamen from '../src/ol/source/Stamen.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Fill, Stroke, Style} from '../src/ol/style.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; /* * Compute the style of the feature. Here we want the opacity of polygons to @@ -14,7 +13,7 @@ import {Fill, Stroke, Style} from '../src/ol/style.js'; * currently midnight would have an opacity of 0. This doesn't account for * daylight savings, so don't use it to plan your vacation. */ -const styleFunction = function(feature) { +const styleFunction = function (feature) { let offset = 0; const name = feature.get('name'); // e.g. GMT -08:30 const match = name.match(/([\-+]\d{2}):(\d{2})$/); @@ -24,21 +23,22 @@ const styleFunction = function(feature) { offset = 60 * hours + minutes; } const date = new Date(); - const local = new Date(date.getTime() + - (date.getTimezoneOffset() + offset) * 60000); + const local = new Date( + date.getTime() + (date.getTimezoneOffset() + offset) * 60000 + ); // offset from local noon (in hours) - let delta = Math.abs(12 - local.getHours() + (local.getMinutes() / 60)); + let delta = Math.abs(12 - local.getHours() + local.getMinutes() / 60); if (delta > 12) { delta = 24 - delta; } const opacity = 0.75 * (1 - delta / 12); return new Style({ fill: new Fill({ - color: [0xff, 0xff, 0x33, opacity] + color: [0xff, 0xff, 0x33, opacity], }), stroke: new Stroke({ - color: '#ffffff' - }) + color: '#ffffff', + }), }); }; @@ -46,16 +46,16 @@ const vector = new VectorLayer({ source: new VectorSource({ url: 'data/kml/timezones.kml', format: new KML({ - extractStyles: false - }) + extractStyles: false, + }), }), - style: styleFunction + style: styleFunction, }); const raster = new TileLayer({ source: new Stamen({ - layer: 'toner' - }) + layer: 'toner', + }), }); const map = new Map({ @@ -63,26 +63,27 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const info = $('#info'); info.tooltip({ animation: false, - trigger: 'manual' + trigger: 'manual', }); -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { info.css({ left: pixel[0] + 'px', - top: (pixel[1] - 15) + 'px' + top: pixel[1] - 15 + 'px', }); - const feature = map.forEachFeatureAtPixel(pixel, function(feature) { + const feature = map.forEachFeatureAtPixel(pixel, function (feature) { return feature; }); if (feature) { - info.tooltip('hide') + info + .tooltip('hide') .attr('data-original-title', feature.get('name')) .tooltip('fixTitle') .tooltip('show'); @@ -91,7 +92,7 @@ const displayFeatureInfo = function(pixel) { } }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { info.tooltip('hide'); return; @@ -99,6 +100,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(map.getEventPixel(evt.originalEvent)); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/kml.js b/examples/kml.js index 611cd5beaa..3d16eda6a8 100644 --- a/examples/kml.js +++ b/examples/kml.js @@ -1,27 +1,28 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import KML from '../src/ol/format/KML.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import XYZ from '../src/ol/source/XYZ.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 {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +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 - }) + maxZoom: 20, + }), }); const vector = new VectorLayer({ source: new VectorSource({ url: 'data/kml/2012-02-10.kml', - format: new KML() - }) + format: new KML(), + }), }); const map = new Map({ @@ -30,13 +31,13 @@ const map = new Map({ view: new View({ center: [876970.8463461736, 5859807.853963373], projection: 'EPSG:3857', - zoom: 10 - }) + zoom: 10, + }), }); -const displayFeatureInfo = function(pixel) { +const displayFeatureInfo = function (pixel) { const features = []; - map.forEachFeatureAtPixel(pixel, function(feature) { + map.forEachFeatureAtPixel(pixel, function (feature) { features.push(feature); }); if (features.length > 0) { @@ -53,7 +54,7 @@ const displayFeatureInfo = function(pixel) { } }; -map.on('pointermove', function(evt) { +map.on('pointermove', function (evt) { if (evt.dragging) { return; } @@ -61,6 +62,6 @@ map.on('pointermove', function(evt) { displayFeatureInfo(pixel); }); -map.on('click', function(evt) { +map.on('click', function (evt) { displayFeatureInfo(evt.pixel); }); diff --git a/examples/layer-clipping-vector.css b/examples/layer-clipping-vector.css new file mode 100644 index 0000000000..3d35756e41 --- /dev/null +++ b/examples/layer-clipping-vector.css @@ -0,0 +1,3 @@ +#map { + background: transparent; +} diff --git a/examples/layer-clipping-vector.html b/examples/layer-clipping-vector.html new file mode 100644 index 0000000000..2343aa0105 --- /dev/null +++ b/examples/layer-clipping-vector.html @@ -0,0 +1,9 @@ +--- +layout: example.html +title: Vector Clipping Layer +shortdesc: Vector Clipping Layer example +docs: > + Example of a clipping layer based on a vector source +tags: "clipping, openstreetmap, vector" +--- + diff --git a/examples/layer-clipping-vector.js b/examples/layer-clipping-vector.js new file mode 100644 index 0000000000..5568d0e411 --- /dev/null +++ b/examples/layer-clipping-vector.js @@ -0,0 +1,57 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; +import View from '../src/ol/View.js'; +import {Fill, Style} from '../src/ol/style.js'; +import {OSM, Stamen, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {fromLonLat} from '../src/ol/proj.js'; +import {getVectorContext} from '../src/ol/render.js'; + +//A distinct className is required to use another canvas for the background +const background = new TileLayer({ + className: 'stamen', + source: new Stamen({ + layer: 'toner', + }), +}); + +const base = new TileLayer({ + source: new OSM(), +}); + +const clipLayer = new VectorLayer({ + style: null, + source: new VectorSource({ + url: './data/geojson/switzerland.geojson', + format: new GeoJSON(), + }), +}); + +//Giving the clipped layer an extent is necessary to avoid rendering when the feature is outside the viewport +clipLayer.getSource().on('addfeature', function () { + base.setExtent(clipLayer.getSource().getExtent()); +}); + +const style = new Style({ + fill: new Fill({ + color: 'black', + }), +}); + +base.on('postrender', function (e) { + const vectorContext = getVectorContext(e); + e.context.globalCompositeOperation = 'destination-in'; + clipLayer.getSource().forEachFeature(function (feature) { + vectorContext.drawFeature(feature, style); + }); + e.context.globalCompositeOperation = 'source-over'; +}); + +const map = new Map({ + layers: [background, base, clipLayer], + target: 'map', + view: new View({ + center: fromLonLat([8.23, 46.86]), + zoom: 7, + }), +}); diff --git a/examples/layer-clipping.js b/examples/layer-clipping.js index a6805fdac5..6bb1b6a25a 100644 --- a/examples/layer-clipping.js +++ b/examples/layer-clipping.js @@ -1,10 +1,10 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const osm = new TileLayer({ - source: new OSM() + source: new OSM(), }); const map = new Map({ @@ -12,16 +12,18 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -osm.on('prerender', function(event) { +osm.on('prerender', function (event) { const ctx = event.context; // calculate the pixel ratio and rotation of the canvas const matrix = event.inversePixelTransform; - const canvasPixelRatio = Math.sqrt(matrix[0] * matrix[0] + matrix[1] * matrix[1]); + const canvasPixelRatio = Math.sqrt( + matrix[0] * matrix[0] + matrix[1] * matrix[1] + ); const canvasRotation = -Math.atan2(matrix[1], matrix[0]); ctx.save(); // center the canvas and remove rotation to position clipping @@ -47,7 +49,7 @@ osm.on('prerender', function(event) { ctx.translate(-ctx.canvas.width / 2, -ctx.canvas.height / 2); }); -osm.on('postrender', function(event) { +osm.on('postrender', function (event) { const ctx = event.context; ctx.restore(); }); diff --git a/examples/layer-extent.js b/examples/layer-extent.js index 6aa6a45075..ae8c5ca411 100644 --- a/examples/layer-extent.js +++ b/examples/layer-extent.js @@ -1,8 +1,8 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import {transformExtent} from '../src/ol/proj.js'; import TileJSON from '../src/ol/source/TileJSON.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {transformExtent} from '../src/ol/proj.js'; function transform(extent) { return transformExtent(extent, 'EPSG:4326', 'EPSG:3857'); @@ -12,24 +12,29 @@ const extents = { India: transform([68.17665, 7.96553, 97.40256, 35.49401]), Argentina: transform([-73.41544, -55.25, -53.62835, -21.83231]), Nigeria: transform([2.6917, 4.24059, 14.57718, 13.86592]), - Sweden: transform([11.02737, 55.36174, 23.90338, 69.10625]) + Sweden: transform([11.02737, 55.36174, 23.90338, 69.10625]), }; -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; const base = new TileLayer({ source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.world-light.json?secure&access_token=' + key, - crossOrigin: 'anonymous' - }) + url: + 'https://api.tiles.mapbox.com/v4/mapbox.world-light.json?secure&access_token=' + + key, + crossOrigin: 'anonymous', + }), }); const overlay = new TileLayer({ extent: extents.India, source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.world-black.json?secure&access_token=' + key, - crossOrigin: 'anonymous' - }) + url: + 'https://api.tiles.mapbox.com/v4/mapbox.world-black.json?secure&access_token=' + + key, + crossOrigin: 'anonymous', + }), }); const map = new Map({ @@ -37,12 +42,12 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 1 - }) + zoom: 1, + }), }); for (const key in extents) { - document.getElementById(key).onclick = function(event) { + document.getElementById(key).onclick = function (event) { overlay.setExtent(extents[event.target.id]); }; } diff --git a/examples/layer-group.js b/examples/layer-group.js index 112dc7d951..c6fd6b524b 100644 --- a/examples/layer-group.js +++ b/examples/layer-group.js @@ -1,62 +1,71 @@ import Map from '../src/ol/Map.js'; +import OSM from '../src/ol/source/OSM.js'; +import TileJSON from '../src/ol/source/TileJSON.js'; import View from '../src/ol/View.js'; import {Group as LayerGroup, Tile as TileLayer} from '../src/ol/layer.js'; import {fromLonLat} from '../src/ol/proj.js'; -import OSM from '../src/ol/source/OSM.js'; -import TileJSON from '../src/ol/source/TileJSON.js'; -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }), new LayerGroup({ + source: new OSM(), + }), + new LayerGroup({ layers: [ new TileLayer({ source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.20110804-hoa-foodinsecurity-3month.json?secure&access_token=' + key, - crossOrigin: 'anonymous' - }) + url: + 'https://api.tiles.mapbox.com/v4/mapbox.20110804-hoa-foodinsecurity-3month.json?secure&access_token=' + + key, + crossOrigin: 'anonymous', + }), }), new TileLayer({ source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.world-borders-light.json?secure&access_token=' + key, - crossOrigin: 'anonymous' - }) - }) - ] - }) + url: + 'https://api.tiles.mapbox.com/v4/mapbox.world-borders-light.json?secure&access_token=' + + key, + crossOrigin: 'anonymous', + }), + }), + ], + }), ], target: 'map', view: new View({ - center: fromLonLat([37.40570, 8.81566]), - zoom: 4 - }) + center: fromLonLat([37.4057, 8.81566]), + zoom: 4, + }), }); function bindInputs(layerid, layer) { const visibilityInput = $(layerid + ' input.visible'); - visibilityInput.on('change', function() { + visibilityInput.on('change', function () { layer.setVisible(this.checked); }); visibilityInput.prop('checked', layer.getVisible()); const opacityInput = $(layerid + ' input.opacity'); - opacityInput.on('input change', function() { + opacityInput.on('input change', function () { layer.setOpacity(parseFloat(this.value)); }); opacityInput.val(String(layer.getOpacity())); } -map.getLayers().forEach(function(layer, i) { +map.getLayers().forEach(function (layer, i) { bindInputs('#layer' + i, layer); if (layer instanceof LayerGroup) { - layer.getLayers().forEach(function(sublayer, j) { + layer.getLayers().forEach(function (sublayer, j) { bindInputs('#layer' + i + j, sublayer); }); } }); -$('#layertree li > span').click(function() { - $(this).siblings('fieldset').toggle(); -}).siblings('fieldset').hide(); +$('#layertree li > span') + .click(function () { + $(this).siblings('fieldset').toggle(); + }) + .siblings('fieldset') + .hide(); diff --git a/examples/layer-spy.js b/examples/layer-spy.js index 4418e7a5ca..bdb7d8f1cd 100644 --- a/examples/layer-spy.js +++ b/examples/layer-spy.js @@ -1,12 +1,13 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; -import {fromLonLat} from '../src/ol/proj.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; +import {fromLonLat} from '../src/ol/proj.js'; import {getRenderPixel} from '../src/ol/render.js'; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const roads = new TileLayer({ @@ -14,16 +15,16 @@ const roads = new TileLayer({ attributions: attributions, url: 'https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=' + key, tileSize: 512, - maxZoom: 22 - }) + maxZoom: 22, + }), }); const imagery = new TileLayer({ source: new XYZ({ attributions: attributions, url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, - maxZoom: 20 - }) + maxZoom: 20, + }), }); const container = document.getElementById('map'); @@ -33,12 +34,12 @@ const map = new Map({ target: container, view: new View({ center: fromLonLat([-109, 46.5]), - zoom: 6 - }) + zoom: 6, + }), }); let radius = 75; -document.addEventListener('keydown', function(evt) { +document.addEventListener('keydown', function (evt) { if (evt.which === 38) { radius = Math.min(radius + 5, 150); map.render(); @@ -53,28 +54,33 @@ document.addEventListener('keydown', function(evt) { // get the pixel position with every move let mousePosition = null; -container.addEventListener('mousemove', function(event) { +container.addEventListener('mousemove', function (event) { mousePosition = map.getEventPixel(event); map.render(); }); -container.addEventListener('mouseout', function() { +container.addEventListener('mouseout', function () { mousePosition = null; map.render(); }); // before rendering the layer, do some clipping -imagery.on('prerender', function(event) { +imagery.on('prerender', function (event) { const ctx = event.context; ctx.save(); ctx.beginPath(); if (mousePosition) { // only show a circle around the mouse const pixel = getRenderPixel(event, mousePosition); - const offset = getRenderPixel(event, [mousePosition[0] + radius, mousePosition[1]]); - const canvasRadius = Math.sqrt(Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2)); + const offset = getRenderPixel(event, [ + mousePosition[0] + radius, + mousePosition[1], + ]); + const canvasRadius = Math.sqrt( + Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2) + ); ctx.arc(pixel[0], pixel[1], canvasRadius, 0, 2 * Math.PI); - ctx.lineWidth = 5 * canvasRadius / radius; + ctx.lineWidth = (5 * canvasRadius) / radius; ctx.strokeStyle = 'rgba(0,0,0,0.5)'; ctx.stroke(); } @@ -82,7 +88,7 @@ imagery.on('prerender', function(event) { }); // after rendering the layer, restore the canvas context -imagery.on('postrender', function(event) { +imagery.on('postrender', function (event) { const ctx = event.context; ctx.restore(); }); diff --git a/examples/layer-swipe.js b/examples/layer-swipe.js index 5d6a20b274..cf457a4b94 100644 --- a/examples/layer-swipe.js +++ b/examples/layer-swipe.js @@ -1,24 +1,25 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; import {getRenderPixel} from '../src/ol/render.js'; const osm = new TileLayer({ - source: new OSM() + source: new OSM(), }); const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const aerial = new TileLayer({ source: new XYZ({ attributions: attributions, url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, - maxZoom: 20 - }) + maxZoom: 20, + }), }); const map = new Map({ @@ -26,13 +27,13 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const swipe = document.getElementById('swipe'); -aerial.on('prerender', function(event) { +aerial.on('prerender', function (event) { const ctx = event.context; const mapSize = map.getSize(); const width = mapSize[0] * (swipe.value / 100); @@ -51,11 +52,15 @@ aerial.on('prerender', function(event) { ctx.clip(); }); -aerial.on('postrender', function(event) { +aerial.on('postrender', function (event) { const ctx = event.context; ctx.restore(); }); -swipe.addEventListener('input', function() { - map.render(); -}, false); +swipe.addEventListener( + 'input', + function () { + map.render(); + }, + false +); diff --git a/examples/layer-z-index.js b/examples/layer-z-index.js index 12cbfc3b7c..8e967a30e5 100644 --- a/examples/layer-z-index.js +++ b/examples/layer-z-index.js @@ -1,12 +1,11 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Fill, RegularShape, Stroke, Style} from '../src/ol/style.js'; - const stroke = new Stroke({color: 'black', width: 1}); const styles = { @@ -16,8 +15,8 @@ const styles = { stroke: stroke, points: 4, radius: 80, - angle: Math.PI / 4 - }) + angle: Math.PI / 4, + }), }), 'triangle': new Style({ image: new RegularShape({ @@ -26,8 +25,8 @@ const styles = { points: 3, radius: 80, rotation: Math.PI / 4, - angle: 0 - }) + angle: 0, + }), }), 'star': new Style({ image: new RegularShape({ @@ -36,22 +35,21 @@ const styles = { points: 5, radius: 80, radius2: 4, - angle: 0 - }) - }) + angle: 0, + }), + }), }; - function createLayer(coordinates, style, zIndex) { const feature = new Feature(new Point(coordinates)); feature.setStyle(style); const source = new VectorSource({ - features: [feature] + features: [feature], }); const vectorLayer = new VectorLayer({ - source: source + source: source, }); vectorLayer.setZIndex(zIndex); @@ -71,16 +69,15 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 18 - }) + zoom: 18, + }), }); layer0.setMap(map); - function bindInputs(id, layer) { const idxInput = document.getElementById('idx' + id); - idxInput.onchange = function() { + idxInput.onchange = function () { layer.setZIndex(parseInt(this.value, 10) || 0); }; idxInput.value = String(layer.getZIndex()); diff --git a/examples/layer-zoom-limits.html b/examples/layer-zoom-limits.html index 9727e34383..2524312545 100644 --- a/examples/layer-zoom-limits.html +++ b/examples/layer-zoom-limits.html @@ -9,5 +9,8 @@ docs: > be used to set limits. This example shows an OSM layer at zoom levels 14 and lower and a USGS layer at zoom levels higher than 14. tags: "minZoom, maxZoom, layer" +cloak: + - key: get_your_own_D6rA4zTHduk6KOKTXzGB + value: Get your own API key at https://www.maptiler.com/cloud/ --- diff --git a/examples/layer-zoom-limits.js b/examples/layer-zoom-limits.js index 0fa5ab4ada..2111f48831 100644 --- a/examples/layer-zoom-limits.js +++ b/examples/layer-zoom-limits.js @@ -1,33 +1,31 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; -import XYZ from '../src/ol/source/XYZ.js'; -import {transformExtent, fromLonLat} from '../src/ol/proj.js'; +import TileJSON from '../src/ol/source/TileJSON.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {fromLonLat} from '../src/ol/proj.js'; -const mapExtent = [-112.261791, 35.983744, -112.113981, 36.132062]; +const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; const map = new Map({ target: 'map', layers: [ new TileLayer({ maxZoom: 14, // visible at zoom levels 14 and below - source: new OSM() + source: new OSM(), }), new TileLayer({ minZoom: 14, // visible at zoom levels above 14 - source: new XYZ({ - attributions: 'Tiles © USGS, rendered with ' + - 'MapTiler', - url: 'https://tileserver.maptiler.com/grandcanyon/{z}/{x}/{y}.png' - }) - }) + source: new TileJSON({ + url: 'https://api.maptiler.com/maps/outdoor/tiles.json?key=' + key, + tileSize: 512, + }), + }), ], view: new View({ center: fromLonLat([-112.18688965, 36.057944835]), zoom: 15, maxZoom: 18, - extent: transformExtent(mapExtent, 'EPSG:4326', 'EPSG:3857'), - constrainOnlyCenter: true - }) + constrainOnlyCenter: true, + }), }); diff --git a/examples/lazy-source.js b/examples/lazy-source.js index 04a16fea66..8ab7821812 100644 --- a/examples/lazy-source.js +++ b/examples/lazy-source.js @@ -1,7 +1,7 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const source = new OSM(); @@ -12,14 +12,14 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); -document.getElementById('set-source').onclick = function() { +document.getElementById('set-source').onclick = function () { layer.setSource(source); }; -document.getElementById('unset-source').onclick = function() { +document.getElementById('unset-source').onclick = function () { layer.setSource(null); }; diff --git a/examples/line-arrows.js b/examples/line-arrows.js index e99b259d69..5d583ca97c 100644 --- a/examples/line-arrows.js +++ b/examples/line-arrows.js @@ -1,50 +1,52 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import Point from '../src/ol/geom/Point.js'; import Draw from '../src/ol/interaction/Draw.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import Map from '../src/ol/Map.js'; +import Point from '../src/ol/geom/Point.js'; +import View from '../src/ol/View.js'; import {Icon, Stroke, Style} from '../src/ol/style.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const source = new VectorSource(); -const styleFunction = function(feature) { +const styleFunction = function (feature) { const geometry = feature.getGeometry(); const styles = [ // linestring new Style({ stroke: new Stroke({ color: '#ffcc33', - width: 2 - }) - }) + width: 2, + }), + }), ]; - geometry.forEachSegment(function(start, end) { + geometry.forEachSegment(function (start, end) { const dx = end[0] - start[0]; const dy = end[1] - start[1]; const rotation = Math.atan2(dy, dx); // arrows - styles.push(new Style({ - geometry: new Point(end), - image: new Icon({ - src: 'data/arrow.png', - anchor: [0.75, 0.5], - rotateWithView: true, - rotation: -rotation + styles.push( + new Style({ + geometry: new Point(end), + image: new Icon({ + src: 'data/arrow.png', + anchor: [0.75, 0.5], + rotateWithView: true, + rotation: -rotation, + }), }) - })); + ); }); return styles; }; const vector = new VectorLayer({ source: source, - style: styleFunction + style: styleFunction, }); const map = new Map({ @@ -52,11 +54,13 @@ const map = new Map({ target: 'map', view: new View({ center: [-11000000, 4600000], - zoom: 4 - }) + zoom: 4, + }), }); -map.addInteraction(new Draw({ - source: source, - type: 'LineString' -})); +map.addInteraction( + new Draw({ + source: source, + type: 'LineString', + }) +); diff --git a/examples/localized-openstreetmap.js b/examples/localized-openstreetmap.js index a37db45fdd..2da7932a7e 100644 --- a/examples/localized-openstreetmap.js +++ b/examples/localized-openstreetmap.js @@ -1,41 +1,37 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM, {ATTRIBUTION} from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const openCycleMapLayer = new TileLayer({ source: new OSM({ attributions: [ 'All maps © OpenCycleMap', - ATTRIBUTION + ATTRIBUTION, ], - url: 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + - '?apikey=0e6fc415256d4fbb9b5166a718591d71' - }) + url: + 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + + '?apikey=0e6fc415256d4fbb9b5166a718591d71', + }), }); const openSeaMapLayer = new TileLayer({ source: new OSM({ attributions: [ 'All maps © OpenSeaMap', - ATTRIBUTION + ATTRIBUTION, ], opaque: false, - url: 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png' - }) + url: 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', + }), }); - const map = new Map({ - layers: [ - openCycleMapLayer, - openSeaMapLayer - ], + layers: [openCycleMapLayer, openSeaMapLayer], target: 'map', view: new View({ maxZoom: 18, center: [-244780.24508882355, 5986452.183179816], - zoom: 15 - }) + zoom: 15, + }), }); diff --git a/examples/magnify.js b/examples/magnify.js index 17c3a6c963..4eafe2db1b 100644 --- a/examples/magnify.js +++ b/examples/magnify.js @@ -1,12 +1,13 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; -import {fromLonLat} from '../src/ol/proj.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; +import {fromLonLat} from '../src/ol/proj.js'; import {getRenderPixel} from '../src/ol/render.js'; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const imagery = new TileLayer({ @@ -14,8 +15,8 @@ const imagery = new TileLayer({ attributions: attributions, url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, maxZoom: 20, - crossOrigin: '' - }) + crossOrigin: '', + }), }); const container = document.getElementById('map'); @@ -25,12 +26,12 @@ const map = new Map({ target: container, view: new View({ center: fromLonLat([-109, 46.5]), - zoom: 6 - }) + zoom: 6, + }), }); let radius = 75; -document.addEventListener('keydown', function(evt) { +document.addEventListener('keydown', function (evt) { if (evt.which === 38) { radius = Math.min(radius + 5, 150); map.render(); @@ -45,22 +46,27 @@ document.addEventListener('keydown', function(evt) { // get the pixel position with every move let mousePosition = null; -container.addEventListener('mousemove', function(event) { +container.addEventListener('mousemove', function (event) { mousePosition = map.getEventPixel(event); map.render(); }); -container.addEventListener('mouseout', function() { +container.addEventListener('mouseout', function () { mousePosition = null; map.render(); }); // after rendering the layer, show an oversampled version around the pointer -imagery.on('postrender', function(event) { +imagery.on('postrender', function (event) { if (mousePosition) { const pixel = getRenderPixel(event, mousePosition); - const offset = getRenderPixel(event, [mousePosition[0] + radius, mousePosition[1]]); - const half = Math.sqrt(Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2)); + const offset = getRenderPixel(event, [ + mousePosition[0] + radius, + mousePosition[1], + ]); + const half = Math.sqrt( + Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2) + ); const context = event.context; const centerX = pixel[0]; const centerY = pixel[1]; @@ -91,7 +97,7 @@ imagery.on('postrender', function(event) { } context.beginPath(); context.arc(centerX, centerY, half, 0, 2 * Math.PI); - context.lineWidth = 3 * half / radius; + context.lineWidth = (3 * half) / radius; context.strokeStyle = 'rgba(255,255,255,0.5)'; context.putImageData(dest, originX, originY); context.stroke(); diff --git a/examples/mapbox-layer.css b/examples/mapbox-layer.css new file mode 100644 index 0000000000..07c3d5d8d2 --- /dev/null +++ b/examples/mapbox-layer.css @@ -0,0 +1,5 @@ +/* Reset font size changed by Mapbox CSS */ +.map { + font-size: medium; + font-family: 'Quattrocento Sans', sans-serif; +} diff --git a/examples/mapbox-layer.html b/examples/mapbox-layer.html index 05a67fdf21..bd8bfa7ec6 100644 --- a/examples/mapbox-layer.html +++ b/examples/mapbox-layer.html @@ -7,8 +7,8 @@ docs: > tags: "simple, mapbox, vector, tiles, maptiler" experimental: true resources: - - https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.js - - https://unpkg.com/mapbox-gl@0.54.0/dist/mapbox-gl.css + - https://unpkg.com/mapbox-gl@1.11.1/dist/mapbox-gl.js + - https://unpkg.com/mapbox-gl@1.11.1/dist/mapbox-gl.css cloak: - key: get_your_own_D6rA4zTHduk6KOKTXzGB value: Get your own API key at https://www.maptiler.com/cloud/ diff --git a/examples/mapbox-layer.js b/examples/mapbox-layer.js index 2bb3e4fa4c..e2f93463d5 100644 --- a/examples/mapbox-layer.js +++ b/examples/mapbox-layer.js @@ -1,11 +1,12 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; +import GeoJSON from '../src/ol/format/GeoJSON.js'; import Layer from '../src/ol/layer/Layer.js'; -import {toLonLat, fromLonLat} from '../src/ol/proj.js'; -import {Stroke, Style} from '../src/ol/style.js'; +import Map from '../src/ol/Map.js'; +import Source from '../src/ol/source/Source.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; -import GeoJSON from '../src/ol/format/GeoJSON.js'; +import View from '../src/ol/View.js'; +import {Stroke, Style} from '../src/ol/style.js'; +import {fromLonLat, toLonLat} from '../src/ol/proj.js'; const center = [-98.8, 37.9]; const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; @@ -23,11 +24,11 @@ const mbMap = new mapboxgl.Map({ keyboard: false, pitchWithRotate: false, scrollZoom: false, - touchZoomRotate: false + touchZoomRotate: false, }); const mbLayer = new Layer({ - render: function(frameState) { + render: function (frameState) { const canvas = mbMap.getCanvas(); const viewState = frameState.viewState; @@ -39,20 +40,16 @@ const mbLayer = new Layer({ // adjust view parameters in mapbox const rotation = viewState.rotation; - if (rotation) { - mbMap.rotateTo(-rotation * 180 / Math.PI, { - animate: false - }); - } mbMap.jumpTo({ center: toLonLat(viewState.center), zoom: viewState.zoom - 1, - animate: false + bearing: (-rotation * 180) / Math.PI, + animate: false, }); // cancel the scheduled update & trigger synchronous redraw // see https://github.com/mapbox/mapbox-gl-js/issues/7893#issue-408992184 - // NOTE: THIS MIGHT BREAK WHEN UPDATING MAPBOX + // NOTE: THIS MIGHT BREAK IF UPDATING THE MAPBOX VERSION if (mbMap._frame) { mbMap._frame.cancel(); mbMap._frame = null; @@ -60,29 +57,35 @@ const mbLayer = new Layer({ mbMap._render(); return canvas; - } + }, + source: new Source({ + attributions: [ + '© MapTiler', + '© OpenStreetMap contributors', + ], + }), }); const style = new Style({ stroke: new Stroke({ color: '#319FD3', - width: 2 - }) + width: 2, + }), }); const vectorLayer = new VectorLayer({ source: new VectorSource({ url: 'data/geojson/countries.geojson', - format: new GeoJSON() + format: new GeoJSON(), }), - style: style + style: style, }); const map = new Map({ target: 'map', view: new View({ center: fromLonLat(center), - zoom: 4 + zoom: 4, }), - layers: [mbLayer, vectorLayer] + layers: [mbLayer, vectorLayer], }); diff --git a/examples/mapbox-style.css b/examples/mapbox-style.css new file mode 100644 index 0000000000..00452f8269 --- /dev/null +++ b/examples/mapbox-style.css @@ -0,0 +1,6 @@ +.map .ol-rotate { + left: .5em; + bottom: .5em; + top: auto; + right: auto; +} diff --git a/examples/mapbox-style.html b/examples/mapbox-style.html index 8285734955..1c88215464 100644 --- a/examples/mapbox-style.html +++ b/examples/mapbox-style.html @@ -1,5 +1,5 @@ --- -layout: example-verbatim.html +layout: example.html title: Vector tiles created from a Mapbox Style object shortdesc: Example of using ol-mapbox-style with tiles from maptiler.com. docs: > @@ -10,27 +10,4 @@ cloak: - key: get_your_own_D6rA4zTHduk6KOKTXzGB value: Get your own API key at https://www.maptiler.com/cloud/ --- - - - - - - - Mapbox Style objects with ol-mapbox-style - - - - - - - - - - + diff --git a/examples/mapbox-style.js b/examples/mapbox-style.js index 819177a69d..03f712e594 100644 --- a/examples/mapbox-style.js +++ b/examples/mapbox-style.js @@ -1,3 +1,9 @@ +import FullScreen from '../src/ol/control/FullScreen.js'; import apply from 'ol-mapbox-style'; -apply('map', 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB'); +apply( + 'map', + 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB' +).then(function (map) { + map.addControl(new FullScreen()); +}); diff --git a/examples/mapbox-vector-layer.css b/examples/mapbox-vector-layer.css new file mode 100644 index 0000000000..33e90f7301 --- /dev/null +++ b/examples/mapbox-vector-layer.css @@ -0,0 +1,3 @@ +.map { + background: #f8f4f0; +} diff --git a/examples/mapbox-vector-layer.html b/examples/mapbox-vector-layer.html new file mode 100644 index 0000000000..92cdc9a857 --- /dev/null +++ b/examples/mapbox-vector-layer.html @@ -0,0 +1,15 @@ +--- +layout: example.html +title: Mapbox Vector Layer +shortdesc: Rendering a layer with a Mapbox-hosted style. +docs: > + The MapboxVector layer allows you to create a layer based on a Mapbox-hosted style using a single + vector source. If your style uses more than one source, use the `source` property to choose a + single vector source. Use the `layers` property if you only want to render a subset of the style's + layers (provided they all share the same source). +tags: "mapbox, studio, vector, tiles" +cloak: + - key: pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q + value: Your Mapbox access token from https://mapbox.com/ here +--- + diff --git a/examples/mapbox-vector-layer.js b/examples/mapbox-vector-layer.js new file mode 100644 index 0000000000..3fdc9d7f8b --- /dev/null +++ b/examples/mapbox-vector-layer.js @@ -0,0 +1,18 @@ +import Map from '../src/ol/Map.js'; +import MapboxVector from '../src/ol/layer/MapboxVector.js'; +import View from '../src/ol/View.js'; + +const map = new Map({ + target: 'map', + layers: [ + new MapboxVector({ + styleUrl: 'mapbox://styles/mapbox/bright-v9', + accessToken: + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q', + }), + ], + view: new View({ + center: [0, 0], + zoom: 2, + }), +}); diff --git a/examples/mapbox-vector-tiles-advanced.js b/examples/mapbox-vector-tiles-advanced.js index f8b15fd20a..037b3f76eb 100644 --- a/examples/mapbox-vector-tiles-advanced.js +++ b/examples/mapbox-vector-tiles-advanced.js @@ -1,14 +1,14 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import MVT from '../src/ol/format/MVT.js'; -import VectorTileLayer from '../src/ol/layer/VectorTile.js'; -import {get as getProjection} from '../src/ol/proj.js'; -import VectorTileSource from '../src/ol/source/VectorTile.js'; -import {Fill, Icon, Stroke, Style, Text} from '../src/ol/style.js'; +import Map from '../src/ol/Map.js'; import TileGrid from '../src/ol/tilegrid/TileGrid.js'; +import VectorTileLayer from '../src/ol/layer/VectorTile.js'; +import VectorTileSource from '../src/ol/source/VectorTile.js'; +import View from '../src/ol/View.js'; +import {Fill, Icon, Stroke, Style, Text} from '../src/ol/style.js'; +import {get as getProjection} from '../src/ol/proj.js'; - -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; // Calculation of resolutions that match zoom levels 1, 3, 5, 7, 9, 11, 13, 15. const resolutions = []; @@ -17,37 +17,43 @@ for (let i = 0; i <= 8; ++i) { } // Calculation of tile urls for zoom levels 1, 3, 5, 7, 9, 11, 13, 15. function tileUrlFunction(tileCoord) { - return ('https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' + - '{z}/{x}/{y}.vector.pbf?access_token=' + key) + return ( + 'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' + + '{z}/{x}/{y}.vector.pbf?access_token=' + + key + ) .replace('{z}', String(tileCoord[0] * 2 - 1)) .replace('{x}', String(tileCoord[1])) .replace('{y}', String(tileCoord[2])) - .replace('{a-d}', 'abcd'.substr( - ((tileCoord[1] << tileCoord[0]) + tileCoord[2]) % 4, 1)); + .replace( + '{a-d}', + 'abcd'.substr(((tileCoord[1] << tileCoord[0]) + tileCoord[2]) % 4, 1) + ); } const map = new Map({ layers: [ new VectorTileLayer({ source: new VectorTileSource({ - attributions: '© Mapbox ' + + attributions: + '© Mapbox ' + '© ' + 'OpenStreetMap contributors', format: new MVT(), tileGrid: new TileGrid({ extent: getProjection('EPSG:3857').getExtent(), resolutions: resolutions, - tileSize: 512 + tileSize: 512, }), - tileUrlFunction: tileUrlFunction + tileUrlFunction: tileUrlFunction, }), - style: createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text) - }) + style: createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text), + }), ], target: 'map', view: new View({ center: [0, 0], minZoom: 1, - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/mapbox-vector-tiles.js b/examples/mapbox-vector-tiles.js index ac5e796a61..f4aaea324c 100644 --- a/examples/mapbox-vector-tiles.js +++ b/examples/mapbox-vector-tiles.js @@ -1,31 +1,34 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import MVT from '../src/ol/format/MVT.js'; +import Map from '../src/ol/Map.js'; import VectorTileLayer from '../src/ol/layer/VectorTile.js'; import VectorTileSource from '../src/ol/source/VectorTile.js'; +import View from '../src/ol/View.js'; import {Fill, Icon, Stroke, Style, Text} from '../src/ol/style.js'; - -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; const map = new Map({ layers: [ new VectorTileLayer({ declutter: true, source: new VectorTileSource({ - attributions: '© Mapbox ' + + attributions: + '© Mapbox ' + '© ' + 'OpenStreetMap contributors', format: new MVT(), - url: 'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' + - '{z}/{x}/{y}.vector.pbf?access_token=' + key + url: + 'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' + + '{z}/{x}/{y}.vector.pbf?access_token=' + + key, }), - style: createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text) - }) + style: createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/mapguide-untiled.js b/examples/mapguide-untiled.js index a9e3846cf4..474b0d3cd6 100644 --- a/examples/mapguide-untiled.js +++ b/examples/mapguide-untiled.js @@ -1,16 +1,15 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import ImageLayer from '../src/ol/layer/Image.js'; import ImageMapGuide from '../src/ol/source/ImageMapGuide.js'; +import Map from '../src/ol/Map.js'; +import View from '../src/ol/View.js'; const mdf = 'Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition'; -const agentUrl = - 'http://138.197.230.93:8008/mapguide/mapagent/mapagent.fcgi?'; +const agentUrl = 'http://138.197.230.93:8008/mapguide/mapagent/mapagent.fcgi?'; const bounds = [ -87.865114442365922, 43.665065564837931, -87.595394059497067, - 43.823852564430069 + 43.823852564430069, ]; const map = new Map({ layers: [ @@ -26,16 +25,16 @@ const map = new Map({ FORMAT: 'PNG', VERSION: '3.0.0', USERNAME: 'OLGuest', - PASSWORD: 'olguest' + PASSWORD: 'olguest', }, - ratio: 2 - }) - }) + ratio: 2, + }), + }), ], target: 'map', view: new View({ center: [-87.7302542509315, 43.744459064634], projection: 'EPSG:4326', - zoom: 12 - }) + zoom: 12, + }), }); diff --git a/examples/measure.js b/examples/measure.js index 37666f4251..6e4b1e2530 100644 --- a/examples/measure.js +++ b/examples/measure.js @@ -1,17 +1,16 @@ -import Map from '../src/ol/Map.js'; -import {unByKey} from '../src/ol/Observable.js'; -import Overlay from '../src/ol/Overlay.js'; -import {getArea, getLength} from '../src/ol/sphere.js'; -import View from '../src/ol/View.js'; -import {LineString, Polygon} from '../src/ol/geom.js'; import Draw from '../src/ol/interaction/Draw.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; -import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import Map from '../src/ol/Map.js'; +import Overlay from '../src/ol/Overlay.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; - +import {LineString, Polygon} from '../src/ol/geom.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import {getArea, getLength} from '../src/ol/sphere.js'; +import {unByKey} from '../src/ol/Observable.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const source = new VectorSource(); @@ -20,76 +19,68 @@ const vector = new VectorLayer({ source: source, style: new Style({ fill: new Fill({ - color: 'rgba(255, 255, 255, 0.2)' + color: 'rgba(255, 255, 255, 0.2)', }), stroke: new Stroke({ color: '#ffcc33', - width: 2 + width: 2, }), image: new CircleStyle({ radius: 7, fill: new Fill({ - color: '#ffcc33' - }) - }) - }) + color: '#ffcc33', + }), + }), + }), }); - /** * Currently drawn feature. * @type {import("../src/ol/Feature.js").default} */ let sketch; - /** * The help tooltip element. * @type {HTMLElement} */ let helpTooltipElement; - /** * Overlay to show the help messages. * @type {Overlay} */ let helpTooltip; - /** * The measure tooltip element. * @type {HTMLElement} */ let measureTooltipElement; - /** * Overlay to show the measurement. * @type {Overlay} */ let measureTooltip; - /** * Message to show when the user is drawing a polygon. * @type {string} */ const continuePolygonMsg = 'Click to continue drawing the polygon'; - /** * Message to show when the user is drawing a line. * @type {string} */ const continueLineMsg = 'Click to continue drawing the line'; - /** * Handle pointer move. * @param {import("../src/ol/MapBrowserEvent").default} evt The event. */ -const pointerMoveHandler = function(evt) { +const pointerMoveHandler = function (evt) { if (evt.dragging) { return; } @@ -111,19 +102,18 @@ const pointerMoveHandler = function(evt) { helpTooltipElement.classList.remove('hidden'); }; - const map = new Map({ layers: [raster, vector], target: 'map', view: new View({ center: [-11000000, 4600000], - zoom: 15 - }) + zoom: 15, + }), }); map.on('pointermove', pointerMoveHandler); -map.getViewport().addEventListener('mouseout', function() { +map.getViewport().addEventListener('mouseout', function () { helpTooltipElement.classList.add('hidden'); }); @@ -131,68 +121,62 @@ const typeSelect = document.getElementById('type'); let draw; // global so we can remove it later - /** * Format length output. * @param {LineString} line The line. * @return {string} The formatted length. */ -const formatLength = function(line) { +const formatLength = function (line) { const length = getLength(line); let output; if (length > 100) { - output = (Math.round(length / 1000 * 100) / 100) + - ' ' + 'km'; + output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km'; } else { - output = (Math.round(length * 100) / 100) + - ' ' + 'm'; + output = Math.round(length * 100) / 100 + ' ' + 'm'; } return output; }; - /** * Format area output. * @param {Polygon} polygon The polygon. * @return {string} Formatted area. */ -const formatArea = function(polygon) { +const formatArea = function (polygon) { const area = getArea(polygon); let output; if (area > 10000) { - output = (Math.round(area / 1000000 * 100) / 100) + - ' ' + 'km2'; + output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km2'; } else { - output = (Math.round(area * 100) / 100) + - ' ' + 'm2'; + output = Math.round(area * 100) / 100 + ' ' + 'm2'; } return output; }; function addInteraction() { - const type = (typeSelect.value == 'area' ? 'Polygon' : 'LineString'); + const type = typeSelect.value == 'area' ? 'Polygon' : 'LineString'; draw = new Draw({ source: source, type: type, style: new Style({ fill: new Fill({ - color: 'rgba(255, 255, 255, 0.2)' + color: 'rgba(255, 255, 255, 0.2)', }), stroke: new Stroke({ color: 'rgba(0, 0, 0, 0.5)', lineDash: [10, 10], - width: 2 + width: 2, }), image: new CircleStyle({ radius: 5, stroke: new Stroke({ - color: 'rgba(0, 0, 0, 0.7)' + color: 'rgba(0, 0, 0, 0.7)', }), fill: new Fill({ - color: 'rgba(255, 255, 255, 0.2)' - }) - }) - }) + color: 'rgba(255, 255, 255, 0.2)', + }), + }), + }), }); map.addInteraction(draw); @@ -200,43 +184,40 @@ function addInteraction() { createHelpTooltip(); let listener; - draw.on('drawstart', - function(evt) { - // set sketch - sketch = evt.feature; + draw.on('drawstart', function (evt) { + // set sketch + sketch = evt.feature; - /** @type {import("../src/ol/coordinate.js").Coordinate|undefined} */ - let tooltipCoord = evt.coordinate; + /** @type {import("../src/ol/coordinate.js").Coordinate|undefined} */ + let tooltipCoord = evt.coordinate; - listener = sketch.getGeometry().on('change', function(evt) { - const geom = evt.target; - let output; - if (geom instanceof Polygon) { - output = formatArea(geom); - tooltipCoord = geom.getInteriorPoint().getCoordinates(); - } else if (geom instanceof LineString) { - output = formatLength(geom); - tooltipCoord = geom.getLastCoordinate(); - } - measureTooltipElement.innerHTML = output; - measureTooltip.setPosition(tooltipCoord); - }); + listener = sketch.getGeometry().on('change', function (evt) { + const geom = evt.target; + let output; + if (geom instanceof Polygon) { + output = formatArea(geom); + tooltipCoord = geom.getInteriorPoint().getCoordinates(); + } else if (geom instanceof LineString) { + output = formatLength(geom); + tooltipCoord = geom.getLastCoordinate(); + } + measureTooltipElement.innerHTML = output; + measureTooltip.setPosition(tooltipCoord); }); + }); - draw.on('drawend', - function() { - measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'; - measureTooltip.setOffset([0, -7]); - // unset sketch - sketch = null; - // unset tooltip so that a new one can be created - measureTooltipElement = null; - createMeasureTooltip(); - unByKey(listener); - }); + draw.on('drawend', function () { + measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'; + measureTooltip.setOffset([0, -7]); + // unset sketch + sketch = null; + // unset tooltip so that a new one can be created + measureTooltipElement = null; + createMeasureTooltip(); + unByKey(listener); + }); } - /** * Creates a new help tooltip */ @@ -249,12 +230,11 @@ function createHelpTooltip() { helpTooltip = new Overlay({ element: helpTooltipElement, offset: [15, 0], - positioning: 'center-left' + positioning: 'center-left', }); map.addOverlay(helpTooltip); } - /** * Creates a new measure tooltip */ @@ -267,16 +247,15 @@ function createMeasureTooltip() { measureTooltip = new Overlay({ element: measureTooltipElement, offset: [0, -15], - positioning: 'bottom-center' + positioning: 'bottom-center', }); map.addOverlay(measureTooltip); } - /** * Let user change the geometry type. */ -typeSelect.onchange = function() { +typeSelect.onchange = function () { map.removeInteraction(draw); addInteraction(); }; diff --git a/examples/min-max-resolution.js b/examples/min-max-resolution.js index 062c22b837..27b67b6ab3 100644 --- a/examples/min-max-resolution.js +++ b/examples/min-max-resolution.js @@ -1,10 +1,11 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; import TileJSON from '../src/ol/source/TileJSON.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; /** * Create the map. @@ -14,20 +15,22 @@ const map = new Map({ new TileLayer({ source: new OSM(), minResolution: 200, - maxResolution: 2000 + maxResolution: 2000, }), new TileLayer({ source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.natural-earth-hypso-bathy.json?secure&access_token=' + key, - crossOrigin: 'anonymous' + url: + 'https://api.tiles.mapbox.com/v4/mapbox.natural-earth-hypso-bathy.json?secure&access_token=' + + key, + crossOrigin: 'anonymous', }), minResolution: 2000, - maxResolution: 20000 - }) + maxResolution: 20000, + }), ], target: 'map', view: new View({ center: [653600, 5723680], - zoom: 5 - }) + zoom: 5, + }), }); diff --git a/examples/min-zoom.js b/examples/min-zoom.js index f37740f9ce..38b0260c93 100644 --- a/examples/min-zoom.js +++ b/examples/min-zoom.js @@ -1,7 +1,7 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const viewport = document.getElementById('map'); @@ -15,20 +15,20 @@ const initialZoom = getMinZoom(); const view = new View({ center: [0, 0], minZoom: initialZoom, - zoom: initialZoom + zoom: initialZoom, }); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', - view: view + view: view, }); -window.addEventListener('resize', function() { +window.addEventListener('resize', function () { const minZoom = getMinZoom(); if (minZoom !== view.getMinZoom()) { view.setMinZoom(minZoom); diff --git a/examples/mobile-full-screen.html b/examples/mobile-full-screen.html index 8bb8b0ee22..cfc4a270c1 100644 --- a/examples/mobile-full-screen.html +++ b/examples/mobile-full-screen.html @@ -4,7 +4,7 @@ title: Full-Screen Mobile shortdesc: Example of a full screen map. tags: "fullscreen, geolocation, mobile" cloak: - - key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5 + - key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp value: Your Bing Maps Key from http://www.bingmapsportal.com/ here --- diff --git a/examples/mobile-full-screen.js b/examples/mobile-full-screen.js index d1a3071bbe..1c3bbb701f 100644 --- a/examples/mobile-full-screen.js +++ b/examples/mobile-full-screen.js @@ -1,33 +1,33 @@ +import BingMaps from '../src/ol/source/BingMaps.js'; import Geolocation from '../src/ol/Geolocation.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; -import BingMaps from '../src/ol/source/BingMaps.js'; - +import View from '../src/ol/View.js'; const view = new View({ center: [0, 0], - zoom: 2 + zoom: 2, }); const map = new Map({ layers: [ new TileLayer({ source: new BingMaps({ - key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5', - imagerySet: 'RoadOnDemand' - }) - }) + key: + 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp ', + imagerySet: 'RoadOnDemand', + }), + }), ], target: 'map', - view: view + view: view, }); const geolocation = new Geolocation({ projection: view.getProjection(), - tracking: true + tracking: true, }); -geolocation.once('change:position', function() { +geolocation.once('change:position', function () { view.setCenter(geolocation.getPosition()); view.setResolution(2.388657133911758); }); diff --git a/examples/modify-features.js b/examples/modify-features.js index 3be37f11dc..488508fe35 100644 --- a/examples/modify-features.js +++ b/examples/modify-features.js @@ -1,29 +1,32 @@ +import GeoJSON from '../src/ol/format/GeoJSON.js'; import Map from '../src/ol/Map.js'; import View from '../src/ol/View.js'; -import GeoJSON from '../src/ol/format/GeoJSON.js'; -import {defaults as defaultInteractions, Modify, Select} from '../src/ol/interaction.js'; -import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; +import { + Modify, + Select, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; import {OSM, Vector as VectorSource} from '../src/ol/source.js'; - +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; const raster = new TileLayer({ - source: new OSM() + source: new OSM(), }); const vector = new VectorLayer({ source: new VectorSource({ url: 'data/geojson/countries.geojson', format: new GeoJSON(), - wrapX: false - }) + wrapX: false, + }), }); const select = new Select({ - wrapX: false + wrapX: false, }); const modify = new Modify({ - features: select.getFeatures() + features: select.getFeatures(), }); const map = new Map({ @@ -32,6 +35,6 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/modify-test.js b/examples/modify-test.js index f399546a03..13f6b17384 100644 --- a/examples/modify-test.js +++ b/examples/modify-test.js @@ -1,55 +1,58 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; -import {defaults as defaultInteractions, Modify, Select} from '../src/ol/interaction.js'; +import Map from '../src/ol/Map.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; +import { + Modify, + Select, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; - -const styleFunction = (function() { +const styleFunction = (function () { const styles = {}; const image = new CircleStyle({ radius: 5, fill: null, - stroke: new Stroke({color: 'orange', width: 2}) + stroke: new Stroke({color: 'orange', width: 2}), }); styles['Point'] = new Style({image: image}); styles['Polygon'] = new Style({ stroke: new Stroke({ color: 'blue', - width: 3 + width: 3, }), fill: new Fill({ - color: 'rgba(0, 0, 255, 0.1)' - }) + color: 'rgba(0, 0, 255, 0.1)', + }), }); styles['MultiLineString'] = new Style({ stroke: new Stroke({ color: 'green', - width: 3 - }) + width: 3, + }), }); styles['MultiPolygon'] = new Style({ stroke: new Stroke({ color: 'yellow', - width: 1 + width: 1, }), fill: new Fill({ - color: 'rgba(255, 255, 0, 0.1)' - }) + color: 'rgba(255, 255, 0, 0.1)', + }), }); styles['default'] = new Style({ stroke: new Stroke({ color: 'red', - width: 3 + width: 3, }), fill: new Fill({ - color: 'rgba(255, 0, 0, 0.1)' + color: 'rgba(255, 0, 0, 0.1)', }), - image: image + image: image, }); - return function(feature) { + return function (feature) { return styles[feature.getGeometry().getType()] || styles['default']; }; })(); @@ -59,115 +62,209 @@ const geojsonObject = { 'crs': { 'type': 'name', 'properties': { - 'name': 'EPSG:3857' - } + 'name': 'EPSG:3857', + }, }, - 'features': [{ - 'type': 'Feature', - 'geometry': { - 'type': 'Point', - 'coordinates': [0, 0] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiPoint', - 'coordinates': [[-2e6, 0], [0, -2e6]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'LineString', - 'coordinates': [[4e6, -2e6], [8e6, 2e6], [9e6, 2e6]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'LineString', - 'coordinates': [[4e6, -2e6], [8e6, 2e6], [8e6, 3e6]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [[[-5e6, -1e6], [-4e6, 1e6], - [-3e6, -1e6], [-5e6, -1e6]], [[-4.5e6, -0.5e6], - [-3.5e6, -0.5e6], [-4e6, 0.5e6], [-4.5e6, -0.5e6]]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiLineString', - 'coordinates': [ - [[-1e6, -7.5e5], [-1e6, 7.5e5]], - [[-1e6, -7.5e5], [-1e6, 7.5e5], [-5e5, 0], [-1e6, -7.5e5]], - [[1e6, -7.5e5], [15e5, 0], [15e5, 0], [1e6, 7.5e5]], - [[-7.5e5, -1e6], [7.5e5, -1e6]], - [[-7.5e5, 1e6], [7.5e5, 1e6]] - ] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiPolygon', - 'coordinates': [ - [[[-5e6, 6e6], [-5e6, 8e6], [-3e6, 8e6], - [-3e6, 6e6], [-5e6, 6e6]]], - [[[-3e6, 6e6], [-2e6, 8e6], [0, 8e6], - [0, 6e6], [-3e6, 6e6]]], - [[[1e6, 6e6], [1e6, 8e6], [3e6, 8e6], - [3e6, 6e6], [1e6, 6e6]]] - ] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'GeometryCollection', - 'geometries': [{ - 'type': 'LineString', - 'coordinates': [[-5e6, -5e6], [0, -5e6]] - }, { + 'features': [ + { + 'type': 'Feature', + 'geometry': { 'type': 'Point', - 'coordinates': [4e6, -5e6] - }, { + 'coordinates': [0, 0], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiPoint', + 'coordinates': [ + [-2e6, 0], + [0, -2e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [ + [4e6, -2e6], + [8e6, 2e6], + [9e6, 2e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [ + [4e6, -2e6], + [8e6, 2e6], + [8e6, 3e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { 'type': 'Polygon', 'coordinates': [ - [[1e6, -6e6], [2e6, -4e6], [3e6, -6e6], [1e6, -6e6]] - ] - }] - } - }] + [ + [-5e6, -1e6], + [-4e6, 1e6], + [-3e6, -1e6], + [-5e6, -1e6], + ], + [ + [-4.5e6, -0.5e6], + [-3.5e6, -0.5e6], + [-4e6, 0.5e6], + [-4.5e6, -0.5e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiLineString', + 'coordinates': [ + [ + [-1e6, -7.5e5], + [-1e6, 7.5e5], + ], + [ + [-1e6, -7.5e5], + [-1e6, 7.5e5], + [-5e5, 0], + [-1e6, -7.5e5], + ], + [ + [1e6, -7.5e5], + [15e5, 0], + [15e5, 0], + [1e6, 7.5e5], + ], + [ + [-7.5e5, -1e6], + [7.5e5, -1e6], + ], + [ + [-7.5e5, 1e6], + [7.5e5, 1e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiPolygon', + 'coordinates': [ + [ + [ + [-5e6, 6e6], + [-5e6, 8e6], + [-3e6, 8e6], + [-3e6, 6e6], + [-5e6, 6e6], + ], + ], + [ + [ + [-3e6, 6e6], + [-2e6, 8e6], + [0, 8e6], + [0, 6e6], + [-3e6, 6e6], + ], + ], + [ + [ + [1e6, 6e6], + [1e6, 8e6], + [3e6, 8e6], + [3e6, 6e6], + [1e6, 6e6], + ], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'GeometryCollection', + 'geometries': [ + { + 'type': 'LineString', + 'coordinates': [ + [-5e6, -5e6], + [0, -5e6], + ], + }, + { + 'type': 'Point', + 'coordinates': [4e6, -5e6], + }, + { + 'type': 'Polygon', + 'coordinates': [ + [ + [1e6, -5e6], + [2e6, -3.5e6], + [3e6, -5e6], + [1e6, -5e6], + ], + ], + }, + { + 'type': 'Polygon', + 'coordinates': [ + [ + [1e6, -5e6], + [2e6, -6.5e6], + [3e6, -5e6], + [1e6, -5e6], + ], + ], + }, + ], + }, + }, + ], }; const source = new VectorSource({ - features: (new GeoJSON()).readFeatures(geojsonObject) + features: new GeoJSON().readFeatures(geojsonObject), }); const layer = new VectorLayer({ source: source, - style: styleFunction + style: styleFunction, }); -const overlayStyle = (function() { +const overlayStyle = (function () { const styles = {}; styles['Polygon'] = [ new Style({ fill: new Fill({ - color: [255, 255, 255, 0.5] - }) + color: [255, 255, 255, 0.5], + }), }), new Style({ stroke: new Stroke({ color: [255, 255, 255, 1], - width: 5 - }) + width: 5, + }), }), new Style({ stroke: new Stroke({ color: [0, 153, 255, 1], - width: 3 - }) - }) + width: 3, + }), + }), ]; styles['MultiPolygon'] = styles['Polygon']; @@ -175,15 +272,15 @@ const overlayStyle = (function() { new Style({ stroke: new Stroke({ color: [255, 255, 255, 1], - width: 5 - }) + width: 5, + }), }), new Style({ stroke: new Stroke({ color: [0, 153, 255, 1], - width: 3 - }) - }) + width: 3, + }), + }), ]; styles['MultiLineString'] = styles['LineString']; @@ -192,38 +289,44 @@ const overlayStyle = (function() { image: new CircleStyle({ radius: 7, fill: new Fill({ - color: [0, 153, 255, 1] + color: [0, 153, 255, 1], }), stroke: new Stroke({ color: [255, 255, 255, 0.75], - width: 1.5 - }) + width: 1.5, + }), }), - zIndex: 100000 - }) + zIndex: 100000, + }), ]; styles['MultiPoint'] = styles['Point']; styles['GeometryCollection'] = styles['Polygon'].concat(styles['Point']); - return function(feature) { + return function (feature) { return styles[feature.getGeometry().getType()]; }; })(); const select = new Select({ - style: overlayStyle + style: overlayStyle, }); const modify = new Modify({ features: select.getFeatures(), style: overlayStyle, - insertVertexCondition: function() { + insertVertexCondition: function () { // prevent new vertices to be added to the polygons - return !select.getFeatures().getArray().every(function(feature) { - return feature.getGeometry().getType().match(/Polygon/); - }); - } + return !select + .getFeatures() + .getArray() + .every(function (feature) { + return feature + .getGeometry() + .getType() + .match(/Polygon/); + }); + }, }); const map = new Map({ @@ -232,6 +335,7 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 1000000], - zoom: 2 - }) + zoom: 2, + multiWorld: true, + }), }); diff --git a/examples/mouse-position.js b/examples/mouse-position.js index aaf4d51c89..5b198c3030 100644 --- a/examples/mouse-position.js +++ b/examples/mouse-position.js @@ -1,10 +1,10 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls} from '../src/ol/control.js'; import MousePosition from '../src/ol/control/MousePosition.js'; -import {createStringXY} from '../src/ol/coordinate.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {createStringXY} from '../src/ol/coordinate.js'; +import {defaults as defaultControls} from '../src/ol/control.js'; const mousePositionControl = new MousePosition({ coordinateFormat: createStringXY(4), @@ -13,30 +13,30 @@ const mousePositionControl = new MousePosition({ // be placed within the map. className: 'custom-mouse-position', target: document.getElementById('mouse-position'), - undefinedHTML: ' ' + undefinedHTML: ' ', }); const map = new Map({ controls: defaultControls().extend([mousePositionControl]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const projectionSelect = document.getElementById('projection'); -projectionSelect.addEventListener('change', function(event) { +projectionSelect.addEventListener('change', function (event) { mousePositionControl.setProjection(event.target.value); }); const precisionInput = document.getElementById('precision'); -precisionInput.addEventListener('change', function(event) { +precisionInput.addEventListener('change', function (event) { const format = createStringXY(event.target.valueAsNumber); mousePositionControl.setCoordinateFormat(format); }); diff --git a/examples/moveend.js b/examples/moveend.js index da762ed600..17d69ef0c2 100644 --- a/examples/moveend.js +++ b/examples/moveend.js @@ -1,22 +1,21 @@ import Map from '../src/ol/Map.js'; +import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; import View from '../src/ol/View.js'; import {getBottomLeft, getTopRight} from '../src/ol/extent.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import {toLonLat} from '../src/ol/proj.js'; -import OSM from '../src/ol/source/OSM.js'; - const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); function display(id, value) { @@ -25,7 +24,7 @@ function display(id, value) { function wrapLon(value) { const worlds = Math.floor((value + 180) / 360); - return value - (worlds * 360); + return value - worlds * 360; } function onMoveEnd(evt) { diff --git a/examples/navigation-controls.js b/examples/navigation-controls.js index 9b4ed18b34..6d63b19139 100644 --- a/examples/navigation-controls.js +++ b/examples/navigation-controls.js @@ -1,27 +1,28 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, ZoomToExtent} from '../src/ol/control.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {ZoomToExtent, defaults as defaultControls} from '../src/ol/control.js'; const map = new Map({ controls: defaultControls().extend([ new ZoomToExtent({ extent: [ - 813079.7791264898, 5929220.284081122, - 848966.9639063801, 5936863.986909639 - ] - }) + 813079.7791264898, + 5929220.284081122, + 848966.9639063801, + 5936863.986909639, + ], + }), ]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/offscreen-canvas.css b/examples/offscreen-canvas.css new file mode 100644 index 0000000000..aa8012667b --- /dev/null +++ b/examples/offscreen-canvas.css @@ -0,0 +1,9 @@ +.map { + background: rgba(232, 230, 223, 1); +} +.map .ol-rotate { + left: .5em; + bottom: .5em; + top: auto; + right: auto; +} diff --git a/examples/offscreen-canvas.html b/examples/offscreen-canvas.html new file mode 100644 index 0000000000..741d469e23 --- /dev/null +++ b/examples/offscreen-canvas.html @@ -0,0 +1,10 @@ +--- +layout: example.html +title: Vector tiles rendered in an offscreen canvas +shortdesc: Example of a map that delegates rendering to a worker. +docs: > + The map in this example is rendered in a web worker, using `OffscreenCanvas`. **Note:** This is currently only supported in Chrome and Edge. +tags: "worker, offscreencanvas, vector-tiles" +experimental: true +--- + diff --git a/examples/offscreen-canvas.js b/examples/offscreen-canvas.js new file mode 100644 index 0000000000..c70de0afcb --- /dev/null +++ b/examples/offscreen-canvas.js @@ -0,0 +1,139 @@ +import Layer from '../src/ol/layer/Layer.js'; +import Map from '../src/ol/Map.js'; +import Source from '../src/ol/source/Source.js'; +import View from '../src/ol/View.js'; +import Worker from 'worker-loader!./offscreen-canvas.worker.js'; //eslint-disable-line +import stringify from 'json-stringify-safe'; +import {FullScreen} from '../src/ol/control.js'; +import {compose, create} from '../src/ol/transform.js'; +import {createTransformString} from '../src/ol/render/canvas.js'; +import {createXYZ} from '../src/ol/tilegrid.js'; + +const worker = new Worker(); + +let container, + transformContainer, + canvas, + rendering, + workerFrameState, + mainThreadFrameState; + +// Transform the container to account for the differnece between the (newer) +// main thread frameState and the (older) worker frameState +function updateContainerTransform() { + if (workerFrameState) { + const viewState = mainThreadFrameState.viewState; + const renderedViewState = workerFrameState.viewState; + const center = viewState.center; + const resolution = viewState.resolution; + const rotation = viewState.rotation; + const renderedCenter = renderedViewState.center; + const renderedResolution = renderedViewState.resolution; + const renderedRotation = renderedViewState.rotation; + const transform = create(); + // Skip the extra transform for rotated views, because it will not work + // correctly in that case + if (!rotation) { + compose( + transform, + (renderedCenter[0] - center[0]) / resolution, + (center[1] - renderedCenter[1]) / resolution, + renderedResolution / resolution, + renderedResolution / resolution, + rotation - renderedRotation, + 0, + 0 + ); + } + transformContainer.style.transform = createTransformString(transform); + } +} + +const map = new Map({ + layers: [ + new Layer({ + render: function (frameState) { + if (!container) { + container = document.createElement('div'); + container.style.position = 'absolute'; + container.style.width = '100%'; + container.style.height = '100%'; + transformContainer = document.createElement('div'); + transformContainer.style.position = 'absolute'; + transformContainer.style.width = '100%'; + transformContainer.style.height = '100%'; + container.appendChild(transformContainer); + canvas = document.createElement('canvas'); + canvas.style.position = 'absolute'; + canvas.style.left = '0'; + canvas.style.transformOrigin = 'top left'; + transformContainer.appendChild(canvas); + } + mainThreadFrameState = frameState; + updateContainerTransform(); + if (!rendering) { + rendering = true; + worker.postMessage({ + action: 'render', + frameState: JSON.parse(stringify(frameState)), + }); + } else { + frameState.animate = true; + } + return container; + }, + source: new Source({ + attributions: [ + '© MapTiler', + '© OpenStreetMap contributors', + ], + }), + }), + ], + target: 'map', + view: new View({ + resolutions: createXYZ({tileSize: 512}).getResolutions89, + center: [0, 0], + zoom: 2, + }), +}); +map.addControl(new FullScreen()); + +// Worker messaging and actions +worker.addEventListener('message', (message) => { + if (message.data.action === 'loadImage') { + // Image loader for ol-mapbox-style + const image = new Image(); + image.crossOrigin = 'anonymous'; + image.addEventListener('load', function () { + createImageBitmap(image, 0, 0, image.width, image.height).then( + (imageBitmap) => { + worker.postMessage( + { + action: 'imageLoaded', + image: imageBitmap, + src: message.data.src, + }, + [imageBitmap] + ); + } + ); + }); + image.src = event.data.src; + } else if (message.data.action === 'requestRender') { + // Worker requested a new render frame + map.render(); + } else if (canvas && message.data.action === 'rendered') { + // Worker provies a new render frame + requestAnimationFrame(function () { + const imageData = message.data.imageData; + canvas.width = imageData.width; + canvas.height = imageData.height; + canvas.getContext('2d').drawImage(imageData, 0, 0); + canvas.style.transform = message.data.transform; + workerFrameState = message.data.frameState; + updateContainerTransform(); + }); + rendering = false; + } +}); diff --git a/examples/offscreen-canvas.worker.js b/examples/offscreen-canvas.worker.js new file mode 100644 index 0000000000..ce33a656c5 --- /dev/null +++ b/examples/offscreen-canvas.worker.js @@ -0,0 +1,163 @@ +import MVT from '../src/ol/format/MVT.js'; +import TileQueue from '../src/ol/TileQueue.js'; +import VectorTileLayer from '../src/ol/layer/VectorTile.js'; +import VectorTileSource from '../src/ol/source/VectorTile.js'; +import stringify from 'json-stringify-safe'; +import styleFunction from 'ol-mapbox-style/dist/stylefunction.js'; +import {Projection} from '../src/ol/proj.js'; +import {inView} from '../src/ol/layer/Layer.js'; +import {renderDeclutterItems} from '../src/ol/render.js'; +import {getTilePriority as tilePriorityFunction} from '../src/ol/TileQueue.js'; + +/** @type {any} */ +const worker = self; + +let frameState, pixelRatio, rendererTransform; +const canvas = new OffscreenCanvas(1, 1); +// OffscreenCanvas does not have a style, so we mock it +canvas.style = {}; +const context = canvas.getContext('2d'); + +const sources = { + landcover: new VectorTileSource({ + maxZoom: 9, + format: new MVT(), + url: + 'https://api.maptiler.com/tiles/landcover/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB', + }), + contours: new VectorTileSource({ + minZoom: 9, + maxZoom: 14, + format: new MVT(), + url: + 'https://api.maptiler.com/tiles/contours/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB', + }), + openmaptiles: new VectorTileSource({ + format: new MVT(), + maxZoom: 14, + url: + 'https://api.maptiler.com/tiles/v3/{z}/{x}/{y}.pbf?key=get_your_own_D6rA4zTHduk6KOKTXzGB', + }), +}; +const layers = []; + +// Font replacement so we do not need to load web fonts in the worker +function getFont(font) { + return font[0].replace('Noto Sans', 'serif').replace('Roboto', 'sans-serif'); +} + +function loadStyles() { + const styleUrl = + 'https://api.maptiler.com/maps/topo/style.json?key=get_your_own_D6rA4zTHduk6KOKTXzGB'; + + fetch(styleUrl) + .then((data) => data.json()) + .then((styleJson) => { + const buckets = []; + let currentSource; + styleJson.layers.forEach((layer) => { + if (!layer.source) { + return; + } + if (currentSource !== layer.source) { + currentSource = layer.source; + buckets.push({ + source: layer.source, + layers: [], + }); + } + buckets[buckets.length - 1].layers.push(layer.id); + }); + + const spriteUrl = + styleJson.sprite + (pixelRatio > 1 ? '@2x' : '') + '.json'; + const spriteImageUrl = + styleJson.sprite + (pixelRatio > 1 ? '@2x' : '') + '.png'; + fetch(spriteUrl) + .then((data) => data.json()) + .then((spriteJson) => { + buckets.forEach((bucket) => { + const source = sources[bucket.source]; + if (!source) { + return; + } + const layer = new VectorTileLayer({ + declutter: true, + source, + minZoom: source.getTileGrid().getMinZoom(), + }); + layer.getRenderer().useContainer = function (target, transform) { + this.containerReused = this.getLayer() !== layers[0]; + this.canvas = canvas; + this.context = context; + this.container = { + firstElementChild: canvas, + }; + rendererTransform = transform; + }; + styleFunction( + layer, + styleJson, + bucket.layers, + undefined, + spriteJson, + spriteImageUrl, + getFont + ); + layers.push(layer); + }); + worker.postMessage({action: 'requestRender'}); + }); + }); +} + +// Minimal map-like functionality for rendering + +const tileQueue = new TileQueue( + (tile, tileSourceKey, tileCenter, tileResolution) => + tilePriorityFunction( + frameState, + tile, + tileSourceKey, + tileCenter, + tileResolution + ), + () => worker.postMessage({action: 'requestRender'}) +); + +const maxTotalLoading = 8; +const maxNewLoads = 2; + +worker.addEventListener('message', (event) => { + if (event.data.action !== 'render') { + return; + } + frameState = event.data.frameState; + if (!pixelRatio) { + pixelRatio = frameState.pixelRatio; + loadStyles(); + } + frameState.tileQueue = tileQueue; + frameState.viewState.projection.__proto__ = Projection.prototype; + layers.forEach((layer) => { + if (inView(layer.getLayerState(), frameState.viewState)) { + const renderer = layer.getRenderer(); + renderer.renderFrame(frameState, canvas); + } + }); + renderDeclutterItems(frameState, null); + if (tileQueue.getTilesLoading() < maxTotalLoading) { + tileQueue.reprioritize(); + tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); + } + const imageData = canvas.transferToImageBitmap(); + worker.postMessage( + { + action: 'rendered', + imageData: imageData, + transform: rendererTransform, + frameState: JSON.parse(stringify(frameState)), + }, + [imageData] + ); +}); diff --git a/examples/osm-vector-tiles.js b/examples/osm-vector-tiles.js index e7211986fd..5ca899ddc3 100644 --- a/examples/osm-vector-tiles.js +++ b/examples/osm-vector-tiles.js @@ -1,10 +1,10 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TopoJSON from '../src/ol/format/TopoJSON.js'; import VectorTileLayer from '../src/ol/layer/VectorTile.js'; -import {fromLonLat} from '../src/ol/proj.js'; import VectorTileSource from '../src/ol/source/VectorTile.js'; +import View from '../src/ol/View.js'; import {Fill, Stroke, Style} from '../src/ol/style.js'; +import {fromLonLat} from '../src/ol/proj.js'; const key = 'uZNs91nMR-muUTP99MyBSg'; @@ -12,24 +12,24 @@ const roadStyleCache = {}; const roadColor = { 'major_road': '#776', 'minor_road': '#ccb', - 'highway': '#f39' + 'highway': '#f39', }; const buildingStyle = new Style({ fill: new Fill({ color: '#666', - opacity: 0.4 + opacity: 0.4, }), stroke: new Stroke({ color: '#444', - width: 1 - }) + width: 1, + }), }); const waterStyle = new Style({ fill: new Fill({ - color: '#9db9e8' - }) + color: '#9db9e8', + }), }); -const roadStyle = function(feature) { +const roadStyle = function (feature) { const kind = feature.get('kind'); const railway = feature.get('railway'); const sort_key = feature.get('sort_key'); @@ -47,9 +47,9 @@ const roadStyle = function(feature) { style = new Style({ stroke: new Stroke({ color: color, - width: width + width: width, }), - zIndex: sort_key + zIndex: sort_key, }); roadStyleCache[styleKey] = style; } @@ -60,29 +60,36 @@ const map = new Map({ layers: [ new VectorTileLayer({ source: new VectorTileSource({ - attributions: '© OpenStreetMap contributors, Who’s On First, ' + - 'Natural Earth, and openstreetmapdata.com', + attributions: + '© OpenStreetMap contributors, Who’s On First, ' + + 'Natural Earth, and openstreetmapdata.com', format: new TopoJSON({ layerName: 'layer', - layers: ['water', 'roads', 'buildings'] + layers: ['water', 'roads', 'buildings'], }), maxZoom: 19, - url: 'https://tile.nextzen.org/tilezen/vector/v1/all/{z}/{x}/{y}.topojson?api_key=' + key + url: + 'https://tile.nextzen.org/tilezen/vector/v1/all/{z}/{x}/{y}.topojson?api_key=' + + key, }), - style: function(feature, resolution) { + style: function (feature, resolution) { switch (feature.get('layer')) { - case 'water': return waterStyle; - case 'roads': return roadStyle(feature); - case 'buildings': return (resolution < 10) ? buildingStyle : null; - default: return null; + case 'water': + return waterStyle; + case 'roads': + return roadStyle(feature); + case 'buildings': + return resolution < 10 ? buildingStyle : null; + default: + return null; } - } - }) + }, + }), ], target: 'map', view: new View({ center: fromLonLat([-74.0064, 40.7142]), maxZoom: 19, - zoom: 15 - }) + zoom: 15, + }), }); diff --git a/examples/overlay.css b/examples/overlay.css index 7b813f5ba9..a617a00d00 100644 --- a/examples/overlay.css +++ b/examples/overlay.css @@ -13,6 +13,6 @@ font-weight: bold; text-shadow: black 0.1em 0.1em 0.2em; } -.popover-content { - min-width: 180px; +.popover-body { + min-width: 276px; } diff --git a/examples/overlay.html b/examples/overlay.html index ea6bab8e99..73a2596af8 100644 --- a/examples/overlay.html +++ b/examples/overlay.html @@ -3,12 +3,12 @@ layout: example.html title: Overlay shortdesc: Demonstrates overlays. docs: > -The popups are created using Popovers from Bootstrap.
+The popups are created using Popovers from Bootstrap.
tags: "overlay, popup, bootstrap, popover" resources: - - https://code.jquery.com/jquery-2.2.3.min.js - - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css - - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js + - https://code.jquery.com/jquery-3.5.1.min.js + - https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css + - https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js ---diff --git a/examples/overlay.js b/examples/overlay.js index be9a65040d..7e8282da21 100644 --- a/examples/overlay.js +++ b/examples/overlay.js @@ -1,14 +1,13 @@ import Map from '../src/ol/Map.js'; -import Overlay from '../src/ol/Overlay.js'; -import View from '../src/ol/View.js'; -import {toStringHDMS} from '../src/ol/coordinate.js'; -import TileLayer from '../src/ol/layer/Tile.js'; -import {fromLonLat, toLonLat} from '../src/ol/proj.js'; import OSM from '../src/ol/source/OSM.js'; - +import Overlay from '../src/ol/Overlay.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {fromLonLat, toLonLat} from '../src/ol/proj.js'; +import {toStringHDMS} from '../src/ol/coordinate.js'; const layer = new TileLayer({ - source: new OSM() + source: new OSM(), }); const map = new Map({ @@ -16,8 +15,8 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); const pos = fromLonLat([16.3725, 48.208889]); @@ -27,35 +26,36 @@ const marker = new Overlay({ position: pos, positioning: 'center-center', element: document.getElementById('marker'), - stopEvent: false + stopEvent: false, }); map.addOverlay(marker); // Vienna label const vienna = new Overlay({ position: pos, - element: document.getElementById('vienna') + element: document.getElementById('vienna'), }); map.addOverlay(vienna); // Popup showing the position the user clicked const popup = new Overlay({ - element: document.getElementById('popup') + element: document.getElementById('popup'), }); map.addOverlay(popup); -map.on('click', function(evt) { +map.on('click', function (evt) { const element = popup.getElement(); const coordinate = evt.coordinate; const hdms = toStringHDMS(toLonLat(coordinate)); - $(element).popover('destroy'); + $(element).popover('dispose'); popup.setPosition(coordinate); $(element).popover({ + container: element, placement: 'top', animation: false, html: true, - content: '' + ); } /** @@ -406,28 +461,31 @@ class ScaleLine extends Control { * @return {number} The appropriate scale. */ getScaleForResolution() { - const resolution = this.getMap().getView().getResolution(); - const dpi = 25.4 / 0.28; + const resolution = getPointResolution( + this.viewState_.projection, + this.viewState_.resolution, + this.viewState_.center + ); + const dpi = this.dpi_ || DEFAULT_DPI; const mpu = this.viewState_.projection.getMetersPerUnit(); const inchesPerMeter = 39.37; return parseFloat(resolution.toString()) * mpu * inchesPerMeter * dpi; } -} -/** - * Update the scale line element. - * @param {import("../MapEvent.js").default} mapEvent Map event. - * @this {ScaleLine} - */ -export function render(mapEvent) { - const frameState = mapEvent.frameState; - if (!frameState) { - this.viewState_ = null; - } else { - this.viewState_ = frameState.viewState; + /** + * Update the scale line element. + * @param {import("../MapEvent.js").default} mapEvent Map event. + * @override + */ + render(mapEvent) { + const frameState = mapEvent.frameState; + if (!frameState) { + this.viewState_ = null; + } else { + this.viewState_ = frameState.viewState; + } + this.updateElement_(); } - this.updateElement_(); } - export default ScaleLine; diff --git a/src/ol/control/Zoom.js b/src/ol/control/Zoom.js index 0dbed9bf39..b2ac5dae04 100644 --- a/src/ol/control/Zoom.js +++ b/src/ol/control/Zoom.js @@ -1,12 +1,11 @@ /** * @module ol/control/Zoom */ -import EventType from '../events/EventType.js'; import Control from './Control.js'; +import EventType from '../events/EventType.js'; import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js'; import {easeOut} from '../easing.js'; - /** * @typedef {Object} Options * @property {number} [duration=250] Animation duration in milliseconds. @@ -22,7 +21,6 @@ import {easeOut} from '../easing.js'; * rendered outside of the map's viewport. */ - /** * @classdesc * A control with 2 buttons, one for zoom in and one for zoom out. @@ -32,52 +30,68 @@ import {easeOut} from '../easing.js'; * @api */ class Zoom extends Control { - /** * @param {Options=} opt_options Zoom options. */ constructor(opt_options) { - const options = opt_options ? opt_options : {}; super({ element: document.createElement('div'), - target: options.target + target: options.target, }); - const className = options.className !== undefined ? options.className : 'ol-zoom'; + const className = + options.className !== undefined ? options.className : 'ol-zoom'; const delta = options.delta !== undefined ? options.delta : 1; - const zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+'; - const zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212'; + const zoomInLabel = + options.zoomInLabel !== undefined ? options.zoomInLabel : '+'; + const zoomOutLabel = + options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212'; - const zoomInTipLabel = options.zoomInTipLabel !== undefined ? - options.zoomInTipLabel : 'Zoom in'; - const zoomOutTipLabel = options.zoomOutTipLabel !== undefined ? - options.zoomOutTipLabel : 'Zoom out'; + const zoomInTipLabel = + options.zoomInTipLabel !== undefined ? options.zoomInTipLabel : 'Zoom in'; + const zoomOutTipLabel = + options.zoomOutTipLabel !== undefined + ? options.zoomOutTipLabel + : 'Zoom out'; const inElement = document.createElement('button'); inElement.className = className + '-in'; inElement.setAttribute('type', 'button'); inElement.title = zoomInTipLabel; inElement.appendChild( - typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel + typeof zoomInLabel === 'string' + ? document.createTextNode(zoomInLabel) + : zoomInLabel ); - inElement.addEventListener(EventType.CLICK, this.handleClick_.bind(this, delta), false); + inElement.addEventListener( + EventType.CLICK, + this.handleClick_.bind(this, delta), + false + ); const outElement = document.createElement('button'); outElement.className = className + '-out'; outElement.setAttribute('type', 'button'); outElement.title = zoomOutTipLabel; outElement.appendChild( - typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel + typeof zoomOutLabel === 'string' + ? document.createTextNode(zoomOutLabel) + : zoomOutLabel ); - outElement.addEventListener(EventType.CLICK, this.handleClick_.bind(this, -delta), false); + outElement.addEventListener( + EventType.CLICK, + this.handleClick_.bind(this, -delta), + false + ); - const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; + const cssClasses = + className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; const element = this.element; element.className = cssClasses; element.appendChild(inElement); @@ -88,7 +102,6 @@ class Zoom extends Control { * @private */ this.duration_ = options.duration !== undefined ? options.duration : 250; - } /** @@ -123,7 +136,7 @@ class Zoom extends Control { view.animate({ zoom: newZoom, duration: this.duration_, - easing: easeOut + easing: easeOut, }); } else { view.setZoom(newZoom); @@ -132,5 +145,4 @@ class Zoom extends Control { } } - export default Zoom; diff --git a/src/ol/control/ZoomSlider.js b/src/ol/control/ZoomSlider.js index 58f2229d40..0387f0bfc3 100644 --- a/src/ol/control/ZoomSlider.js +++ b/src/ol/control/ZoomSlider.js @@ -2,16 +2,14 @@ * @module ol/control/ZoomSlider */ -import 'elm-pep'; import Control from './Control.js'; +import EventType from '../events/EventType.js'; +import PointerEventType from '../pointer/EventType.js'; import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js'; +import {clamp} from '../math.js'; import {easeOut} from '../easing.js'; import {listen, unlistenByKey} from '../events.js'; import {stopPropagation} from '../events/Event.js'; -import EventType from '../events/EventType.js'; -import {clamp} from '../math.js'; -import PointerEventType from '../pointer/EventType.js'; - /** * The enum for available directions. @@ -20,19 +18,17 @@ import PointerEventType from '../pointer/EventType.js'; */ const Direction = { VERTICAL: 0, - HORIZONTAL: 1 + HORIZONTAL: 1, }; - /** * @typedef {Object} Options * @property {string} [className='ol-zoomslider'] CSS class name. * @property {number} [duration=200] Animation duration in milliseconds. - * @property {function(import("../MapEvent.js").default)} [render] Function called when the control + * @property {function(import("../MapEvent.js").default):void} [render] Function called when the control * should be re-rendered. This is called in a `requestAnimationFrame` callback. */ - /** * @classdesc * A slider type of control for zooming. @@ -44,23 +40,21 @@ const Direction = { * @api */ class ZoomSlider extends Control { - /** * @param {Options=} opt_options Zoom slider options. */ constructor(opt_options) { - const options = opt_options ? opt_options : {}; super({ element: document.createElement('div'), - render: options.render || render + render: options.render, }); /** - * @type {!Array.The location you clicked was:
' + hdms + '' + content: 'The location you clicked was:
' + hdms + '', }); $(element).popover('show'); }); diff --git a/examples/overviewmap-custom.css b/examples/overviewmap-custom.css index 2b3e9a749e..82cc4e4f1f 100644 --- a/examples/overviewmap-custom.css +++ b/examples/overviewmap-custom.css @@ -1,36 +1,33 @@ -.mapcontainer { - position: relative; -} -div.ol-custom-overviewmap, -div.ol-custom-overviewmap.ol-uncollapsible { +.map .ol-custom-overviewmap, +.map .ol-custom-overviewmap.ol-uncollapsible { bottom: auto; left: auto; right: 0; top: 0; } -div.ol-custom-overviewmap:not(.ol-collapsed) { +.map .ol-custom-overviewmap:not(.ol-collapsed) { border: 1px solid black; } -div.ol-custom-overviewmap div.ol-overviewmap-map { +.map .ol-custom-overviewmap .ol-overviewmap-map { border: none; width: 300px; } -div.ol-custom-overviewmap div.ol-overviewmap-box { +.map .ol-custom-overviewmap .ol-overviewmap-box { border: 2px solid red; } -div.ol-custom-overviewmap:not(.ol-collapsed) button{ +.map .ol-custom-overviewmap:not(.ol-collapsed) button{ bottom: auto; left: auto; right: 1px; top: 1px; } -div.ol-rotate { +.map .ol-rotate { top: 170px; right: 0; } diff --git a/examples/overviewmap-custom.html b/examples/overviewmap-custom.html index 852b11366b..8b06bd2132 100644 --- a/examples/overviewmap-custom.html +++ b/examples/overviewmap-custom.html @@ -10,7 +10,5 @@ cloak: value: Your API key from http://www.thunderforest.com/docs/apikeys/ here --- -- -+Rotate with viewdiff --git a/examples/overviewmap-custom.js b/examples/overviewmap-custom.js index e82ff9ceb4..96844c83cc 100644 --- a/examples/overviewmap-custom.js +++ b/examples/overviewmap-custom.js @@ -1,10 +1,12 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, OverviewMap} from '../src/ol/control.js'; -import {defaults as defaultInteractions, DragRotateAndZoom} from '../src/ol/interaction.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import { + DragRotateAndZoom, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; +import {OverviewMap, defaults as defaultControls} from '../src/ol/control.js'; const rotateWithView = document.getElementById('rotateWithView'); @@ -14,35 +16,32 @@ const overviewMapControl = new OverviewMap({ layers: [ new TileLayer({ source: new OSM({ - 'url': 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + - '?apikey=0e6fc415256d4fbb9b5166a718591d71' - }) - }) + 'url': + 'https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png' + + '?apikey=0e6fc415256d4fbb9b5166a718591d71', + }), + }), ], collapseLabel: '\u00BB', label: '\u00AB', - collapsed: false + collapsed: false, }); -rotateWithView.addEventListener('change', function() { +rotateWithView.addEventListener('change', function () { overviewMapControl.setRotateWithView(this.checked); }); const map = new Map({ - controls: defaultControls().extend([ - overviewMapControl - ]), - interactions: defaultInteractions().extend([ - new DragRotateAndZoom() - ]), + controls: defaultControls().extend([overviewMapControl]), + interactions: defaultInteractions().extend([new DragRotateAndZoom()]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [500000, 6000000], - zoom: 7 - }) + zoom: 7, + }), }); diff --git a/examples/overviewmap.js b/examples/overviewmap.js index a740254a40..d468729bba 100644 --- a/examples/overviewmap.js +++ b/examples/overviewmap.js @@ -1,30 +1,28 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, OverviewMap} from '../src/ol/control.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {OverviewMap, defaults as defaultControls} from '../src/ol/control.js'; const source = new OSM(); const overviewMapControl = new OverviewMap({ layers: [ new TileLayer({ - source: source - }) - ] + source: source, + }), + ], }); const map = new Map({ - controls: defaultControls().extend([ - overviewMapControl - ]), + controls: defaultControls().extend([overviewMapControl]), layers: [ new TileLayer({ - source: source - }) + source: source, + }), ], target: 'map', view: new View({ center: [500000, 6000000], - zoom: 7 - }) + zoom: 7, + }), }); diff --git a/examples/page-scroll.js b/examples/page-scroll.js index e128b8e9ec..3c60ab0748 100644 --- a/examples/page-scroll.js +++ b/examples/page-scroll.js @@ -1,18 +1,17 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/permalink.js b/examples/permalink.js index c41d25846a..c62ee3e4f7 100644 --- a/examples/permalink.js +++ b/examples/permalink.js @@ -1,7 +1,7 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; // default zoom, center and rotation let zoom = 2; @@ -14,10 +14,7 @@ if (window.location.hash !== '') { const parts = hash.split('/'); if (parts.length === 4) { zoom = parseInt(parts[0], 10); - center = [ - parseFloat(parts[1]), - parseFloat(parts[2]) - ]; + center = [parseFloat(parts[1]), parseFloat(parts[2])]; rotation = parseFloat(parts[3]); } } @@ -25,20 +22,20 @@ if (window.location.hash !== '') { const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: center, zoom: zoom, - rotation: rotation - }) + rotation: rotation, + }), }); let shouldUpdate = true; const view = map.getView(); -const updatePermalink = function() { +const updatePermalink = function () { if (!shouldUpdate) { // do not update the URL when the view was changed in the 'popstate' handler shouldUpdate = true; @@ -46,15 +43,19 @@ const updatePermalink = function() { } const center = view.getCenter(); - const hash = '#map=' + - view.getZoom() + '/' + - Math.round(center[0] * 100) / 100 + '/' + - Math.round(center[1] * 100) / 100 + '/' + - view.getRotation(); + const hash = + '#map=' + + view.getZoom() + + '/' + + Math.round(center[0] * 100) / 100 + + '/' + + Math.round(center[1] * 100) / 100 + + '/' + + view.getRotation(); const state = { zoom: view.getZoom(), center: view.getCenter(), - rotation: view.getRotation() + rotation: view.getRotation(), }; window.history.pushState(state, 'map', hash); }; @@ -63,7 +64,7 @@ map.on('moveend', updatePermalink); // restore the view state when navigating through the history, see // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate -window.addEventListener('popstate', function(event) { +window.addEventListener('popstate', function (event) { if (event.state === null) { return; } diff --git a/examples/pinch-zoom.js b/examples/pinch-zoom.js index 0fba1794c9..0a750dc82f 100644 --- a/examples/pinch-zoom.js +++ b/examples/pinch-zoom.js @@ -1,23 +1,23 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultInteractions, PinchZoom} from '../src/ol/interaction.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import { + PinchZoom, + defaults as defaultInteractions, +} from '../src/ol/interaction.js'; const map = new Map({ - interactions: defaultInteractions().extend([ - new PinchZoom() - ]), + interactions: defaultInteractions().extend([new PinchZoom()]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], zoom: 2, - constrainResolution: true - }) + constrainResolution: true, + }), }); diff --git a/examples/polygon-styles.js b/examples/polygon-styles.js index 7f1a03e1c2..edc37b892f 100644 --- a/examples/polygon-styles.js +++ b/examples/polygon-styles.js @@ -1,9 +1,9 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; import MultiPoint from '../src/ol/geom/MultiPoint.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; const styles = [ @@ -17,25 +17,25 @@ const styles = [ new Style({ stroke: new Stroke({ color: 'blue', - width: 3 + width: 3, }), fill: new Fill({ - color: 'rgba(0, 0, 255, 0.1)' - }) + color: 'rgba(0, 0, 255, 0.1)', + }), }), new Style({ image: new CircleStyle({ radius: 5, fill: new Fill({ - color: 'orange' - }) + color: 'orange', + }), }), - geometry: function(feature) { + geometry: function (feature) { // return the coordinates of the first ring of the polygon const coordinates = feature.getGeometry().getCoordinates()[0]; return new MultiPoint(coordinates); - } - }) + }, + }), ]; const geojsonObject = { @@ -43,47 +43,79 @@ const geojsonObject = { 'crs': { 'type': 'name', 'properties': { - 'name': 'EPSG:3857' - } + 'name': 'EPSG:3857', + }, }, - 'features': [{ - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [[[-5e6, 6e6], [-5e6, 8e6], [-3e6, 8e6], - [-3e6, 6e6], [-5e6, 6e6]]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [[[-2e6, 6e6], [-2e6, 8e6], [0, 8e6], - [0, 6e6], [-2e6, 6e6]]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [[[1e6, 6e6], [1e6, 8e6], [3e6, 8e6], - [3e6, 6e6], [1e6, 6e6]]] - } - }, { - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [[[-2e6, -1e6], [-1e6, 1e6], - [0, -1e6], [-2e6, -1e6]]] - } - }] + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [ + [ + [-5e6, 6e6], + [-5e6, 8e6], + [-3e6, 8e6], + [-3e6, 6e6], + [-5e6, 6e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [ + [ + [-2e6, 6e6], + [-2e6, 8e6], + [0, 8e6], + [0, 6e6], + [-2e6, 6e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [ + [ + [1e6, 6e6], + [1e6, 8e6], + [3e6, 8e6], + [3e6, 6e6], + [1e6, 6e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [ + [ + [-2e6, -1e6], + [-1e6, 1e6], + [0, -1e6], + [-2e6, -1e6], + ], + ], + }, + }, + ], }; const source = new VectorSource({ - features: (new GeoJSON()).readFeatures(geojsonObject) + features: new GeoJSON().readFeatures(geojsonObject), }); const layer = new VectorLayer({ source: source, - style: styles + style: styles, }); const map = new Map({ @@ -91,6 +123,6 @@ const map = new Map({ target: 'map', view: new View({ center: [0, 3000000], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/popup.html b/examples/popup.html index f7496b7081..b2126f5e1a 100644 --- a/examples/popup.html +++ b/examples/popup.html @@ -8,8 +8,8 @@ docs: > tags: "overlay, popup" cloak: - - key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg - value: Your Mapbox access token from https://mapbox.com/ here + - key: get_your_own_D6rA4zTHduk6KOKTXzGB + value: Get your own API key at https://www.maptiler.com/cloud/ ---diff --git a/examples/popup.js b/examples/popup.js index bb50da8fed..56c789f6a1 100644 --- a/examples/popup.js +++ b/examples/popup.js @@ -1,12 +1,10 @@ import Map from '../src/ol/Map.js'; import Overlay from '../src/ol/Overlay.js'; -import View from '../src/ol/View.js'; -import {toStringHDMS} from '../src/ol/coordinate.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import XYZ from '../src/ol/source/XYZ.js'; import {toLonLat} from '../src/ol/proj.js'; -import TileJSON from '../src/ol/source/TileJSON.js'; - -const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg'; +import {toStringHDMS} from '../src/ol/coordinate.js'; /** * Elements that make up the popup. @@ -15,7 +13,6 @@ const container = document.getElementById('popup'); const content = document.getElementById('popup-content'); const closer = document.getElementById('popup-closer'); - /** * Create an overlay to anchor the popup to the map. */ @@ -23,21 +20,24 @@ const overlay = new Overlay({ element: container, autoPan: true, autoPanAnimation: { - duration: 250 - } + duration: 250, + }, }); - /** * Add a click handler to hide the popup. * @return {boolean} Don't follow the href. */ -closer.onclick = function() { +closer.onclick = function () { overlay.setPosition(undefined); closer.blur(); return false; }; +const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; +const attributions = + '© MapTiler ' + + '© OpenStreetMap contributors'; /** * Create the map. @@ -45,29 +45,28 @@ closer.onclick = function() { const map = new Map({ layers: [ new TileLayer({ - source: new TileJSON({ - url: 'https://api.tiles.mapbox.com/v4/mapbox.natural-earth-hypso-bathy.json?access_token=' + key, - crossOrigin: 'anonymous' - }) - }) + source: new XYZ({ + attributions: attributions, + url: 'https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=' + key, + tileSize: 512, + }), + }), ], overlays: [overlay], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); - /** * Add a click handler to the map to render the popup. */ -map.on('singleclick', function(evt) { +map.on('singleclick', function (evt) { const coordinate = evt.coordinate; const hdms = toStringHDMS(toLonLat(coordinate)); - content.innerHTML = 'diff --git a/examples/reprojection.js b/examples/reprojection.js index 0d4dd4d9a9..d6d2d77acf 100644 --- a/examples/reprojection.js +++ b/examples/reprojection.js @@ -1,44 +1,63 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {getWidth, getCenter} from '../src/ol/extent.js'; -import WMTSCapabilities from '../src/ol/format/WMTSCapabilities.js'; +import TileGrid from '../src/ol/tilegrid/TileGrid.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import WMTS, {optionsFromCapabilities} from '../src/ol/source/WMTS.js'; +import WMTSCapabilities from '../src/ol/format/WMTSCapabilities.js'; +import proj4 from 'proj4'; +import {OSM, TileImage, TileWMS} from '../src/ol/source.js'; +import {getCenter, getWidth} from '../src/ol/extent.js'; import {get as getProjection} from '../src/ol/proj.js'; import {register} from '../src/ol/proj/proj4.js'; -import {OSM, TileImage, TileWMS, XYZ} from '../src/ol/source.js'; -import WMTS, {optionsFromCapabilities} from '../src/ol/source/WMTS.js'; -import TileGrid from '../src/ol/tilegrid/TileGrid.js'; -import proj4 from 'proj4'; - -proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + +proj4.defs( + 'EPSG:27700', + '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + '+x_0=400000 +y_0=-100000 +ellps=airy ' + '+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' + - '+units=m +no_defs'); -proj4.defs('EPSG:23032', '+proj=utm +zone=32 +ellps=intl ' + - '+towgs84=-87,-98,-121,0,0,0,0 +units=m +no_defs'); -proj4.defs('EPSG:5479', '+proj=lcc +lat_1=-76.66666666666667 +lat_2=' + + '+units=m +no_defs' +); +proj4.defs( + 'EPSG:23032', + '+proj=utm +zone=32 +ellps=intl ' + + '+towgs84=-87,-98,-121,0,0,0,0 +units=m +no_defs' +); +proj4.defs( + 'EPSG:5479', + '+proj=lcc +lat_1=-76.66666666666667 +lat_2=' + '-79.33333333333333 +lat_0=-78 +lon_0=163 +x_0=7000000 +y_0=5000000 ' + - '+ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'); -proj4.defs('EPSG:21781', '+proj=somerc +lat_0=46.95240555555556 ' + + '+ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs' +); +proj4.defs( + 'EPSG:21781', + '+proj=somerc +lat_0=46.95240555555556 ' + '+lon_0=7.439583333333333 +k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' + - '+towgs84=674.4,15.1,405.3,0,0,0,0 +units=m +no_defs'); -proj4.defs('EPSG:3413', '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 ' + - '+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'); -proj4.defs('EPSG:2163', '+proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 ' + - '+a=6370997 +b=6370997 +units=m +no_defs'); -proj4.defs('ESRI:54009', '+proj=moll +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 ' + - '+units=m +no_defs'); + '+towgs84=674.4,15.1,405.3,0,0,0,0 +units=m +no_defs' +); +proj4.defs( + 'EPSG:3413', + '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 ' + + '+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs' +); +proj4.defs( + 'EPSG:2163', + '+proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 ' + + '+a=6370997 +b=6370997 +units=m +no_defs' +); +proj4.defs( + 'ESRI:54009', + '+proj=moll +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 ' + '+units=m +no_defs' +); register(proj4); const proj27700 = getProjection('EPSG:27700'); proj27700.setExtent([0, 0, 700000, 1300000]); const proj23032 = getProjection('EPSG:23032'); -proj23032.setExtent([-1206118.71, 4021309.92, 1295389.00, 8051813.28]); +proj23032.setExtent([-1206118.71, 4021309.92, 1295389.0, 8051813.28]); const proj5479 = getProjection('EPSG:5479'); -proj5479.setExtent([6825737.53, 4189159.80, 9633741.96, 5782472.71]); +proj5479.setExtent([6825737.53, 4189159.8, 9633741.96, 5782472.71]); const proj21781 = getProjection('EPSG:21781'); proj21781.setExtent([485071.54, 75346.36, 828515.78, 299941.84]); @@ -47,16 +66,15 @@ const proj3413 = getProjection('EPSG:3413'); proj3413.setExtent([-4194304, -4194304, 4194304, 4194304]); const proj2163 = getProjection('EPSG:2163'); -proj2163.setExtent([-8040784.5135, -2577524.9210, 3668901.4484, 4785105.1096]); +proj2163.setExtent([-8040784.5135, -2577524.921, 3668901.4484, 4785105.1096]); const proj54009 = getProjection('ESRI:54009'); proj54009.setExtent([-18e6, -9e6, 18e6, 9e6]); - const layers = {}; layers['osm'] = new TileLayer({ - source: new OSM() + source: new OSM(), }); layers['wms4326'] = new TileLayer({ @@ -65,74 +83,70 @@ layers['wms4326'] = new TileLayer({ crossOrigin: '', params: { 'LAYERS': 'ne:NE1_HR_LC_SR_W_DR', - 'TILED': true + 'TILED': true, }, - projection: 'EPSG:4326' - }) + projection: 'EPSG:4326', + }), }); layers['wms21781'] = new TileLayer({ source: new TileWMS({ - attributions: '© Pixelmap 1:1000000 / geo.admin.ch', crossOrigin: 'anonymous', params: { 'LAYERS': 'ch.swisstopo.pixelkarte-farbe-pk1000.noscale', - 'FORMAT': 'image/jpeg' + 'FORMAT': 'image/jpeg', }, url: 'https://wms.geo.admin.ch/', - projection: 'EPSG:21781' - }) + projection: 'EPSG:21781', + }), }); const parser = new WMTSCapabilities(); layers['wmts3413'] = new TileLayer(); -const urlA = 'https://map1.vis.earthdata.nasa.gov/wmts-arctic/' + - 'wmts.cgi?SERVICE=WMTS&request=GetCapabilities'; -fetch(urlA).then(function(response) { - return response.text(); -}).then(function(text) { - const result = parser.read(text); - const options = optionsFromCapabilities(result, { - layer: 'OSM_Land_Mask', - matrixSet: 'EPSG3413_250m' +const urlA = + 'https://map1.vis.earthdata.nasa.gov/wmts-arctic/' + + 'wmts.cgi?SERVICE=WMTS&request=GetCapabilities'; +fetch(urlA) + .then(function (response) { + return response.text(); + }) + .then(function (text) { + const result = parser.read(text); + const options = optionsFromCapabilities(result, { + layer: 'OSM_Land_Mask', + matrixSet: 'EPSG3413_250m', + }); + options.crossOrigin = ''; + options.projection = 'EPSG:3413'; + options.wrapX = false; + layers['wmts3413'].setSource(new WMTS(options)); }); - options.crossOrigin = ''; - options.projection = 'EPSG:3413'; - options.wrapX = false; - layers['wmts3413'].setSource(new WMTS(options)); -}); layers['bng'] = new TileLayer(); -const urlB = 'https://tiles.arcgis.com/tiles/qHLhLQrcvEnxjtPr/arcgis/rest/services/OS_Open_Raster/MapServer/WMTS'; -fetch(urlB).then(function(response) { - return response.text(); -}).then(function(text) { - const result = parser.read(text); - const options = optionsFromCapabilities(result, { - layer: 'OS_Open_Raster' - }); - options.attributions = 'Contains OS data © Crown Copyright and database right 2019'; - options.crossOrigin = ''; - options.projection = 'EPSG:27700'; - options.wrapX = false; - layers['bng'].setSource(new WMTS(options)); -}); - -layers['grandcanyon'] = new TileLayer({ - source: new XYZ({ - url: 'https://tileserver.maptiler.com/grandcanyon@2x/{z}/{x}/{y}.png', - crossOrigin: '', - tilePixelRatio: 2, - maxZoom: 15, - attributions: 'Tiles © USGS, rendered with ' + - 'MapTiler' +const urlB = + 'https://tiles.arcgis.com/tiles/qHLhLQrcvEnxjtPr/arcgis/rest/services/OS_Open_Raster/MapServer/WMTS'; +fetch(urlB) + .then(function (response) { + return response.text(); }) -}); + .then(function (text) { + const result = parser.read(text); + const options = optionsFromCapabilities(result, { + layer: 'OS_Open_Raster', + }); + options.attributions = + 'Contains OS data © Crown Copyright and database right 2019'; + options.crossOrigin = ''; + options.projection = 'EPSG:27700'; + options.wrapX = false; + layers['bng'].setSource(new WMTS(options)); + }); -const startResolution = - getWidth(getProjection('EPSG:3857').getExtent()) / 256; +const startResolution = getWidth(getProjection('EPSG:3857').getExtent()) / 256; const resolutions = new Array(22); for (let i = 0, ii = resolutions.length; i < ii; ++i) { resolutions[i] = startResolution / Math.pow(2, i); @@ -147,27 +161,22 @@ layers['states'] = new TileLayer({ tileGrid: new TileGrid({ extent: [-13884991, 2870341, -7455066, 6338219], resolutions: resolutions, - tileSize: [512, 256] + tileSize: [512, 256], }), - projection: 'EPSG:3857' - }) + projection: 'EPSG:3857', + }), }); - const map = new Map({ - layers: [ - layers['osm'], - layers['bng'] - ], + layers: [layers['osm'], layers['bng']], target: 'map', view: new View({ projection: 'EPSG:3857', center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); - const baseLayerSelect = document.getElementById('base-layer'); const overlayLayerSelect = document.getElementById('overlay-layer'); const viewProjSelect = document.getElementById('view-projection'); @@ -181,7 +190,7 @@ function updateViewProjection() { projection: newProj, center: getCenter(newProjExtent || [0, 0, 0, 0]), zoom: 0, - extent: newProjExtent || undefined + extent: newProjExtent || undefined, }); map.setView(newView); @@ -193,17 +202,16 @@ function updateViewProjection() { } } - /** * Handle change event. */ -viewProjSelect.onchange = function() { +viewProjSelect.onchange = function () { updateViewProjection(); }; updateViewProjection(); -const updateRenderEdgesOnLayer = function(layer) { +const updateRenderEdgesOnLayer = function (layer) { if (layer instanceof TileLayer) { const source = layer.getSource(); if (source instanceof TileImage) { @@ -212,11 +220,10 @@ const updateRenderEdgesOnLayer = function(layer) { } }; - /** * Handle change event. */ -baseLayerSelect.onchange = function() { +baseLayerSelect.onchange = function () { const layer = layers[baseLayerSelect.value]; if (layer) { layer.setOpacity(1); @@ -225,11 +232,10 @@ baseLayerSelect.onchange = function() { } }; - /** * Handle change event. */ -overlayLayerSelect.onchange = function() { +overlayLayerSelect.onchange = function () { const layer = layers[overlayLayerSelect.value]; if (layer) { layer.setOpacity(0.7); @@ -238,13 +244,12 @@ overlayLayerSelect.onchange = function() { } }; - /** * Handle change event. */ -renderEdgesCheckbox.onchange = function() { +renderEdgesCheckbox.onchange = function () { renderEdges = renderEdgesCheckbox.checked; - map.getLayers().forEach(function(layer) { + map.getLayers().forEach(function (layer) { updateRenderEdgesOnLayer(layer); }); }; diff --git a/examples/resources/common.js b/examples/resources/common.js index 893fe51c1a..62ed888dd7 100644 --- a/examples/resources/common.js +++ b/examples/resources/common.js @@ -57,6 +57,8 @@ event.preventDefault(); const html = document.getElementById('example-html-source').innerText; const js = document.getElementById('example-js-source').innerText; + const workerContainer = document.getElementById('example-worker-source'); + const worker = workerContainer ? workerContainer.innerText : undefined; const pkgJson = document.getElementById('example-pkg-source').innerText; const form = document.getElementById('codepen-form'); @@ -68,22 +70,28 @@ Promise.all(promises) .then(results => { - const data = { - files: { - 'index.html': { - content: html - }, - 'index.js': { - content: js - }, - "package.json": { - content: pkgJson - }, - 'sandbox.config.json': { - content: '{"template": "parcel"}' - } + const files = { + 'index.html': { + content: html + }, + 'main.js': { + content: js + }, + "package.json": { + content: pkgJson + }, + 'sandbox.config.json': { + content: '{"template": "parcel"}' } }; + if (worker) { + files['worker.js'] = { + content: worker + } + } + const data = { + files: files + }; for (let i = 0; i < localResources.length; i++) { data.files[localResources[i]] = results[i]; diff --git a/examples/resources/layout.css b/examples/resources/layout.css index 9fa3d8d461..4913023f77 100644 --- a/examples/resources/layout.css +++ b/examples/resources/layout.css @@ -35,6 +35,23 @@ body { .display-table { display: table; } +a { + color: #03899c; + text-decoration:none +} +a:hover, a:focus, footer a:hover, footer a:focus { + color: #ff7a00; + text-decoration:none +} +.btn-link { + font-weight: 400; + color: #03899c; + text-decoration: none; +} +.btn-link:hover { + color: #ff7a00; + text-decoration: none; +} .version-form, .navbar-form { display: table-cell; vertical-align: middle; diff --git a/examples/resources/mapbox-streets-v6-style.js b/examples/resources/mapbox-streets-v6-style.js index abd5babca3..afc1d8605d 100644 --- a/examples/resources/mapbox-streets-v6-style.js +++ b/examples/resources/mapbox-streets-v6-style.js @@ -309,4 +309,4 @@ function createMapboxStreetsV6Style(Style, Fill, Stroke, Icon, Text) { styles.length = length; return styles; }; -} +} \ No newline at end of file diff --git a/examples/reusable-source.js b/examples/reusable-source.js index 862ee919f9..516c4d268b 100644 --- a/examples/reusable-source.js +++ b/examples/reusable-source.js @@ -1,15 +1,20 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; import XYZ from '../src/ol/source/XYZ.js'; -const key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; +const key = + 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiY2pzbmg0Nmk5MGF5NzQzbzRnbDNoeHJrbiJ9.7_-_gL8ur7ZtEiNwRfCy7Q'; const baseUrl = 'https://{a-c}.tiles.mapbox.com/v4'; const urls = [ baseUrl + '/mapbox.blue-marble-topo-jan/{z}/{x}/{y}.png?access_token=' + key, - baseUrl + '/mapbox.blue-marble-topo-bathy-jan/{z}/{x}/{y}.png?access_token=' + key, + baseUrl + + '/mapbox.blue-marble-topo-bathy-jan/{z}/{x}/{y}.png?access_token=' + + key, baseUrl + '/mapbox.blue-marble-topo-jul/{z}/{x}/{y}.png?access_token=' + key, - baseUrl + '/mapbox.blue-marble-topo-bathy-jul/{z}/{x}/{y}.png?access_token=' + key + baseUrl + + '/mapbox.blue-marble-topo-bathy-jul/{z}/{x}/{y}.png?access_token=' + + key, ]; const source = new XYZ(); @@ -18,16 +23,15 @@ const map = new Map({ target: 'map', layers: [ new TileLayer({ - source: source - }) + source: source, + }), ], view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); - function updateUrl(index) { source.setUrl(urls[index]); } diff --git a/examples/rotation.js b/examples/rotation.js index 4a1d8b6956..8ca856222a 100644 --- a/examples/rotation.js +++ b/examples/rotation.js @@ -1,19 +1,18 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; - +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [14200000, 4130000], rotation: Math.PI / 6, - zoom: 10 - }) + zoom: 10, + }), }); diff --git a/examples/scale-line.js b/examples/scale-line.js index 0fad817b12..d961b13d41 100644 --- a/examples/scale-line.js +++ b/examples/scale-line.js @@ -1,8 +1,8 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {defaults as defaultControls, ScaleLine} from '../src/ol/control.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {ScaleLine, defaults as defaultControls} from '../src/ol/control.js'; const unitsSelect = document.getElementById('units'); const typeSelect = document.getElementById('type'); @@ -18,7 +18,7 @@ let control; function scaleControl() { if (scaleType === 'scaleline') { control = new ScaleLine({ - units: unitsSelect.value + units: unitsSelect.value, }); return control; } @@ -27,24 +27,22 @@ function scaleControl() { bar: true, steps: scaleBarSteps, text: scaleBarText, - minWidth: 140 + minWidth: 140, }); return control; } const map = new Map({ - controls: defaultControls().extend([ - scaleControl() - ]), + controls: defaultControls().extend([scaleControl()]), layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); function onChange() { diff --git a/examples/scaleline-indiana-east.js b/examples/scaleline-indiana-east.js index b0c2aa3f07..af5173e0f7 100644 --- a/examples/scaleline-indiana-east.js +++ b/examples/scaleline-indiana-east.js @@ -1,13 +1,15 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {ScaleLine} from '../src/ol/control.js'; +import OSM from '../src/ol/source/OSM.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import proj4 from 'proj4'; +import {ScaleLine} from '../src/ol/control.js'; import {fromLonLat, transformExtent} from '../src/ol/proj.js'; import {register} from '../src/ol/proj/proj4.js'; -import OSM from '../src/ol/source/OSM.js'; -import proj4 from 'proj4'; -proj4.defs('Indiana-East', 'PROJCS["IN83-EF",GEOGCS["LL83",DATUM["NAD83",' + +proj4.defs( + 'Indiana-East', + 'PROJCS["IN83-EF",GEOGCS["LL83",DATUM["NAD83",' + 'SPHEROID["GRS1980",6378137.000,298.25722210]],PRIMEM["Greenwich",0],' + 'UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],' + 'PARAMETER["false_easting",328083.333],' + @@ -15,24 +17,28 @@ proj4.defs('Indiana-East', 'PROJCS["IN83-EF",GEOGCS["LL83",DATUM["NAD83",' + 'PARAMETER["scale_factor",0.999966666667],' + 'PARAMETER["central_meridian",-85.66666666666670],' + 'PARAMETER["latitude_of_origin",37.50000000000000],' + - 'UNIT["Foot_US",0.30480060960122]]'); + 'UNIT["Foot_US",0.30480060960122]]' +); register(proj4); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ projection: 'Indiana-East', center: fromLonLat([-85.685, 39.891], 'Indiana-East'), zoom: 7, - extent: transformExtent([-172.54, 23.81, -47.74, 86.46], - 'EPSG:4326', 'Indiana-East'), - minZoom: 6 - }) + extent: transformExtent( + [-172.54, 23.81, -47.74, 86.46], + 'EPSG:4326', + 'Indiana-East' + ), + minZoom: 6, + }), }); map.addControl(new ScaleLine({units: 'us'})); diff --git a/examples/sea-level.css b/examples/sea-level.css index bee4df9bd6..124fc818e5 100644 --- a/examples/sea-level.css +++ b/examples/sea-level.css @@ -7,3 +7,7 @@ a.location { cursor: pointer; } + +#map { + background: #85ccf9; +} diff --git a/examples/sea-level.html b/examples/sea-level.html index 6861d69fec..147b6021f7 100644 --- a/examples/sea-level.html +++ b/examples/sea-level.html @@ -15,8 +15,8 @@ docs: > tags: "raster, pixel operation, flood" cloak: - - key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg - value: Your Mapbox access token from https://mapbox.com/ here + - key: get_your_own_D6rA4zTHduk6KOKTXzGB + value: Get your own API key at https://www.maptiler.com/cloud/ ---You clicked here:
' + hdms + - ''; + content.innerHTML = 'You clicked here:
' + hdms + ''; overlay.setPosition(coordinate); }); diff --git a/examples/preload.html b/examples/preload.html index 7398986e0b..193a6bd0ec 100644 --- a/examples/preload.html +++ b/examples/preload.html @@ -6,7 +6,7 @@ docs: >The map on the top preloads low resolution tiles. The map on the bottom does not use any preloading. Try zooming out and panning to see the difference.
tags: "preload, bing" cloak: - - key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5 + - key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp value: Your Bing Maps Key from http://www.bingmapsportal.com/ here --- diff --git a/examples/preload.js b/examples/preload.js index 5d15402941..2ca51436aa 100644 --- a/examples/preload.js +++ b/examples/preload.js @@ -1,12 +1,11 @@ -import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import BingMaps from '../src/ol/source/BingMaps.js'; - +import Map from '../src/ol/Map.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const view = new View({ center: [-4808600, -2620936], - zoom: 8 + zoom: 8, }); const map1 = new Map({ @@ -14,13 +13,13 @@ const map1 = new Map({ new TileLayer({ preload: Infinity, source: new BingMaps({ - key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5', - imagerySet: 'Aerial' - }) - }) + key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp', + imagerySet: 'Aerial', + }), + }), ], target: 'map1', - view: view + view: view, }); const map2 = new Map({ @@ -28,11 +27,11 @@ const map2 = new Map({ new TileLayer({ preload: 0, // default value source: new BingMaps({ - key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5', - imagerySet: 'AerialWithLabelsOnDemand' - }) - }) + key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp', + imagerySet: 'AerialWithLabelsOnDemand', + }), + }), ], target: 'map2', - view: view + view: view, }); diff --git a/examples/print-to-scale.css b/examples/print-to-scale.css new file mode 100644 index 0000000000..7911e178ab --- /dev/null +++ b/examples/print-to-scale.css @@ -0,0 +1,6 @@ +.wrapper { + max-width: 566px; + width: 100%; + height: 400px; + overflow: hidden; +} diff --git a/examples/print-to-scale.html b/examples/print-to-scale.html new file mode 100644 index 0000000000..54d88db427 --- /dev/null +++ b/examples/print-to-scale.html @@ -0,0 +1,47 @@ +--- +layout: example.html +title: Print to scale example +shortdesc: Example of printing a map to a specified scale. +docs: > + Example of printing a map to a specified scale. + The print is exported as a PDF using the jsPDF library. + Unlike the Export PDF example the on screen map is only used to set the center and rotation. + The extent printed depends on the scale and page size. To print the scale bar and attributions the example uses the + dom-to-image-more library. Due to browser + limitations and restrictions Internet Explorer and Safari are not supported. +tags: "print, printing, scale, scaleline, export, pdf" +resources: + - https://unpkg.com/dom-to-image-more@2.8.0/dist/dom-to-image-more.min.js + - https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js +--- ++ ++ + diff --git a/examples/print-to-scale.js b/examples/print-to-scale.js new file mode 100644 index 0000000000..75f702ec99 --- /dev/null +++ b/examples/print-to-scale.js @@ -0,0 +1,136 @@ +import Map from '../src/ol/Map.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import WMTS, {optionsFromCapabilities} from '../src/ol/source/WMTS.js'; +import WMTSCapabilities from '../src/ol/format/WMTSCapabilities.js'; +import proj4 from 'proj4'; +import {ScaleLine, defaults as defaultControls} from '../src/ol/control.js'; +import {getPointResolution, get as getProjection} from '../src/ol/proj.js'; +import {register} from '../src/ol/proj/proj4.js'; + +proj4.defs( + 'EPSG:27700', + '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + + '+x_0=400000 +y_0=-100000 +ellps=airy ' + + '+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' + + '+units=m +no_defs' +); + +register(proj4); + +const proj27700 = getProjection('EPSG:27700'); +proj27700.setExtent([0, 0, 700000, 1300000]); + +const raster = new TileLayer(); + +const url = + 'https://tiles.arcgis.com/tiles/qHLhLQrcvEnxjtPr/arcgis/rest/services/OS_Open_Raster/MapServer/WMTS'; +fetch(url) + .then(function (response) { + return response.text(); + }) + .then(function (text) { + const result = new WMTSCapabilities().read(text); + const options = optionsFromCapabilities(result, { + layer: 'OS_Open_Raster', + }); + options.attributions = + 'Contains OS data © Crown Copyright and database right ' + + new Date().getFullYear(); + options.crossOrigin = ''; + options.projection = proj27700; + options.wrapX = false; + raster.setSource(new WMTS(options)); + }); + +const map = new Map({ + layers: [raster], + controls: defaultControls({ + attributionOptions: {collapsible: false}, + }), + target: 'map', + view: new View({ + center: [373500, 436500], + projection: proj27700, + zoom: 7, + }), +}); + +const scaleLine = new ScaleLine({bar: true, text: true, minWidth: 125}); +map.addControl(scaleLine); + +const dims = { + a0: [1189, 841], + a1: [841, 594], + a2: [594, 420], + a3: [420, 297], + a4: [297, 210], + a5: [210, 148], +}; + +// export options for html-to-image. +// See: https://github.com/bubkoo/html-to-image#options +const exportOptions = { + filter: function (element) { + const className = element.className || ''; + return ( + className.indexOf('ol-control') === -1 || + className.indexOf('ol-scale') > -1 || + (className.indexOf('ol-attribution') > -1 && + className.indexOf('ol-uncollapsible')) + ); + }, +}; + +const exportButton = document.getElementById('export-pdf'); + +exportButton.addEventListener( + 'click', + function () { + exportButton.disabled = true; + document.body.style.cursor = 'progress'; + + const format = document.getElementById('format').value; + const resolution = document.getElementById('resolution').value; + const scale = document.getElementById('scale').value; + const dim = dims[format]; + const width = Math.round((dim[0] * resolution) / 25.4); + const height = Math.round((dim[1] * resolution) / 25.4); + const viewResolution = map.getView().getResolution(); + const scaleResolution = + scale / + getPointResolution( + map.getView().getProjection(), + resolution / 25.4, + map.getView().getCenter() + ); + + map.once('rendercomplete', function () { + exportOptions.width = width; + exportOptions.height = height; + domtoimage + .toJpeg(map.getViewport(), exportOptions) + .then(function (dataUrl) { + const pdf = new jsPDF('landscape', undefined, format); + pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]); + pdf.save('map.pdf'); + // Reset original map size + scaleLine.setDpi(); + map.getTargetElement().style.width = ''; + map.getTargetElement().style.height = ''; + map.updateSize(); + map.getView().setResolution(viewResolution); + exportButton.disabled = false; + document.body.style.cursor = 'auto'; + }); + }); + + // Set print size + scaleLine.setDpi(resolution); + map.getTargetElement().style.width = width + 'px'; + map.getTargetElement().style.height = height + 'px'; + map.updateSize(); + map.getView().setResolution(scaleResolution); + }, + false +); diff --git a/examples/raster.js b/examples/raster.js index b62bb8796d..2abdfd463a 100644 --- a/examples/raster.js +++ b/examples/raster.js @@ -1,14 +1,13 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; -import XYZ from '../src/ol/source/XYZ.js'; import RasterSource from '../src/ol/source/Raster.js'; +import View from '../src/ol/View.js'; +import XYZ from '../src/ol/source/XYZ.js'; +import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; const minVgi = 0; const maxVgi = 0.25; const bins = 10; - /** * Calculate the Vegetation Greenness Index (VGI) from an input pixel. This * is a rough estimate assuming that pixel values correspond to reflectance. @@ -22,7 +21,6 @@ function vgi(pixel) { return (2 * g - r - b) / (2 * g + r + b); } - /** * Summarize values for a histogram. * @param {numver} value A VGI value. @@ -42,23 +40,22 @@ function summarize(value, counts) { } } - /** * Use aerial imagery as the input data for the raster source. */ const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const aerial = new XYZ({ attributions: attributions, url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, maxZoom: 20, - crossOrigin: '' + crossOrigin: '', }); - /** * Create a raster source where pixels with VGI values above a threshold will * be colored green. @@ -71,7 +68,7 @@ const raster = new RasterSource({ * @param {Object} data User data object. * @return {Array} The output pixel. */ - operation: function(pixels, data) { + operation: function (pixels, data) { const pixel = pixels[0]; const value = vgi(pixel); summarize(value, data.counts); @@ -87,8 +84,8 @@ const raster = new RasterSource({ }, lib: { vgi: vgi, - summarize: summarize - } + summarize: summarize, + }, }); raster.set('threshold', 0.1); @@ -101,38 +98,37 @@ function createCounts(min, max, num) { min: min, max: max, values: values, - delta: (max - min) / num + delta: (max - min) / num, }; } -raster.on('beforeoperations', function(event) { +raster.on('beforeoperations', function (event) { event.data.counts = createCounts(minVgi, maxVgi, bins); event.data.threshold = raster.get('threshold'); }); -raster.on('afteroperations', function(event) { +raster.on('afteroperations', function (event) { schedulePlot(event.resolution, event.data.counts, event.data.threshold); }); const map = new Map({ layers: [ new TileLayer({ - source: aerial + source: aerial, }), new ImageLayer({ - source: raster - }) + source: raster, + }), ], target: 'map', view: new View({ center: [-9651695, 4937351], zoom: 13, minZoom: 12, - maxZoom: 19 - }) + maxZoom: 19, + }), }); - let timer = null; function schedulePlot(resolution, counts, threshold) { if (timer) { @@ -144,17 +140,19 @@ function schedulePlot(resolution, counts, threshold) { const barWidth = 15; const plotHeight = 150; -const chart = d3.select('#plot').append('svg') +const chart = d3 + .select('#plot') + .append('svg') .attr('width', barWidth * bins) .attr('height', plotHeight); const chartRect = chart.node().getBoundingClientRect(); -const tip = d3.select(document.body).append('div') - .attr('class', 'tip'); +const tip = d3.select(document.body).append('div').attr('class', 'tip'); function plot(resolution, counts, threshold) { - const yScale = d3.scaleLinear() + const yScale = d3 + .scaleLinear() .domain([0, d3.max(counts.values)]) .range([0, plotHeight]); @@ -162,49 +160,61 @@ function plot(resolution, counts, threshold) { bar.enter().append('rect'); - bar.attr('class', function(count, index) { - const value = counts.min + (index * counts.delta); - return 'bar' + (value >= threshold ? ' selected' : ''); - }) + bar + .attr('class', function (count, index) { + const value = counts.min + index * counts.delta; + return 'bar' + (value >= threshold ? ' selected' : ''); + }) .attr('width', barWidth - 2); - bar.transition().attr('transform', function(value, index) { - return 'translate(' + (index * barWidth) + ', ' + - (plotHeight - yScale(value)) + ')'; - }) + bar + .transition() + .attr('transform', function (value, index) { + return ( + 'translate(' + + index * barWidth + + ', ' + + (plotHeight - yScale(value)) + + ')' + ); + }) .attr('height', yScale); - bar.on('mousemove', function(count, index) { - const threshold = counts.min + (index * counts.delta); + bar.on('mousemove', function (count, index) { + const threshold = counts.min + index * counts.delta; if (raster.get('threshold') !== threshold) { raster.set('threshold', threshold); raster.changed(); } }); - bar.on('mouseover', function(count, index) { + bar.on('mouseover', function (count, index) { let area = 0; for (let i = counts.values.length - 1; i >= index; --i) { area += resolution * resolution * counts.values[i]; } - tip.html(message(counts.min + (index * counts.delta), area)); + tip.html(message(counts.min + index * counts.delta, area)); tip.style('display', 'block'); tip.transition().style({ - left: (chartRect.left + (index * barWidth) + (barWidth / 2)) + 'px', - top: (d3.event.y - 60) + 'px', - opacity: 1 + left: chartRect.left + index * barWidth + barWidth / 2 + 'px', + top: d3.event.y - 60 + 'px', + opacity: 1, }); }); - bar.on('mouseout', function() { - tip.transition().style('opacity', 0).each('end', function() { - tip.style('display', 'none'); - }); + bar.on('mouseout', function () { + tip + .transition() + .style('opacity', 0) + .each('end', function () { + tip.style('display', 'none'); + }); }); - } function message(value, area) { - const acres = (area / 4046.86).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ','); + const acres = (area / 4046.86) + .toFixed(0) + .replace(/\B(?=(\d{3})+(?!\d))/g, ','); return acres + ' acres at
' + value.toFixed(2) + ' VGI or above'; } diff --git a/examples/region-growing.js b/examples/region-growing.js index 9d0a9a3a26..c8e293b26e 100644 --- a/examples/region-growing.js +++ b/examples/region-growing.js @@ -1,9 +1,9 @@ import Map from '../src/ol/Map.js'; +import RasterSource from '../src/ol/source/Raster.js'; import View from '../src/ol/View.js'; +import XYZ from '../src/ol/source/XYZ.js'; import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; import {fromLonLat} from '../src/ol/proj.js'; -import XYZ from '../src/ol/source/XYZ.js'; -import RasterSource from '../src/ol/source/Raster.js'; function growRegion(inputs, data) { const image = inputs[0]; @@ -43,8 +43,11 @@ function growRegion(inputs, data) { if (ca === 0) { continue; } - if (Math.abs(seedR - cr) < delta && Math.abs(seedG - cg) < delta && - Math.abs(seedB - cb) < delta) { + if ( + Math.abs(seedR - cr) < delta && + Math.abs(seedG - cg) < delta && + Math.abs(seedB - cb) < delta + ) { outputData[ci] = 255; outputData[ci + 1] = 0; outputData[ci + 2] = 0; @@ -68,12 +71,13 @@ function next4Edges(edge) { [x + 1, y], [x - 1, y], [x, y + 1], - [x, y - 1] + [x, y - 1], ]; } const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB'; -const attributions = '© MapTiler ' + +const attributions = + '© MapTiler ' + '© OpenStreetMap contributors'; const imagery = new TileLayer({ @@ -81,8 +85,8 @@ const imagery = new TileLayer({ attributions: attributions, url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key, maxZoom: 20, - crossOrigin: '' - }) + crossOrigin: '', + }), }); const raster = new RasterSource({ @@ -92,13 +96,13 @@ const raster = new RasterSource({ // Functions in the `lib` object will be available to the operation run in // the web worker. lib: { - next4Edges: next4Edges - } + next4Edges: next4Edges, + }, }); const rasterImage = new ImageLayer({ opacity: 0.7, - source: raster + source: raster, }); const map = new Map({ @@ -106,20 +110,20 @@ const map = new Map({ target: 'map', view: new View({ center: fromLonLat([-119.07, 47.65]), - zoom: 11 - }) + zoom: 11, + }), }); let coordinate; -map.on('click', function(event) { +map.on('click', function (event) { coordinate = event.coordinate; raster.changed(); }); const thresholdControl = document.getElementById('threshold'); -raster.on('beforeoperations', function(event) { +raster.on('beforeoperations', function (event) { // the event.data object will be passed to operations const data = event.data; data.delta = thresholdControl.value; @@ -133,7 +137,7 @@ function updateControlValue() { } updateControlValue(); -thresholdControl.addEventListener('input', function() { +thresholdControl.addEventListener('input', function () { updateControlValue(); raster.changed(); }); diff --git a/examples/regularshape.js b/examples/regularshape.js index 0c194892d3..83eab335d1 100644 --- a/examples/regularshape.js +++ b/examples/regularshape.js @@ -1,12 +1,11 @@ import Feature from '../src/ol/Feature.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; import Point from '../src/ol/geom/Point.js'; import VectorLayer from '../src/ol/layer/Vector.js'; import VectorSource from '../src/ol/source/Vector.js'; +import View from '../src/ol/View.js'; import {Fill, RegularShape, Stroke, Style} from '../src/ol/style.js'; - const stroke = new Stroke({color: 'black', width: 2}); const fill = new Fill({color: 'red'}); @@ -17,8 +16,8 @@ const styles = { stroke: stroke, points: 4, radius: 10, - angle: Math.PI / 4 - }) + angle: Math.PI / 4, + }), }), 'triangle': new Style({ image: new RegularShape({ @@ -27,8 +26,8 @@ const styles = { points: 3, radius: 10, rotation: Math.PI / 4, - angle: 0 - }) + angle: 0, + }), }), 'star': new Style({ image: new RegularShape({ @@ -37,8 +36,8 @@ const styles = { points: 5, radius: 10, radius2: 4, - angle: 0 - }) + angle: 0, + }), }), 'cross': new Style({ image: new RegularShape({ @@ -47,8 +46,8 @@ const styles = { points: 4, radius: 10, radius2: 0, - angle: 0 - }) + angle: 0, + }), }), 'x': new Style({ image: new RegularShape({ @@ -57,8 +56,8 @@ const styles = { points: 4, radius: 10, radius2: 0, - angle: Math.PI / 4 - }) + angle: Math.PI / 4, + }), }), 'stacked': [ new Style({ @@ -68,8 +67,8 @@ const styles = { points: 4, radius: 5, angle: Math.PI / 4, - displacement: [0, 10] - }) + displacement: [0, 10], + }), }), new Style({ image: new RegularShape({ @@ -77,13 +76,12 @@ const styles = { stroke: stroke, points: 4, radius: 10, - angle: Math.PI / 4 - }) - }) - ] + angle: Math.PI / 4, + }), + }), + ], }; - const styleKeys = ['x', 'cross', 'star', 'triangle', 'square', 'stacked']; const count = 250; const features = new Array(count); @@ -95,20 +93,18 @@ for (let i = 0; i < count; ++i) { } const source = new VectorSource({ - features: features + features: features, }); const vectorLayer = new VectorLayer({ - source: source + source: source, }); const map = new Map({ - layers: [ - vectorLayer - ], + layers: [vectorLayer], target: 'map', view: new View({ center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/render-geometry.js b/examples/render-geometry.js index d3e1be366a..f21c4d9308 100644 --- a/examples/render-geometry.js +++ b/examples/render-geometry.js @@ -1,7 +1,6 @@ +import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; import {LineString, Point, Polygon} from '../src/ol/geom.js'; import {toContext} from '../src/ol/render.js'; -import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js'; - const canvas = document.getElementById('canvas'); const vectorContext = toContext(canvas.getContext('2d'), {size: [100, 100]}); @@ -14,11 +13,25 @@ const style = new Style({ image: new CircleStyle({ radius: 10, fill: fill, - stroke: stroke - }) + stroke: stroke, + }), }); vectorContext.setStyle(style); -vectorContext.drawGeometry(new LineString([[10, 10], [90, 90]])); -vectorContext.drawGeometry(new Polygon([[[2, 2], [98, 2], [2, 98], [2, 2]]])); +vectorContext.drawGeometry( + new LineString([ + [10, 10], + [90, 90], + ]) +); +vectorContext.drawGeometry( + new Polygon([ + [ + [2, 2], + [98, 2], + [2, 98], + [2, 2], + ], + ]) +); vectorContext.drawGeometry(new Point([88, 88])); diff --git a/examples/reprojection-by-code.html b/examples/reprojection-by-code.html index 319309832a..df386d4864 100644 --- a/examples/reprojection-by-code.html +++ b/examples/reprojection-by-code.html @@ -6,12 +6,12 @@ docs: > This example shows client-side raster reprojection capabilities from OSM (EPSG:3857) to arbitrary projection by searching in EPSG.io database. -tags: "reprojection, projection, proj4js, epsg.io" +tags: "reprojection, projection, proj4js, epsg.io, graticule" --- diff --git a/examples/reprojection-by-code.js b/examples/reprojection-by-code.js index 346cb3067a..2926a94486 100644 --- a/examples/reprojection-by-code.js +++ b/examples/reprojection-by-code.js @@ -1,42 +1,58 @@ +import Graticule from '../src/ol/layer/Graticule.js'; import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {applyTransform} from '../src/ol/extent.js'; +import OSM from '../src/ol/source/OSM.js'; +import Stroke from '../src/ol/style/Stroke.js'; +import TileImage from '../src/ol/source/TileImage.js'; import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import proj4 from 'proj4'; +import {applyTransform} from '../src/ol/extent.js'; import {get as getProjection, getTransform} from '../src/ol/proj.js'; import {register} from '../src/ol/proj/proj4.js'; -import OSM from '../src/ol/source/OSM.js'; -import TileImage from '../src/ol/source/TileImage.js'; -import proj4 from 'proj4'; +const graticule = new Graticule({ + // the style to use for the lines, optional. + strokeStyle: new Stroke({ + color: 'rgba(255,120,0,0.9)', + width: 2, + lineDash: [0.5, 4], + }), + showLabels: true, + visible: false, + wrapX: false, +}); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), + graticule, ], target: 'map', view: new View({ projection: 'EPSG:3857', center: [0, 0], - zoom: 1 - }) + zoom: 1, + }), }); - const queryInput = document.getElementById('epsg-query'); const searchButton = document.getElementById('epsg-search'); const resultSpan = document.getElementById('epsg-result'); const renderEdgesCheckbox = document.getElementById('render-edges'); +const showGraticuleCheckbox = document.getElementById('show-graticule'); function setProjection(code, name, proj4def, bbox) { if (code === null || name === null || proj4def === null || bbox === null) { resultSpan.innerHTML = 'Nothing usable found, using EPSG:3857...'; - map.setView(new View({ - projection: 'EPSG:3857', - center: [0, 0], - zoom: 1 - })); + map.setView( + new View({ + projection: 'EPSG:3857', + center: [0, 0], + zoom: 1, + }) + ); return; } @@ -48,60 +64,71 @@ function setProjection(code, name, proj4def, bbox) { const newProj = getProjection(newProjCode); const fromLonLat = getTransform('EPSG:4326', newProj); - // very approximate calculation of projection extent - const extent = applyTransform( - [bbox[1], bbox[2], bbox[3], bbox[0]], fromLonLat); + let worldExtent = [bbox[1], bbox[2], bbox[3], bbox[0]]; + newProj.setWorldExtent(worldExtent); + + // approximate calculation of projection extent, + // checking if the world extent crosses the dateline + if (bbox[1] > bbox[3]) { + worldExtent = [bbox[1], bbox[2], bbox[3] + 360, bbox[0]]; + } + const extent = applyTransform(worldExtent, fromLonLat, undefined, 8); newProj.setExtent(extent); const newView = new View({ - projection: newProj + projection: newProj, }); map.setView(newView); newView.fit(extent); } - function search(query) { resultSpan.innerHTML = 'Searching ...'; - fetch('https://epsg.io/?format=json&q=' + query).then(function(response) { - return response.json(); - }).then(function(json) { - const results = json['results']; - if (results && results.length > 0) { - for (let i = 0, ii = results.length; i < ii; i++) { - const result = results[i]; - if (result) { - const code = result['code']; - const name = result['name']; - const proj4def = result['proj4']; - const bbox = result['bbox']; - if (code && code.length > 0 && proj4def && proj4def.length > 0 && - bbox && bbox.length == 4) { - setProjection(code, name, proj4def, bbox); - return; + fetch('https://epsg.io/?format=json&q=' + query) + .then(function (response) { + return response.json(); + }) + .then(function (json) { + const results = json['results']; + if (results && results.length > 0) { + for (let i = 0, ii = results.length; i < ii; i++) { + const result = results[i]; + if (result) { + const code = result['code']; + const name = result['name']; + const proj4def = result['proj4']; + const bbox = result['bbox']; + if ( + code && + code.length > 0 && + proj4def && + proj4def.length > 0 && + bbox && + bbox.length == 4 + ) { + setProjection(code, name, proj4def, bbox); + return; + } } } } - } - setProjection(null, null, null, null); - }); + setProjection(null, null, null, null); + }); } - /** * Handle click event. * @param {Event} event The event. */ -searchButton.onclick = function(event) { +searchButton.onclick = function (event) { search(queryInput.value); event.preventDefault(); }; - /** - * Handle change event. + * Handle checkbox change event. */ -renderEdgesCheckbox.onchange = function() { - map.getLayers().forEach(function(layer) { +renderEdgesCheckbox.onchange = function () { + map.getLayers().forEach(function (layer) { if (layer instanceof TileLayer) { const source = layer.getSource(); if (source instanceof TileImage) { @@ -110,3 +137,10 @@ renderEdgesCheckbox.onchange = function() { } }); }; + +/** + * Handle checkbox change event. + */ +showGraticuleCheckbox.onchange = function () { + graticule.setVisible(showGraticuleCheckbox.checked); +}; diff --git a/examples/reprojection-image.html b/examples/reprojection-image.html index 6cd557afa4..5a3aa14249 100644 --- a/examples/reprojection-image.html +++ b/examples/reprojection-image.html @@ -7,3 +7,4 @@ docs: > tags: "reprojection, projection, proj4js, image, imagestatic" --- +Image smoothingdiff --git a/examples/reprojection-image.js b/examples/reprojection-image.js index 642ca466ee..24879205cd 100644 --- a/examples/reprojection-image.js +++ b/examples/reprojection-image.js @@ -1,39 +1,53 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import {getCenter} from '../src/ol/extent.js'; -import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; -import {transform} from '../src/ol/proj.js'; -import Static from '../src/ol/source/ImageStatic.js'; import OSM from '../src/ol/source/OSM.js'; -import {register} from '../src/ol/proj/proj4.js'; +import Static from '../src/ol/source/ImageStatic.js'; +import View from '../src/ol/View.js'; import proj4 from 'proj4'; +import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js'; +import {getCenter} from '../src/ol/extent.js'; +import {register} from '../src/ol/proj/proj4.js'; +import {transform} from '../src/ol/proj.js'; -proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + +proj4.defs( + 'EPSG:27700', + '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + '+x_0=400000 +y_0=-100000 +ellps=airy ' + '+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' + - '+units=m +no_defs'); + '+units=m +no_defs' +); register(proj4); const imageExtent = [0, 0, 700000, 1300000]; +const imageLayer = new ImageLayer(); const map = new Map({ layers: [ new TileLayer({ - source: new OSM() + source: new OSM(), }), - new ImageLayer({ - source: new Static({ - url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/' + - 'British_National_Grid.svg/2000px-British_National_Grid.svg.png', - crossOrigin: '', - projection: 'EPSG:27700', - imageExtent: imageExtent - }) - }) + imageLayer, ], target: 'map', view: new View({ center: transform(getCenter(imageExtent), 'EPSG:27700', 'EPSG:3857'), - zoom: 4 - }) + zoom: 4, + }), }); + +const imageSmoothing = document.getElementById('imageSmoothing'); + +function setSource() { + const source = new Static({ + url: + 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/' + + 'British_National_Grid.svg/2000px-British_National_Grid.svg.png', + crossOrigin: '', + projection: 'EPSG:27700', + imageExtent: imageExtent, + imageSmoothing: imageSmoothing.checked, + }); + imageLayer.setSource(source); +} +setSource(); + +imageSmoothing.addEventListener('change', setSource); diff --git a/examples/reprojection-wgs84.js b/examples/reprojection-wgs84.js index 0811ef85b3..e512bef6f8 100644 --- a/examples/reprojection-wgs84.js +++ b/examples/reprojection-wgs84.js @@ -1,18 +1,18 @@ import Map from '../src/ol/Map.js'; -import View from '../src/ol/View.js'; -import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; const map = new Map({ layers: [ new TileLayer({ - source: new OSM() - }) + source: new OSM(), + }), ], target: 'map', view: new View({ projection: 'EPSG:4326', center: [0, 0], - zoom: 2 - }) + zoom: 2, + }), }); diff --git a/examples/reprojection.html b/examples/reprojection.html index dee4de0364..5ad6a2da47 100644 --- a/examples/reprojection.html +++ b/examples/reprojection.html @@ -21,7 +21,6 @@ tags: "reprojection, projection, proj4js, osm, wms, wmts, hidpi" -} - * @private - */ + * @type {!Array. } + * @private + */ this.dragListenerKeys_ = []; /** @@ -131,24 +125,46 @@ class ZoomSlider extends Control { */ this.duration_ = options.duration !== undefined ? options.duration : 200; - const className = options.className !== undefined ? options.className : 'ol-zoomslider'; + const className = + options.className !== undefined ? options.className : 'ol-zoomslider'; const thumbElement = document.createElement('button'); thumbElement.setAttribute('type', 'button'); thumbElement.className = className + '-thumb ' + CLASS_UNSELECTABLE; const containerElement = this.element; - containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; + containerElement.className = + className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; containerElement.appendChild(thumbElement); - containerElement.addEventListener(PointerEventType.POINTERDOWN, this.handleDraggerStart_.bind(this), false); - containerElement.addEventListener(PointerEventType.POINTERMOVE, this.handleDraggerDrag_.bind(this), false); - containerElement.addEventListener(PointerEventType.POINTERUP, this.handleDraggerEnd_.bind(this), false); + containerElement.addEventListener( + PointerEventType.POINTERDOWN, + this.handleDraggerStart_.bind(this), + false + ); + containerElement.addEventListener( + PointerEventType.POINTERMOVE, + this.handleDraggerDrag_.bind(this), + false + ); + containerElement.addEventListener( + PointerEventType.POINTERUP, + this.handleDraggerEnd_.bind(this), + false + ); - containerElement.addEventListener(EventType.CLICK, this.handleContainerClick_.bind(this), false); + containerElement.addEventListener( + EventType.CLICK, + this.handleContainerClick_.bind(this), + false + ); thumbElement.addEventListener(EventType.CLICK, stopPropagation, false); } /** - * @inheritDoc + * Remove the control from its current map and attach it to the new map. + * Subclasses may set up event handlers to get notified about changes to + * the map here. + * @param {import("../PluggableMap.js").default} map Map. + * @api */ setMap(map) { super.setMap(map); @@ -162,32 +178,37 @@ class ZoomSlider extends Control { * direction_ and also constrain the dragging of the thumb to always be within * the bounds of the container. * + * @return {boolean} Initialization successful * @private */ initSlider_() { const container = this.element; - const containerSize = { - width: container.offsetWidth, height: container.offsetHeight - }; + const containerWidth = container.offsetWidth; + const containerHeight = container.offsetHeight; + if (containerWidth === 0 && containerHeight === 0) { + return (this.sliderInitialized_ = false); + } const thumb = /** @type {HTMLElement} */ (container.firstElementChild); const computedStyle = getComputedStyle(thumb); - const thumbWidth = thumb.offsetWidth + - parseFloat(computedStyle['marginRight']) + - parseFloat(computedStyle['marginLeft']); - const thumbHeight = thumb.offsetHeight + - parseFloat(computedStyle['marginTop']) + - parseFloat(computedStyle['marginBottom']); + const thumbWidth = + thumb.offsetWidth + + parseFloat(computedStyle['marginRight']) + + parseFloat(computedStyle['marginLeft']); + const thumbHeight = + thumb.offsetHeight + + parseFloat(computedStyle['marginTop']) + + parseFloat(computedStyle['marginBottom']); this.thumbSize_ = [thumbWidth, thumbHeight]; - if (containerSize.width > containerSize.height) { + if (containerWidth > containerHeight) { this.direction_ = Direction.HORIZONTAL; - this.widthLimit_ = containerSize.width - thumbWidth; + this.widthLimit_ = containerWidth - thumbWidth; } else { this.direction_ = Direction.VERTICAL; - this.heightLimit_ = containerSize.height - thumbHeight; + this.heightLimit_ = containerHeight - thumbHeight; } - this.sliderInitialized_ = true; + return (this.sliderInitialized_ = true); } /** @@ -199,7 +220,8 @@ class ZoomSlider extends Control { const relativePosition = this.getRelativePosition_( event.offsetX - this.thumbSize_[0] / 2, - event.offsetY - this.thumbSize_[1] / 2); + event.offsetY - this.thumbSize_[1] / 2 + ); const resolution = this.getResolutionForPosition_(relativePosition); const zoom = view.getConstrainedZoom(view.getZoomForResolution(resolution)); @@ -207,7 +229,7 @@ class ZoomSlider extends Control { view.animateInternal({ zoom: zoom, duration: this.duration_, - easing: easeOut + easing: easeOut, }); } @@ -218,7 +240,8 @@ class ZoomSlider extends Control { */ handleDraggerStart_(event) { if (!this.dragging_ && event.target === this.element.firstElementChild) { - const element = /** @type {HTMLElement} */ (this.element.firstElementChild); + const element = /** @type {HTMLElement} */ (this.element + .firstElementChild); this.getMap().getView().beginInteraction(); this.startX_ = event.clientX - parseFloat(element.style.left); this.startY_ = event.clientY - parseFloat(element.style.top); @@ -246,7 +269,9 @@ class ZoomSlider extends Control { const deltaX = event.clientX - this.startX_; const deltaY = event.clientY - this.startY_; const relativePosition = this.getRelativePosition_(deltaX, deltaY); - this.currentResolution_ = this.getResolutionForPosition_(relativePosition); + this.currentResolution_ = this.getResolutionForPosition_( + relativePosition + ); this.getMap().getView().setResolution(this.currentResolution_); } } @@ -332,25 +357,23 @@ class ZoomSlider extends Control { const fn = this.getMap().getView().getValueForResolutionFunction(); return clamp(1 - fn(res), 0, 1); } -} - -/** - * Update the zoomslider element. - * @param {import("../MapEvent.js").default} mapEvent Map event. - * @this {ZoomSlider} - */ -export function render(mapEvent) { - if (!mapEvent.frameState) { - return; + /** + * Update the zoomslider element. + * @param {import("../MapEvent.js").default} mapEvent Map event. + * @override + */ + render(mapEvent) { + if (!mapEvent.frameState) { + return; + } + if (!this.sliderInitialized_ && !this.initSlider_()) { + return; + } + const res = mapEvent.frameState.viewState.resolution; + this.currentResolution_ = res; + this.setThumbPosition_(res); } - if (!this.sliderInitialized_) { - this.initSlider_(); - } - const res = mapEvent.frameState.viewState.resolution; - this.currentResolution_ = res; - this.setThumbPosition_(res); } - export default ZoomSlider; diff --git a/src/ol/control/ZoomToExtent.js b/src/ol/control/ZoomToExtent.js index 6c3142a6c0..68ddcc3c88 100644 --- a/src/ol/control/ZoomToExtent.js +++ b/src/ol/control/ZoomToExtent.js @@ -1,11 +1,10 @@ /** * @module ol/control/ZoomToExtent */ -import EventType from '../events/EventType.js'; -import {fromExtent as polygonFromExtent} from '../geom/Polygon.js'; import Control from './Control.js'; +import EventType from '../events/EventType.js'; import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js'; - +import {fromExtent as polygonFromExtent} from '../geom/Polygon.js'; /** * @typedef {Object} Options @@ -19,7 +18,6 @@ import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js'; * extent of the view projection is used. */ - /** * @classdesc * A button control which, when pressed, changes the map view to a specific @@ -28,7 +26,6 @@ import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js'; * @api */ class ZoomToExtent extends Control { - /** * @param {Options=} opt_options Options. */ @@ -37,7 +34,7 @@ class ZoomToExtent extends Control { super({ element: document.createElement('div'), - target: options.target + target: options.target, }); /** @@ -46,10 +43,12 @@ class ZoomToExtent extends Control { */ this.extent = options.extent ? options.extent : null; - const className = options.className !== undefined ? options.className : 'ol-zoom-extent'; + const className = + options.className !== undefined ? options.className : 'ol-zoom-extent'; const label = options.label !== undefined ? options.label : 'E'; - const tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Fit to extent'; + const tipLabel = + options.tipLabel !== undefined ? options.tipLabel : 'Fit to extent'; const button = document.createElement('button'); button.setAttribute('type', 'button'); button.title = tipLabel; @@ -57,9 +56,14 @@ class ZoomToExtent extends Control { typeof label === 'string' ? document.createTextNode(label) : label ); - button.addEventListener(EventType.CLICK, this.handleClick_.bind(this), false); + button.addEventListener( + EventType.CLICK, + this.handleClick_.bind(this), + false + ); - const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; + const cssClasses = + className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; const element = this.element; element.className = cssClasses; element.appendChild(button); @@ -80,7 +84,9 @@ class ZoomToExtent extends Control { handleZoomToExtent() { const map = this.getMap(); const view = map.getView(); - const extent = !this.extent ? view.getProjection().getExtent() : this.extent; + const extent = !this.extent + ? view.getProjection().getExtent() + : this.extent; view.fitInternal(polygonFromExtent(extent)); } } diff --git a/src/ol/coordinate.js b/src/ol/coordinate.js index 177c8bce55..85b31f325c 100644 --- a/src/ol/coordinate.js +++ b/src/ol/coordinate.js @@ -1,17 +1,16 @@ /** * @module ol/coordinate */ +import {getWidth} from './extent.js'; import {modulo} from './math.js'; import {padNumber} from './string.js'; - /** * An array of numbers representing an xy coordinate. Example: `[16, 48]`. * @typedef {Array } Coordinate * @api */ - /** * A function that takes a {@link module:ol/coordinate~Coordinate} and * transforms it into a `{string}`. @@ -20,7 +19,6 @@ import {padNumber} from './string.js'; * @api */ - /** * Add `delta` to `coordinate`. `coordinate` is modified in place and returned * by the function. @@ -45,7 +43,6 @@ export function add(coordinate, delta) { return coordinate; } - /** * Calculates the point closest to the passed coordinate on the passed circle. * @@ -68,13 +65,12 @@ export function closestOnCircle(coordinate, circle) { } const d = Math.sqrt(dx * dx + dy * dy); - const x = x0 + r * dx / d; - const y = y0 + r * dy / d; + const x = x0 + (r * dx) / d; + const y = y0 + (r * dy) / d; return [x, y]; } - /** * Calculates the point closest to the passed coordinate on the passed segment. * This is the foot of the perpendicular of the coordinate to the segment when @@ -98,8 +94,10 @@ export function closestOnSegment(coordinate, segment) { const y2 = end[1]; const dx = x2 - x1; const dy = y2 - y1; - const along = (dx === 0 && dy === 0) ? 0 : - ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0); + const along = + dx === 0 && dy === 0 + ? 0 + : (dx * (x0 - x1) + dy * (y0 - y1)) / (dx * dx + dy * dy || 0); let x, y; if (along <= 0) { x = x1; @@ -114,7 +112,6 @@ export function closestOnSegment(coordinate, segment) { return [x, y]; } - /** * Returns a {@link module:ol/coordinate~CoordinateFormat} function that can be * used to format @@ -149,13 +146,12 @@ export function createStringXY(opt_fractionDigits) { * @param {Coordinate} coordinate Coordinate. * @return {string} String XY. */ - function(coordinate) { + function (coordinate) { return toStringXY(coordinate, opt_fractionDigits); } ); } - /** * @param {string} hemispheres Hemispheres. * @param {number} degrees Degrees. @@ -171,7 +167,7 @@ export function degreesToStringHDMS(hemispheres, degrees, opt_fractionDigits) { let deg = Math.floor(x / 3600); let min = Math.floor((x - deg * 3600) / 60); - let sec = x - (deg * 3600) - (min * 60); + let sec = x - deg * 3600 - min * 60; sec = Math.ceil(sec * precision) / precision; if (sec >= 60) { @@ -184,12 +180,19 @@ export function degreesToStringHDMS(hemispheres, degrees, opt_fractionDigits) { deg += 1; } - return deg + '\u00b0 ' + padNumber(min, 2) + '\u2032 ' + - padNumber(sec, 2, dflPrecision) + '\u2033' + - (normalizedDegrees == 0 ? '' : ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0)); + return ( + deg + + '\u00b0 ' + + padNumber(min, 2) + + '\u2032 ' + + padNumber(sec, 2, dflPrecision) + + '\u2033' + + (normalizedDegrees == 0 + ? '' + : ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0)) + ); } - /** * Transforms the given {@link module:ol/coordinate~Coordinate} to a string * using the given string template. The strings `{x}` and `{y}` in the template @@ -231,7 +234,6 @@ export function format(coordinate, template, opt_fractionDigits) { } } - /** * @param {Coordinate} coordinate1 First coordinate. * @param {Coordinate} coordinate2 Second coordinate. @@ -248,7 +250,6 @@ export function equals(coordinate1, coordinate2) { return equals; } - /** * Rotate `coordinate` by `angle`. `coordinate` is modified in place and * returned by the function. @@ -277,7 +278,6 @@ export function rotate(coordinate, angle) { return coordinate; } - /** * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned * by the function. @@ -301,7 +301,6 @@ export function scale(coordinate, scale) { return coordinate; } - /** * @param {Coordinate} coord1 First coordinate. * @param {Coordinate} coord2 Second coordinate. @@ -313,7 +312,6 @@ export function squaredDistance(coord1, coord2) { return dx * dx + dy * dy; } - /** * @param {Coordinate} coord1 First coordinate. * @param {Coordinate} coord2 Second coordinate. @@ -323,7 +321,6 @@ export function distance(coord1, coord2) { return Math.sqrt(squaredDistance(coord1, coord2)); } - /** * Calculate the squared distance from a coordinate to a line segment. * @@ -333,11 +330,9 @@ export function distance(coord1, coord2) { * @return {number} Squared distance from the point to the line segment. */ export function squaredDistanceToSegment(coordinate, segment) { - return squaredDistance(coordinate, - closestOnSegment(coordinate, segment)); + return squaredDistance(coordinate, closestOnSegment(coordinate, segment)); } - /** * Format a geographic coordinate with the hemisphere, degrees, minutes, and * seconds. @@ -366,14 +361,16 @@ export function squaredDistanceToSegment(coordinate, segment) { */ export function toStringHDMS(coordinate, opt_fractionDigits) { if (coordinate) { - return degreesToStringHDMS('NS', coordinate[1], opt_fractionDigits) + ' ' + - degreesToStringHDMS('EW', coordinate[0], opt_fractionDigits); + return ( + degreesToStringHDMS('NS', coordinate[1], opt_fractionDigits) + + ' ' + + degreesToStringHDMS('EW', coordinate[0], opt_fractionDigits) + ); } else { return ''; } } - /** * Format a coordinate as a comma delimited string. * @@ -402,3 +399,42 @@ export function toStringHDMS(coordinate, opt_fractionDigits) { export function toStringXY(coordinate, opt_fractionDigits) { return format(coordinate, '{x}, {y}', opt_fractionDigits); } + +/** + * Modifies the provided coordinate in-place to be within the real world + * extent. The lower projection extent boundary is inclusive, the upper one + * exclusive. + * + * @param {Coordinate} coordinate Coordinate. + * @param {import("./proj/Projection.js").default} projection Projection. + * @return {Coordinate} The coordinate within the real world extent. + */ +export function wrapX(coordinate, projection) { + const worldWidth = getWidth(projection.getExtent()); + const worldsAway = getWorldsAway(coordinate, projection, worldWidth); + if (worldsAway) { + coordinate[0] -= worldsAway * worldWidth; + } + return coordinate; +} +/** + * @param {Coordinate} coordinate Coordinate. + * @param {import("./proj/Projection.js").default} projection Projection. + * @param {number=} opt_sourceExtentWidth Width of the source extent. + * @return {number} Offset in world widths. + */ +export function getWorldsAway(coordinate, projection, opt_sourceExtentWidth) { + const projectionExtent = projection.getExtent(); + let worldsAway = 0; + if ( + projection.canWrapX() && + (coordinate[0] < projectionExtent[0] || coordinate[0] > projectionExtent[2]) + ) { + const sourceExtentWidth = + opt_sourceExtentWidth || getWidth(projectionExtent); + worldsAway = Math.floor( + (coordinate[0] - projectionExtent[0]) / sourceExtentWidth + ); + } + return worldsAway; +} diff --git a/src/ol/css.js b/src/ol/css.js index c855fae7ea..b7eb38b0bf 100644 --- a/src/ol/css.js +++ b/src/ol/css.js @@ -4,12 +4,15 @@ /** * @typedef {Object} FontParameters - * @property {Array } families * @property {string} style + * @property {string} variant * @property {string} weight + * @property {string} size + * @property {string} lineHeight + * @property {string} family + * @property {Array } families */ - /** * The CSS class for hidden feature. * @@ -18,7 +21,6 @@ */ export const CLASS_HIDDEN = 'ol-hidden'; - /** * The CSS class that we'll give the DOM elements to have them selectable. * @@ -27,7 +29,6 @@ export const CLASS_HIDDEN = 'ol-hidden'; */ export const CLASS_SELECTABLE = 'ol-selectable'; - /** * The CSS class that we'll give the DOM elements to have them unselectable. * @@ -36,7 +37,6 @@ export const CLASS_SELECTABLE = 'ol-selectable'; */ export const CLASS_UNSELECTABLE = 'ol-unselectable'; - /** * The CSS class for unsupported feature. * @@ -45,7 +45,6 @@ export const CLASS_UNSELECTABLE = 'ol-unselectable'; */ export const CLASS_UNSUPPORTED = 'ol-unsupported'; - /** * The CSS class for controls. * @@ -54,7 +53,6 @@ export const CLASS_UNSUPPORTED = 'ol-unsupported'; */ export const CLASS_CONTROL = 'ol-control'; - /** * The CSS class that we'll give the DOM elements that are collapsed, i.e. * to those elements which usually can be expanded. @@ -64,42 +62,55 @@ export const CLASS_CONTROL = 'ol-control'; */ export const CLASS_COLLAPSED = 'ol-collapsed'; +/** + * From http://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font + * @type {RegExp} + */ +const fontRegEx = new RegExp( + [ + '^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)', + '(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)', + '(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)', + '(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?', + '(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))', + '(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))', + '?\\s*([-,\\"\\\'\\sa-z]+?)\\s*$', + ].join(''), + 'i' +); +const fontRegExMatchIndex = [ + 'style', + 'variant', + 'weight', + 'size', + 'lineHeight', + 'family', +]; /** * Get the list of font families from a font spec. Note that this doesn't work * for font families that have commas in them. - * @param {string} The CSS font property. - * @return {FontParameters} The font families (or null if the input spec is invalid). + * @param {string} fontSpec The CSS font property. + * @return {FontParameters} The font parameters (or null if the input spec is invalid). */ -export const getFontParameters = (function() { - /** - * @type {CSSStyleDeclaration} - */ - let style; - /** - * @type {Object } - */ - const cache = {}; - return function(font) { - if (!style) { - style = document.createElement('div').style; +export const getFontParameters = function (fontSpec) { + const match = fontSpec.match(fontRegEx); + if (!match) { + return null; + } + const style = /** @type {FontParameters} */ ({ + lineHeight: 'normal', + size: '1.2em', + style: 'normal', + weight: 'normal', + variant: 'normal', + }); + for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) { + const value = match[i + 1]; + if (value !== undefined) { + style[fontRegExMatchIndex[i]] = value; } - if (!(font in cache)) { - style.font = font; - const family = style.fontFamily; - const fontWeight = style.fontWeight; - const fontStyle = style.fontStyle; - style.font = ''; - if (!family) { - return null; - } - const families = family.split(/,\s?/); - cache[font] = { - families: families, - weight: fontWeight, - style: fontStyle - }; - } - return cache[font]; - }; -})(); + } + style.families = style.family.split(/,\s?/); + return style; +}; diff --git a/src/ol/dom.js b/src/ol/dom.js index ad10c14671..1c392cce21 100644 --- a/src/ol/dom.js +++ b/src/ol/dom.js @@ -1,8 +1,10 @@ +import {WORKER_OFFSCREEN_CANVAS} from './has.js'; + /** * @module ol/dom */ - +//FIXME Move this function to the canvas module /** * Create an html canvas element and returns its 2d context. * @param {number=} opt_width Canvas width. @@ -11,18 +13,22 @@ * @return {CanvasRenderingContext2D} The context. */ export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) { - const canvas = opt_canvasPool && opt_canvasPool.length ? - opt_canvasPool.shift() : document.createElement('canvas'); + const canvas = + opt_canvasPool && opt_canvasPool.length + ? opt_canvasPool.shift() + : WORKER_OFFSCREEN_CANVAS + ? new OffscreenCanvas(opt_width || 300, opt_height || 300) + : document.createElement('canvas'); if (opt_width) { canvas.width = opt_width; } if (opt_height) { canvas.height = opt_height; } - return canvas.getContext('2d'); + //FIXME Allow OffscreenCanvasRenderingContext2D as return type + return /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d')); } - /** * Get the current computed width for the given element including margin, * padding and border. @@ -38,7 +44,6 @@ export function outerWidth(element) { return width; } - /** * Get the current computed height for the given element including margin, * padding and border. diff --git a/src/ol/easing.js b/src/ol/easing.js index 7a64d450e9..b6a6c51f51 100644 --- a/src/ol/easing.js +++ b/src/ol/easing.js @@ -2,7 +2,6 @@ * @module ol/easing */ - /** * Start slow and speed up. * @param {number} t Input between 0 and 1. @@ -13,7 +12,6 @@ export function easeIn(t) { return Math.pow(t, 3); } - /** * Start fast and slow down. * @param {number} t Input between 0 and 1. @@ -24,7 +22,6 @@ export function easeOut(t) { return 1 - easeIn(1 - t); } - /** * Start slow, speed up, and then slow down again. * @param {number} t Input between 0 and 1. @@ -35,7 +32,6 @@ export function inAndOut(t) { return 3 * t * t - 2 * t * t * t; } - /** * Maintain a constant speed over time. * @param {number} t Input between 0 and 1. @@ -46,7 +42,6 @@ export function linear(t) { return t; } - /** * Start slow, speed up, and at the very end slow down again. This has the * same general behavior as {@link module:ol/easing~inAndOut}, but the final diff --git a/src/ol/events.js b/src/ol/events.js index 5a64a185ce..8bd12b7b6e 100644 --- a/src/ol/events.js +++ b/src/ol/events.js @@ -3,7 +3,6 @@ */ import {clear} from './obj.js'; - /** * Key to use with {@link module:ol/Observable~Observable#unByKey}. * @typedef {Object} EventsKey @@ -13,7 +12,6 @@ import {clear} from './obj.js'; * @api */ - /** * Listener function. This function is called with an event object as argument. * When the function returns `false`, event propagation will stop. @@ -22,6 +20,14 @@ import {clear} from './obj.js'; * @api */ +/** + * @typedef {Object} ListenerObject + * @property {ListenerFunction} handleEvent + */ + +/** + * @typedef {ListenerFunction|ListenerObject} Listener + */ /** * Registers an event listener on an event target. Inspired by @@ -44,7 +50,7 @@ export function listen(target, type, listener, opt_this, opt_once) { } if (opt_once) { const originalListener = listener; - listener = function() { + listener = function () { target.removeEventListener(type, listener); originalListener.apply(this, arguments); }; @@ -52,13 +58,12 @@ export function listen(target, type, listener, opt_this, opt_once) { const eventsKey = { target: target, type: type, - listener: listener + listener: listener, }; target.addEventListener(type, listener); return eventsKey; } - /** * Registers a one-off event listener on an event target. Inspired by * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html @@ -83,7 +88,6 @@ export function listenOnce(target, type, listener, opt_this) { return listen(target, type, listener, opt_this, true); } - /** * Unregisters event listeners on an event target. Inspired by * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html diff --git a/src/ol/events/Event.js b/src/ol/events/Event.js index 1f6d9739b2..69ce76ba1d 100644 --- a/src/ol/events/Event.js +++ b/src/ol/events/Event.js @@ -13,12 +13,10 @@ * {@link module:ol/events/Target~Target}. */ class BaseEvent { - /** * @param {string} type Type. */ constructor(type) { - /** * @type {boolean} */ @@ -54,10 +52,8 @@ class BaseEvent { stopPropagation() { this.propagationStopped = true; } - } - /** * @param {Event|import("./Event.js").default} evt Event */ @@ -65,7 +61,6 @@ export function stopPropagation(evt) { evt.stopPropagation(); } - /** * @param {Event|import("./Event.js").default} evt Event */ diff --git a/src/ol/events/EventType.js b/src/ol/events/EventType.js index 8959635887..571a653111 100644 --- a/src/ol/events/EventType.js +++ b/src/ol/events/EventType.js @@ -35,5 +35,5 @@ export default { LOAD: 'load', RESIZE: 'resize', TOUCHMOVE: 'touchmove', - WHEEL: 'wheel' + WHEEL: 'wheel', }; diff --git a/src/ol/events/KeyCode.js b/src/ol/events/KeyCode.js index e855570c82..01a2d8cf10 100644 --- a/src/ol/events/KeyCode.js +++ b/src/ol/events/KeyCode.js @@ -10,5 +10,5 @@ export default { LEFT: 37, UP: 38, RIGHT: 39, - DOWN: 40 + DOWN: 40, }; diff --git a/src/ol/events/Target.js b/src/ol/events/Target.js index 766a954479..e8e4967acd 100644 --- a/src/ol/events/Target.js +++ b/src/ol/events/Target.js @@ -2,16 +2,14 @@ * @module ol/events/Target */ import Disposable from '../Disposable.js'; -import {VOID} from '../functions.js'; import Event from './Event.js'; +import {VOID} from '../functions.js'; import {clear} from '../obj.js'; - /** * @typedef {EventTarget|Target} EventTargetLike */ - /** * @classdesc * A simplified implementation of the W3C DOM Level 2 EventTarget interface. @@ -28,12 +26,10 @@ import {clear} from '../obj.js'; * returns false. */ class Target extends Disposable { - /** * @param {*=} opt_target Default event target for dispatched events. */ constructor(opt_target) { - super(); /** @@ -44,39 +40,35 @@ class Target extends Disposable { /** * @private - * @type {!Object } + * @type {Object } */ - this.pendingRemovals_ = {}; + this.pendingRemovals_ = null; /** * @private - * @type {!Object } + * @type {Object } */ - this.dispatching_ = {}; + this.dispatching_ = null; /** * @private - * @type {!Object >} + * @type {Object >} */ - this.listeners_ = {}; - + this.listeners_ = null; } /** * @param {string} type Type. - * @param {import("../events.js").ListenerFunction} listener Listener. + * @param {import("../events.js").Listener} listener Listener. */ addEventListener(type, listener) { if (!type || !listener) { return; } - let listeners = this.listeners_[type]; - if (!listeners) { - listeners = []; - this.listeners_[type] = listeners; - } - if (listeners.indexOf(listener) === -1) { - listeners.push(listener); + const listeners = this.listeners_ || (this.listeners_ = {}); + const listenersForType = listeners[type] || (listeners[type] = []); + if (listenersForType.indexOf(listener) === -1) { + listenersForType.push(listener); } } @@ -85,52 +77,62 @@ class Target extends Disposable { * of this type. The event parameter can either be a string or an * Object with a `type` property. * - * @param {{type: string, - * target: (EventTargetLike|undefined), - * propagationStopped: (boolean|undefined)}| - * import("./Event.js").default|string} event Event object. + * @param {import("./Event.js").default|string} event Event object. * @return {boolean|undefined} `false` if anyone called preventDefault on the * event object or if any of the listeners returned false. * @api */ dispatchEvent(event) { + /** @type {import("./Event.js").default|Event} */ const evt = typeof event === 'string' ? new Event(event) : event; const type = evt.type; if (!evt.target) { evt.target = this.eventTarget_ || this; } - const listeners = this.listeners_[type]; + const listeners = this.listeners_ && this.listeners_[type]; let propagate; if (listeners) { - if (!(type in this.dispatching_)) { - this.dispatching_[type] = 0; - this.pendingRemovals_[type] = 0; + const dispatching = this.dispatching_ || (this.dispatching_ = {}); + const pendingRemovals = + this.pendingRemovals_ || (this.pendingRemovals_ = {}); + if (!(type in dispatching)) { + dispatching[type] = 0; + pendingRemovals[type] = 0; } - ++this.dispatching_[type]; + ++dispatching[type]; for (let i = 0, ii = listeners.length; i < ii; ++i) { - if (listeners[i].call(this, evt) === false || evt.propagationStopped) { + if ('handleEvent' in listeners[i]) { + propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[ + i + ]).handleEvent(evt); + } else { + propagate = /** @type {import("../events.js").ListenerFunction} */ (listeners[ + i + ]).call(this, evt); + } + if (propagate === false || evt.propagationStopped) { propagate = false; break; } } - --this.dispatching_[type]; - if (this.dispatching_[type] === 0) { - let pendingRemovals = this.pendingRemovals_[type]; - delete this.pendingRemovals_[type]; - while (pendingRemovals--) { + --dispatching[type]; + if (dispatching[type] === 0) { + let pr = pendingRemovals[type]; + delete pendingRemovals[type]; + while (pr--) { this.removeEventListener(type, VOID); } - delete this.dispatching_[type]; + delete dispatching[type]; } return propagate; } } /** - * @inheritDoc + * Clean up. */ disposeInternal() { - clear(this.listeners_); + this.listeners_ && clear(this.listeners_); } /** @@ -138,10 +140,10 @@ class Target extends Disposable { * order that they will be called in. * * @param {string} type Type. - * @return {Array } Listeners. + * @return {Array |undefined} Listeners. */ getListeners(type) { - return this.listeners_[type]; + return (this.listeners_ && this.listeners_[type]) || undefined; } /** @@ -150,21 +152,24 @@ class Target extends Disposable { * @return {boolean} Has listeners. */ hasListener(opt_type) { - return opt_type ? - opt_type in this.listeners_ : - Object.keys(this.listeners_).length > 0; + if (!this.listeners_) { + return false; + } + return opt_type + ? opt_type in this.listeners_ + : Object.keys(this.listeners_).length > 0; } /** * @param {string} type Type. - * @param {import("../events.js").ListenerFunction} listener Listener. + * @param {import("../events.js").Listener} listener Listener. */ removeEventListener(type, listener) { - const listeners = this.listeners_[type]; + const listeners = this.listeners_ && this.listeners_[type]; if (listeners) { const index = listeners.indexOf(listener); if (index !== -1) { - if (type in this.pendingRemovals_) { + if (this.pendingRemovals_ && type in this.pendingRemovals_) { // make listener a no-op, and remove later in #dispatchEvent() listeners[index] = VOID; ++this.pendingRemovals_[type]; @@ -179,5 +184,4 @@ class Target extends Disposable { } } - export default Target; diff --git a/src/ol/events/condition.js b/src/ol/events/condition.js index fca9ac4032..f6551ac0fd 100644 --- a/src/ol/events/condition.js +++ b/src/ol/events/condition.js @@ -2,10 +2,9 @@ * @module ol/events/condition */ import MapBrowserEventType from '../MapBrowserEventType.js'; +import {FALSE, TRUE} from '../functions.js'; +import {MAC, WEBKIT} from '../has.js'; import {assert} from '../asserts.js'; -import {TRUE, FALSE} from '../functions.js'; -import {WEBKIT, MAC} from '../has.js'; - /** * A function that takes an {@link module:ol/MapBrowserEvent} and returns a @@ -14,6 +13,28 @@ import {WEBKIT, MAC} from '../has.js'; * @typedef {function(this: ?, import("../MapBrowserEvent.js").default): boolean} Condition */ +/** + * Creates a condition function that passes when all provided conditions pass. + * @param {...Condition} var_args Conditions to check. + * @return {Condition} Condition function. + */ +export function all(var_args) { + const conditions = arguments; + /** + * @param {import("../MapBrowserEvent.js").default} event Event. + * @return {boolean} All conditions passed. + */ + return function (event) { + let pass = true; + for (let i = 0, ii = conditions.length; i < ii; ++i) { + pass = pass && conditions[i](event); + if (!pass) { + break; + } + } + return pass; + }; +} /** * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when @@ -23,15 +44,15 @@ import {WEBKIT, MAC} from '../has.js'; * @return {boolean} True if only the alt key is pressed. * @api */ -export const altKeyOnly = function(mapBrowserEvent) { +export const altKeyOnly = function (mapBrowserEvent) { const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (mapBrowserEvent.originalEvent); return ( originalEvent.altKey && - !(originalEvent.metaKey || originalEvent.ctrlKey) && - !originalEvent.shiftKey); + !(originalEvent.metaKey || originalEvent.ctrlKey) && + !originalEvent.shiftKey + ); }; - /** * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise * (e.g. when additionally the platform-modifier-key is pressed). @@ -40,15 +61,15 @@ export const altKeyOnly = function(mapBrowserEvent) { * @return {boolean} True if only the alt and shift keys are pressed. * @api */ -export const altShiftKeysOnly = function(mapBrowserEvent) { +export const altShiftKeysOnly = function (mapBrowserEvent) { const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (mapBrowserEvent.originalEvent); return ( originalEvent.altKey && - !(originalEvent.metaKey || originalEvent.ctrlKey) && - originalEvent.shiftKey); + !(originalEvent.metaKey || originalEvent.ctrlKey) && + originalEvent.shiftKey + ); }; - /** * Return `true` if the map has the focus. This condition requires a map target * element with a `tabindex` attribute, e.g. ` `. @@ -57,10 +78,21 @@ export const altShiftKeysOnly = function(mapBrowserEvent) { * @return {boolean} The map has the focus. * @api */ -export const focus = function(event) { - return event.target.getTargetElement() === document.activeElement; +export const focus = function (event) { + return event.target.getTargetElement().contains(document.activeElement); }; +/** + * Return `true` if the map has the focus or no 'tabindex' attribute set. + * + * @param {import("../MapBrowserEvent.js").default} event Map browser event. + * @return {boolean} The map container has the focus or no 'tabindex' attribute. + */ +export const focusWithTabindex = function (event) { + return event.map.getTargetElement().hasAttribute('tabindex') + ? focus(event) + : true; +}; /** * Return always true. @@ -71,7 +103,6 @@ export const focus = function(event) { */ export const always = TRUE; - /** * Return `true` if the event is a `click` event, `false` otherwise. * @@ -79,11 +110,10 @@ export const always = TRUE; * @return {boolean} True if the event is a map `click` event. * @api */ -export const click = function(mapBrowserEvent) { +export const click = function (mapBrowserEvent) { return mapBrowserEvent.type == MapBrowserEventType.CLICK; }; - /** * Return `true` if the event has an "action"-producing mouse button. * @@ -93,13 +123,11 @@ export const click = function(mapBrowserEvent) { * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. * @return {boolean} The result. */ -export const mouseActionButton = function(mapBrowserEvent) { +export const mouseActionButton = function (mapBrowserEvent) { const originalEvent = /** @type {MouseEvent} */ (mapBrowserEvent.originalEvent); - return originalEvent.button == 0 && - !(WEBKIT && MAC && originalEvent.ctrlKey); + return originalEvent.button == 0 && !(WEBKIT && MAC && originalEvent.ctrlKey); }; - /** * Return always false. * @@ -109,7 +137,6 @@ export const mouseActionButton = function(mapBrowserEvent) { */ export const never = FALSE; - /** * Return `true` if the browser event is a `pointermove` event, `false` * otherwise. @@ -118,11 +145,10 @@ export const never = FALSE; * @return {boolean} True if the browser event is a `pointermove` event. * @api */ -export const pointerMove = function(mapBrowserEvent) { +export const pointerMove = function (mapBrowserEvent) { return mapBrowserEvent.type == 'pointermove'; }; - /** * Return `true` if the event is a map `singleclick` event, `false` otherwise. * @@ -130,11 +156,10 @@ export const pointerMove = function(mapBrowserEvent) { * @return {boolean} True if the event is a map `singleclick` event. * @api */ -export const singleClick = function(mapBrowserEvent) { +export const singleClick = function (mapBrowserEvent) { return mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK; }; - /** * Return `true` if the event is a map `dblclick` event, `false` otherwise. * @@ -142,11 +167,10 @@ export const singleClick = function(mapBrowserEvent) { * @return {boolean} True if the event is a map `dblclick` event. * @api */ -export const doubleClick = function(mapBrowserEvent) { +export const doubleClick = function (mapBrowserEvent) { return mapBrowserEvent.type == MapBrowserEventType.DBLCLICK; }; - /** * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is * pressed. @@ -155,15 +179,15 @@ export const doubleClick = function(mapBrowserEvent) { * @return {boolean} True only if there no modifier keys are pressed. * @api */ -export const noModifierKeys = function(mapBrowserEvent) { +export const noModifierKeys = function (mapBrowserEvent) { const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (mapBrowserEvent.originalEvent); return ( !originalEvent.altKey && - !(originalEvent.metaKey || originalEvent.ctrlKey) && - !originalEvent.shiftKey); + !(originalEvent.metaKey || originalEvent.ctrlKey) && + !originalEvent.shiftKey + ); }; - /** * Return `true` if only the platform-modifier-key (the meta-key on Mac, * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally @@ -173,14 +197,15 @@ export const noModifierKeys = function(mapBrowserEvent) { * @return {boolean} True if only the platform modifier key is pressed. * @api */ -export const platformModifierKeyOnly = function(mapBrowserEvent) { +export const platformModifierKeyOnly = function (mapBrowserEvent) { const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (mapBrowserEvent.originalEvent); - return !originalEvent.altKey && + return ( + !originalEvent.altKey && (MAC ? originalEvent.metaKey : originalEvent.ctrlKey) && - !originalEvent.shiftKey; + !originalEvent.shiftKey + ); }; - /** * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when * additionally the alt-key is pressed). @@ -189,15 +214,15 @@ export const platformModifierKeyOnly = function(mapBrowserEvent) { * @return {boolean} True if only the shift key is pressed. * @api */ -export const shiftKeyOnly = function(mapBrowserEvent) { +export const shiftKeyOnly = function (mapBrowserEvent) { const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (mapBrowserEvent.originalEvent); return ( !originalEvent.altKey && - !(originalEvent.metaKey || originalEvent.ctrlKey) && - originalEvent.shiftKey); + !(originalEvent.metaKey || originalEvent.ctrlKey) && + originalEvent.shiftKey + ); }; - /** * Return `true` if the target element is not editable, i.e. not a ``-, * ` -
-
-
-
+